Потеря данных при последовательном считывании с помощью Arduino Nano
Я пытаюсь использовать последовательное чтение из последовательного кода python (который выполняется на моем Jetson Nano) в моем проекте, но в каком-то цикле в моем коде мои данные поступают неправильно.
- Я использую функцию Serial.readBytesUntil() для чтения, подобного прерыванию.
- Для связи я использую стандартный синий кабель mini-USB.
- Мой Arduino Nano также подключил модуль nRF24L01 к SPI.
- Скорость передачи данных составляет 9600 для обоих устройств. Я попробовал 115200, но разницы нет.
- Потеря данных составляет около 10% от всех циклов с обоими тестовыми кодами (изображение-1, изображение-2).
- Нет никакой положительной разницы, когда я использую контакты RX / TX на обеих платах с переключателем уровня.
- Когда я использую тестовый код в своем основном коде с USB-подключением, потеря данных увеличивается на 50% от всех циклов. Но последовательный монитор Arduino работает нормально, как изображение-3.
- Когда я использую тестовый код в своем основном коде с выводами RX / TX, последовательный монитор Arduino выглядит как изображение-4, а Arduino IDE выдает ошибку, подобную изображению-5.
Вот мой тестовый код приемника на моем Arduino Nano.
void setup() {
Serial.begin(9600);
pinMode(LED_BUILTIN, OUTPUT);
while (!Serial) {}
}
void loop() {
char buffer[4];
int deger = 0;
if (Serial.available() > 0) {
int size = Serial.readBytesUntil('\n', buffer, 4);
if (size == 4) {
Serial.print("deger: ");
Serial.write(buffer);
Serial.print(" size: ");
Serial.print(size);
// Байт в целое число
deger = (buffer[1] - 48) * 100 + (int(buffer[2]) - 48) * 10 + (buffer[3] - 48);
if (buffer[0] == '1') {
deger = -1*deger; }
Serial.print(" Sayi: ");
Serial.println(deger);
}
if (deger < 0) {
digitalWrite(LED_BUILTIN, HIGH);
}
else {
digitalWrite(LED_BUILTIN, LOW);
}
}
}
И тестовый код последовательного передатчика python.
import serial
ser = serial.Serial('/dev/ttyUSB0',baudrate=9600,timeout=10)
while True:
hata = -58
if hata > 0:
hata = str(hata)
if len(hata) == 2:
hata = '00' + hata
elif len(hata) == 1:
hata = '000' + hata
else:
hata = '0' + hata #Pozitive, Added 0
elif hata < 0:
hata = -1 * hata
hata = str(hata)
if len(hata) == 2:
hata = '10' + hata
elif len(hata) == 1:
hata = '100' + hata
else:
hata = '1' + hata #Negative, Added 1
else:
hata = str(hata)
hata = '000' + hata
# For every loop, sends 4 character and "\n" Example: 1058\n
gonder = hata + '\n' # For readBytesUntil function
ser.write(gonder.encode('utf-8'))
print(gonder.encode('utf-8'))
изображение-1: Скриншот последовательного монитора тестового кода Arduino
изображение-2: Скриншот последовательного терминала тестового кода Python
изображение-3: Монитор основного кода проекта Arduino с USB-кабелем скриншот
изображение-4: Монитор основного кода проекта Arduino с выводами RX / TX на скриншоте GPIO
изображение-5: Ошибка IDE основного кода проекта Arduino
Итак, что я сделал не так? Спасибо!
@dcwaves, 👍0
Обсуждение1 ответ
Вы переполняете свой буфер, а также разрешаете чтение мусора.
Во-первых, вам нужно 5 байт для вашего буфера, а не 4, и вы должны убедиться, что он обнулен, прежде чем использовать его. Это происходит потому, что вы обрабатываете его как строку C, что означает, что он должен заканчиваться нулем.
Во-вторых, ваше использование Serial.readBytesUntil()
является ошибочным. Из руководства:
Функция завершается (проверки выполняются в этом порядке), если определенная длина была прочитана, если время ожидания истекло (см. Serial.setTimeout() ) или если обнаружен символ-терминатор (в этом случае функция возвращает символы до последнего символа перед указанным терминатором).
Вы отправляете 5 байт (1058\n
), но указываете ему на чтение до 4. Который оставляет \n
в буфере. В следующий раз вы прочитаете еще 4 байта, что даст вам \n
, который является завершающим символом.
Если вы должны использовать readBytesUntil
, то вам нужно указать буфер, который больше, чем вся строка, включая терминатор, чтобы терминатор всегда появлялся перед максимальным количеством прочитанных байтов. Включая конечный ноль, вам, таким образом, потребуется не менее 6 байт в вашем буфере, может быть, еще пара "на всякий случай" (никогда нельзя сказать с функциями API Arduino ...)
Итак, чтобы свернуть все это:
char buffer[8]; // <- Больший набор элементов буфера
memset(buffer, 0, 8); // <- Очистите его от
int deger = 0;
if (Serial.available() > 0) {
int size = Serial.readBytesUntil('\n', buffer, 7); // <- Скажите ему, чтобы он прочитал больше, оставляя место для завершающего значения NULL
... etc ...
if (size == 4) {
readBytesUntil
не помещает в буфер завершающий символ. но читается., @Juraj
@Juraj Нет, если это 5-й символ, и вы говорите ему читать только до 4 ..., @Majenko
Благодарю вас! Я попробую закодировать, как вы сказали. Что вы скажете о второй проблеме (изображение-4, сломанный последовательный монитор)?, @dcwaves
Это, скорее всего, переполнение буфера из вашего незавершенного буфера., @Majenko
- В чем разница между библиотеками Software Serial? Какая из них совместима с Arduino Nano?
- Использование последовательных контактов TX/ RX для связи по USB
- Проблема последовательной связи с общей землей SIM800L
- Каков наилучший (самый быстрый и надежный) способ отправки сообщений между Python на ПК и Arduino через последовательный порт?
- Последовательно подключить несколько Arduino Nano к одному порту USB (специального назначения)
- Как использовать pyserial для написания двух отдельных сообщений?
- `time.sleep` в скрипте python чтение последовательного вывода вызывает неустойчивое поведение
- Как игнорировать значения мусора при последовательной связи между Arduino и Python
Уже ответили на форуме Arduino [здесь] (https://forum.arduino.cc/index.php?topic=686370.msg4616676#msg4616676), @P_B