Как игнорировать значения мусора при последовательной связи между Arduino и Python

У меня есть arduino uno. Я пытаюсь отправлять и получать последовательные данные с Arduino на Python. У меня есть конвертер USB-UART. Я подключил его tx к rx Arduino и rx к tx Arduino и gnd подключен к gnd. Я подключил этот USB-накопитель к своему ноутбуку, где написал скрипт Python ниже:

import serial

ser = serial.Serial(port='COM6')

res = ser.read(10)
print(bytes.hex(res))
data = b"\x7E\x7E\xAA\x03\xAB\x77"
ser.write(data)

ser.close()

В приведенном выше коде я сначала считываю последовательные данные, а как только данные получены, я отправляю несколько шестнадцатеричных пакетов. Ниже приведен код Arduino:

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  const byte message[] = {0xAA, 0xBB, 0x06, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03 };

  Serial.write(message, sizeof message);
  Serial.println("data sent");
  delay(1000);

  char buffer[6];
  if (Serial.available() > 0)
  {
    int size = Serial.readBytesUntil('\x77', buffer, 6);
    for (int i = 0 ; i < size ; i++) 
    {
      Serial.println(buffer[i], HEX);
    }
  }
}

В приведенном выше коде я сначала отправляю шестнадцатеричные пакеты (которые нормально принимаются на стороне Python), а затем он ожидает последовательных данных. Как только последовательные данные доступны для чтения, он считывает их с помощью \x77 и распечатывает все данные. Это получено на последовательной консоли Arduino:

Вы заметите, что данные получены, но получены дополнительные FF. Почему мы получили эти FF. Также в коде Python мы знаем, что отправляем данные длиной 6, поэтому, соответственно, мы определили char buffer[6] в arduino, но что, если нам нужно получить данные, которые мы не знаем, какой длины они будут быть. Пожалуйста помоги. Спасибо

, 👍3

Обсуждение

Как вы настроили последовательный порт на стороне Python? Это не сделано в самом коде Python., @Edgar Bonet

@EdgarBonet Извините, я не понял вас по настройке последовательного порта. Что касается Python, я только что упомянул номер порта и все. Что касается оборудования, то оно то же самое, что упоминалось в вопросе., @S Andrew

Вы не можете подключить другой преобразователь USB-Serial к тем же контактам RX и TX. Последовательные порты не могут работать «параллельно». Определите серийный номер программного обеспечения, используя любые другие цифровые контакты, и подключите преобразователь к этим контактам. Аппаратные контакты rx и tx уже подключены к встроенному преобразователю «последовательный порт в USB»., @Fahad

@Фахад, я знаю, и именно поэтому при загрузке кода мне нужно удалить перемычки между контактами rfom tx и rx. Как только код загружен, я просто нажимаю кнопку сброса, чтобы запустить его снова. Все хорошо?, @S Andrew

@SAndrew Но вы все еще используете одни и те же контакты для двух сериалов! Один из них — встроенный серийный номер, который вы просматриваете в последовательном окне Arduino IDE (COM7), а другой — в Python (COM6). Это проблема. Последовательные шины не предназначены для использования в качестве параллельных шин., @Fahad

@Фахад Спасибо за твою помощь. Использование серийного программного обеспечения на самом деле является хорошим вариантом., @S Andrew


1 ответ


Лучший ответ:

4

Эффект, который вы видите, — это продвижение типа, которое в стандарте C++ называется «интегральным продвижением», которое происходит неявно. Значения типа char преобразуются в in t. Обычно, и в вашем случае тоже, char по умолчанию подписан.

Значения 0xAA и 0xAB имеют установленный старший бит, который обычно обозначает отрицательное значение в дополнение до двух. Это справедливо и для вашего случая. Таким образом, эти отрицательные значения преобразуются в те же отрицательные значения, но в полную ширину int. В вашем случае int имеет 32 бита.

Hex 0xAA как (по умолчанию знак) char представляет собой десятичное число -86. И десятичный -86, поскольку (по определению со знаком) int равен 0xFFFFFFAA шестнадцатеричному.

Печатается в шестнадцатеричном формате, отображаются все биты. Итак, вы видите все эти FF.

Решение состоит в том, чтобы замаскировать только интересующие младшие 8 бит:

    {
      Serial.println(buffer[i] & 0xFF, HEX);
    }
,

Хороший улов! Ну, на самом деле все немного сложнее: char преобразуется в 16-битное int с помощью разрешения перегрузки Serial.println(), а затем явно [приводится к long с помощью Print::print (int, int)](https://github.com/arduino/ArduinoCore-avr/blob/1.8.6/cores/arduino/Print.cpp#L79), затем преобразуется в unsigned long с помощью вызова printNumber()., @Edgar Bonet

@EdgarBonet Эта проблема часто случается с новичками, и у меня она уже была много раз. :-D -- Спасибо, что углубились в детали! Я считаю официальную документацию Arduino в сети неудовлетворительной, потому что мне всегда не хватает точных и полных прототипов. Нам не нужно заглядывать в исходный код библиотеки..., @the busybee

Спасибо за Ваш ответ. Есть идеи, почему принимаются некоторые мусорные и случайные значения? Танск, @S Andrew

@SAndrew Какой мусор и случайные значения вы имеете в виду? Я ничего не вижу. Пожалуйста, задайте новый вопрос, если это отдельная проблема, иначе отредактируйте свой вопрос., @the busybee