Получение разных чисел после отправки 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);
}
@Anuragverma2804, 👍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, счетчик номеров сообщений и т. Д.
Эта строка кода получателя:
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
- avrdude ser_open() can't set com-state
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- Ведомое устройство Arduino с двумя мастерами, использующими одну и ту же шину I2C?
- Arduino Uno: avrdude: stk500_recv(): программатор не отвечает
- В чем разница между delay() и delaymicroseconds()
- Программирование Arduino на Паскале?
- Как синхронизировать несколько ардуино?
- Arduino nano KiCad символы
спасибо, брат, это сработало...... большое спасибо...., @Anuragverma2804
Мы используем,чтобы отправить 8,N,2 и получить на 8,N, 1. Это дало нам дополнительное время, чтобы приспособиться к перекосу часов., @Gil