Потеря данных при обмене по беспроводному UART HC-12
- Войдите на сайт для отправки комментариев
Коллеги, помогите разобраться, что-то я застопорился.
Имеется тестовая конфигурация для отладки беспроводного обмена сообщениями 2 ардуинок, один предполагается, что он Master, другая, соответственно, Slave.
Master собран на Mega, HC-12 подключен к аппаратному Serial1
Slave собран на Nano, HC-12 на SoftwareSerial.
Для простоты тестируем режим "Эхо"- Master получает строку с клавиатуры через Serial, ограниченную маркерами '[' и ']', и передает через Serial1 на удаленный Slave. Slave, в свою очередь, используя другие маркеры начала и конца сообщения ('<' и '>' ) это сообщение считывает, переупаковывает, и отправляет назад Мастеру. Master должен все это получить и вывести эту строчку в порт как эхо.
Вот так, к примеру
Input:<123456> Echo : 123456
И все работало, пока я не обратил внимание, что максимальное кол-во символов, которые я могу нормально получить назад, не более 18- 2 символа на маркеры < и > + само сообщение:
Это строка максимальной длины, которую я получаю нормально в качестве эха
Input:<1234567890123456> Echo : 1234567890123456
Если длиннее, то Master подвисает после 18 байт, и так и не может получить маркер конца сообщения '>'
Отладочная печать показала, что эти 18 байт Master всасывает за 1 заход внутрь while, а затем, при следующем входе в функцию чтения, такое чувство, что Serial1.available() > 0 не выполняется. С чего бы это ?
Вот посмотрите, код для Slave - пока есть что в буфере, читает, пока не встретит маркер конца сообщения '>', после чего все, что накопилось в буфере, выплевывает назад.
#include <SoftwareSerial.h> #define BUFSIZE 64 #define STARTMARKER '<' #define ENDMARKER '>' #define MYRX 2 #define MYTX 3 SoftwareSerial mySerial(MYRX, MYTX); //RX, TX char InBuffer[BUFSIZE]; char OutBuffer[BUFSIZE]; void setup() { mySerial.begin(9600); } void ExecuteCommand( char *s) { sprintf(OutBuffer, "<%s>", s); mySerial.print(OutBuffer); mySerial.flush(); } byte bufindex = 0; void CheckAndReadInMessage( void ) { byte c; while (mySerial.available() > 0) { c = mySerial.read(); if (c == STARTMARKER) bufindex = 0; else if ( c == ENDMARKER ) { InBuffer[bufindex] = 0; bufindex = 0; ExecuteCommand(InBuffer); } else InBuffer[bufindex++] = c; } } void loop() { CheckAndReadInMessage(); }
Код для мастера- аналогично. Считываем с клавиатуры через Serial до маркера ']' (сами маркеры удаляются), после чего выводим то, что ввели, в Serial1 - и оно через HC-12 летит в Slave. Затем считываем кусками то что придет обратно...
#define BUFSIZE 64 #define STARTMARKER '<' #define ENDMARKER '>' #define STARTMARKER1 '[' #define ENDMARKER1 ']' char InBuffer[BUFSIZE]; char RadioInBuffer[BUFSIZE]; // Ввод с клавиатуры uint8_t serbufindex = 0; bool CheckAndReadInMessage( void ) { char c; while (Serial.available() > 0) { c = Serial.read(); if (c == STARTMARKER1) serbufindex = 0; else if ( c == ENDMARKER1 ) { InBuffer[serbufindex] = 0; serbufindex = 0; return ( true ); } else InBuffer[serbufindex++] = c; } return ( false ); } // Ввод с радиоканала HC-12 uint8_t radiobufindex = 0; bool RadioCheckAndReadInMessage( void ) { char c; while (Serial1.available() > 0) { // delay(1); c = Serial1.read(); // Serial.write(c); if (c == STARTMARKER) radiobufindex = 0; else if ( c == ENDMARKER ) { RadioInBuffer[radiobufindex] = 0; radiobufindex = 0; return ( true ); } else { RadioInBuffer[radiobufindex++] = c; } } return ( false ); } void setup() { Serial.begin(9600); Serial1.begin(9600); } void loop() { bool f1, f2; f1 = CheckAndReadInMessage( ); if (f1) { Serial.print("Input:"); Serial.println(InBuffer); Serial1.print(InBuffer); Serial1.flush(); } f2 = RadioCheckAndReadInMessage(); if (f2) { Serial.print("Echo : "); Serial.println(RadioInBuffer); } }
Я не могу понять, почему у меня не вводятся длинные сообщения. Возможно, взгляд "замылился", и я просто не вижу очевидного, либо чего-то не учел.
Подскажите...
Пожалуй, что стоит заставить while проверять не количество символов в буфере, а наличие терминирующего символа. В противном случае любая задержка в середине передачи пакета приведет к досрочному прекращению цикла анализатора.
Да, приведёт, но при следующем входе в функцию чтения, Serial1.available должен стать >0, а он остаётся нулевым, как будто вторая часть сообщения не пришла. Вот это и странно, такое впечатление что конец сообщения просто не приходит. Куда девается?
Куда... Клапауций запретил приниматься целиком, наверное. Чем гадать - на стороне приемника повыводите все принимаемое в Терминал без маркеров, записи в буфер и пр. Таким образом сузите круг подозреваемых.
Сначала посмотрю аппаратную часть. На Меге к serial2 подключусь, проверю, Hc-12 другие поставлю.
отладочная печать как раз показывает, что больше символов нет. Мистика или железные глюки, может, потому что Китай.
Попытайтесь писать в канал медленнее, а читать быстрее. Может дело в связи между БТ.
Наверняка так и есть, только вот Slave как раз на SoftwareSerial, поэтому должен быть медленнее аппаратного.
попробую и там задержку поставить
Я бы не стал тормозить принимающую часть.
Замедлил вывод со стороны Slave, поставив delay(1), что гадко, конечно.
Вместо исходного mySerial.print, написал
Потери прекратились. Теперь ясно, что Slave слишком быстро выдавал. Точнее, скорее всего, прием был и остается корявым. Помозгую, как избавиться от delay и переделать прием. Хотя, если честно, корень проблемы до конца не понял, проверка наличия входных символов сделана внутри loop, рано или поздно .available() должна была стать >0, а переполнения буфера точно не было...
Когда я писал процедуру обмена с бесперебойниками APC, то изучал всякие материалы... и наткнулся на рекомендацию не сильно спешить при отправке данных. Единственное мое предположение состоит в том, что на железке маленький буфер или анализ пакета происходит на лету и немного тормознут, поэтому буквочки теряются. Поэтому лучше говорит ему медленнее, чтобы он разбирать слоги успевал.