Потеря данных при обмене по беспроводному UART HC-12

Valerikum
Offline
Зарегистрирован: 10.07.2017

Коллеги, помогите разобраться, что-то я застопорился.

Имеется тестовая конфигурация для отладки беспроводного обмена сообщениями 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);
  }
}

Я не могу понять, почему у меня не вводятся длинные сообщения. Возможно, взгляд "замылился", и я просто не вижу очевидного, либо чего-то не учел.

Подскажите...

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Пожалуй, что стоит заставить while проверять не количество символов в буфере, а наличие терминирующего символа. В противном случае любая задержка в середине передачи пакета приведет к досрочному прекращению цикла анализатора.

Valerikum
Offline
Зарегистрирован: 10.07.2017

Да, приведёт, но при следующем входе в функцию чтения, Serial1.available должен стать >0, а он остаётся нулевым, как будто вторая часть сообщения не пришла. Вот это и странно, такое впечатление что конец сообщения просто не приходит. Куда девается? 

sadman41
Offline
Зарегистрирован: 19.10.2016

Куда... Клапауций запретил приниматься целиком, наверное. Чем гадать - на стороне приемника повыводите все принимаемое в Терминал без маркеров, записи в буфер и пр. Таким образом сузите круг подозреваемых.

Valerikum
Offline
Зарегистрирован: 10.07.2017

Сначала посмотрю аппаратную часть. На Меге к serial2 подключусь, проверю, Hc-12 другие поставлю.

отладочная печать как раз показывает, что больше символов нет. Мистика или железные глюки, может, потому что Китай.

 

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Попытайтесь писать в канал медленнее, а читать быстрее. Может дело в связи между БТ.

Valerikum
Offline
Зарегистрирован: 10.07.2017

Наверняка так и есть, только вот Slave как раз на SoftwareSerial, поэтому должен быть медленнее аппаратного.

попробую и там  задержку поставить

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Я бы не стал тормозить принимающую часть.

Valerikum
Offline
Зарегистрирован: 10.07.2017

Замедлил вывод со стороны Slave, поставив delay(1), что гадко, конечно.

Вместо исходного mySerial.print, написал

void SendBuffer( char *s) {
  while(*s) {
    mySerial.write(*s++);
    delay(1);
  }
}

Потери прекратились. Теперь ясно, что Slave слишком быстро выдавал. Точнее, скорее всего, прием был и остается корявым. Помозгую, как избавиться от delay и переделать прием. Хотя, если честно, корень проблемы до конца не понял, проверка наличия входных символов сделана внутри loop, рано или поздно .available() должна была стать >0, а переполнения буфера точно не было...

 

sadman41
Offline
Зарегистрирован: 19.10.2016

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