Потеря данных при обмене по беспроводному 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, написал
void SendBuffer( char *s) { while(*s) { mySerial.write(*s++); delay(1); } }Потери прекратились. Теперь ясно, что Slave слишком быстро выдавал. Точнее, скорее всего, прием был и остается корявым. Помозгую, как избавиться от delay и переделать прием. Хотя, если честно, корень проблемы до конца не понял, проверка наличия входных символов сделана внутри loop, рано или поздно .available() должна была стать >0, а переполнения буфера точно не было...
Когда я писал процедуру обмена с бесперебойниками APC, то изучал всякие материалы... и наткнулся на рекомендацию не сильно спешить при отправке данных. Единственное мое предположение состоит в том, что на железке маленький буфер или анализ пакета происходит на лету и немного тормознут, поэтому буквочки теряются. Поэтому лучше говорит ему медленнее, чтобы он разбирать слоги успевал.