Получение разных чисел после отправки unsigned int 89 раз между Arduino через последовательный порт

Я пытаюсь передать unsigned int значения int между 2 ардуино. При отправке 61805 в первые 8-9 раз я получаю 61805. Но потом после этих цифр: 61937 28013 61937.

Код отправителя:

unsigned int s = 0;

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

void loop()
{
  s = 61805;
  Serial.write(highByte(s)) ;
  Serial.write(lowByte(s));
}

Код приемника:

unsigned int upperByte, lowerByte, r=0,p=0;

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

void loop () 
{
  if (Serial.available() > 1)
  {
    upperByte = Serial.read();
    lowerByte = Serial.read();
  }

  r = (upperByte << 8) + lowerByte;
  Serial.println(r);
}

, 👍2


2 ответа


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

2

Нет никакого управления потоком на Uno и Nano serial, и вы отправляете достаточно быстро, чтобы байты отбрасывались, и нет никакого способа, чтобы ваш протокол или отсутствие такового разграничивали отдельные сообщения (отдельные номера).

Это станет более ясным, если вы запишете свои числа в шестнадцатеричном формате:

Декабрь Гекс
61805 0xf16d
61937 0xf1f1
28013 0x6d6d
61937 0xf1f1

Добавление задержки между сообщениями может служить для разделения сообщений, если принимающая сторона использует тайм-аут и может предотвратить переполнение принимающей стороны данными.

Если вы не хотите использовать время для замедления и разделения ваших данных, вы можете изменить то, что отправляется вместо этого. Одна идея заключается в том, чтобы приемник активно запрашивал данные, когда он готов их получить. Получатель должен ожидать только целые сообщения между запросами, и если что-то искажается, он может просто прочитать любые данные, которые пришли, и выбросить их перед следующим запросом.

Ваши сообщения также могут быть разделены некоторыми символами, которые не являются частью самих сообщений. Обычный способ сделать это-просто закодировать ваши номера как отдельные текстовые строки, терминатор строки \n, служащий разделителем между сообщениями.

Я еще не тестировал их, но вот некоторые очень минимальные модификации вашего кода, которые приближают наличие протокола с меньшим количеством этих проблем:

Отправитель:

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

void loop() {
  // await message request
  while(Serial.read() != '.') {
  }

  //
  const unsigned int s = 61805;
  Serial.write(highByte(s)) ;
  Serial.write(lowByte(s));
}

Приемник:

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


void loop () {
  // сообщение запроса
  Serial.write('.'); 


  // двухбайтовый ответ
  const unsigned long request_sent = millis();
  while (Serial.available() < 2 && millis() - request_sent < 1000) {
  }


  if (Serial.available() != 0) {
    if (Serial.available() == 2) {
      // двухбайтовый ответ получен
      const unsigned upperByte = Serial.read();
      const unsigned lowerByte = Serial.read();
      const unsigned r = (upperByte << 8) + lowerByte;
      Serial.println(r);
    }  else {
      // Что-то пошло не так, слишком много или слишком мало полученных байтов;
      // выбросьте их и начните все сначала.
      delay(100);
      while (Serial.read() != -1) {}
    }
  }
}

Это далеко от того, чтобы делать это правильно, но он должен вести себя по крайней мере лучше, чем то, с чего вы начали. Существует много для разработки даже простых протоколов. Обычно существуют начальные и конечные байты фрейма, контрольная сумма или CRC, счетчик номеров сообщений и т. Д.

,

спасибо, брат, это сработало...... большое спасибо...., @Anuragverma2804

Мы используем,чтобы отправить 8,N,2 и получить на 8,N, 1. Это дало нам дополнительное время, чтобы приспособиться к перекосу часов., @Gil


0

Эта строка кода получателя:

Serial.println(r);

передает 7 байт (5 цифр, CR и LF). При 9600/8N1 каждый байт занимает 1,04 мс, поэтому все сообщение передается за 7,28 мс. Тем временем отправитель отправляет 2-байтовые сообщения на полной скорости (без паузы между байтами). Таким образом, получатель получает новое сообщение каждые 2,08 мс.

Таким образом, этот приемник получает новое сообщение для ретрансляции каждые 2,08 мс, и ему нужно 7,28 мс для ретрансляции каждого сообщения. Что-то должно дать...

Причина, по которой он работает в начале, заключается в том, что приемник имеет буфер , где он хранит полученные байты, и еще один для байтов, которые были подготовлены для передачи. Пока есть место в этих буферах, все работает нормально. Сначала заполняется буфер передачи, так как он получает 7 байт для передачи каждые 2,08 мс. Как только он заполнен, Serial.println() становится блокирующей функцией: он должен ждать, пока в буфере будет достаточно места. Ваш loop() затем замедляется, чтобы соответствовать скорости передачи, что означает, что вы не читаете буфер приема достаточно часто. Затем буфер приема заполняется, и вы начинаете терять байты.

,

спасибо брату за ваши усилия.... хорошо объяснил... в чем дело, @Anuragverma2804