Потеря данных при последовательном считывании с помощью 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

Итак, что я сделал не так? Спасибо!

, 👍0

Обсуждение

Уже ответили на форуме Arduino [здесь] (https://forum.arduino.cc/index.php?topic=686370.msg4616676#msg4616676), @P_B


1 ответ


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