SoftwareSerial и HC-06. Получение цельных данных

Twilkeris
Offline
Зарегистрирован: 05.02.2016

Добрый день, уважаемые форумчане! 

Есть последовательность команд типа: $l123;d25;r7859;moff#  ,где 

$ - начало команд
; - разделитель между отдельными командами 
l,d,r,moff - типы команд
123,25,7859 - значение команды
# - конец списка команд

Количество команд в последовательности не имеет жесткого ограничения. Необходимо получить последовательность целиком. В этом проблема. 

Пытался двигаться в этом направлении: 

void loop() {
  if(mySerial.available()>0){
    symbol = mySerial.read();
    incomingByte = symbol; 
    if(incomingByte !=-1){
      command = command + symbol;
    }
  }
}

С двумя символами способ работает, но когда посылаю 3 символа, то последний не отображается. Если посылаю 4, то появляются кракозябры. Видимо, не успевает долетать информация или я её неправильно оргнизую. Подскажите пожалуйста, в каком направлении двигаться для решения это задачи? Использовать readBytes()?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, по этому куску ничего не скажешь. Каких типов command , incomingByte и symbol ? Почему Вы нигде не проверяеете на конец посылки (#)? Что значит " посылаю 3 символа"? Символа или команды?

В общем, если хотите нормального обсуждения, делайте пример работающего скетча на десяток строк в котором Вы принимаете ntrcn и печатаете в сериал. Пишите что вводите в мониторе порта и что потом печатается (последнее копипастом). Тогда можно будет о чём-то говорить. Сейчас же ... хрустальные шары на этом форуме запрещены, так что ...

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Можно этой штукой считать

Serial.readBytesUntil(character, buffer, length)

А можно просто в цикле читать и складывать в буфер пока не встретили #. Потом уже спокойно разбирать пакет (или обнаружить что это был и не пакет а что-то "искаженное").

 

Twilkeris
Offline
Зарегистрирован: 05.02.2016

ЕвгенийП, хотел проверить возможность получения трех символов(которые не относятся к поставленной задаче), но даже три символа нормально считать не удалось. 

Penni, в readBytesUntil() необходимо указывать кол-во байтов, которые нужно считать, а это неизвестно. 

Буду пробовать считывать до '#', хотя вчера вечером такое пытался релизовать, но программа не находила символ '#'. Скорее всего сам ошибку допустил. Буду смотреть. 

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Какой-то размер вы все равно будите для буфера приемного указывать, например, 30-50 байт, чтобы точно любой пакет влез. Вот это число и указывайте в readBytesUntil. Она прервется по любому из трех событий, встретили символ конца, прочитали всю длину либо вышел таймаут. В идеальном варианте она всегда будет прерываться по символу #

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Если без всяких проверок на ошибки при приеме и прочего, то вот так, примерно

#define IN_BUFFER_SIZE 50

char inBuffer[IN_BUFFER_SIZE];

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

void loop()
{
  if(Serial.available())
  {
    memset(inBuffer, '\0', IN_BUFFER_SIZE);
    Serial.readBytesUntil('#', inBuffer, IN_BUFFER_SIZE);
    char * pch = strtok (inBuffer,"$;#");
    while (pch != NULL)
    {
        Serial.println(pch);
        pch = strtok (NULL, "$;#");
    }
  }
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Twilkeris пишет:

но даже три символа нормально считать не удалось. 

Мой текст

ЕвгенийП пишет:
если хотите нормального обсуждения, делайте пример работающего скетча на десяток строк в котором Вы принимаете ntrcn и печатаете в сериал. Пишите что вводите в мониторе порта и что потом печатается (последнее копипастом).

Остаётся в силе.

Twilkeris
Offline
Зарегистрирован: 05.02.2016

Penni, спасибо большое! Изучил Ваш код, теперь всё работает.

Только если между (13 и 14) и (15  и 16) строчками в коде из сообщения #5 делаю вывод сообщения в порт через .println(), то появляются крокозябры в принятой команде.. Не знаю чем это можно объяснить. В моей программме нет необходимости в этих частях что-то выводить, но всё же особенность заинтересовала. Был бы благодарен, если кто-нибудь смог бы ткнуть меня носом в нужном направлении.

 

Пока что тестирую обработку принятой команды, поэтому часть кода Penni не использую. В качестве входных данных использую команду "u100". Получаю команду, записываю в inBuffer и вызываю функцию goMove(), которая занимается обработкой команды. Записываю char* pch в String command, потому что со String привык работать, а вот char* для меня дикий зверь. 

Проблема в том, что не выполняется(видимо) код из строк 22, 26, 27. Пробовал ставить в разные места - результат не меняется: в ответ ничего не приходит и, соответственно, код в switch() не выполняется. Подскажите пожалуйста, в чём я допустил ошибку? 

SoftwareSerial mySerial(51, 50);
const int IN_BUFFER_SIZE = 64;
char inBuffer[IN_BUFFER_SIZE];
void loop() {
  if(mySerial.available()>0){
    
    memset(inBuffer, '\0', IN_BUFFER_SIZE);
    mySerial.readBytesUntil('#', inBuffer, IN_BUFFER_SIZE); 
    goMove(inBuffer);
  }
}
void goMove(char* pch){
  String command = pch;
  mySerial.println("command: " + command);
  
  if(isDigit(command.charAt(1))){
    String str_value = "";
    int value = 0;
    for(int k=1; k<command.length(); k++){
      str_value = str_value + pch[k];
    }
    mySerial.println("charAt(): " + command.charAt(0)); 
    mySerial.println("str_value: " + str_value);
    
    value = str_value.toInt();
    mySerial.println("value: " + value);
    mySerial.println("charAt(): " + command.charAt(0));
     
    switch(command.charAt(0)){
      case 'u':
        movement.to_up(value);
      case 'd':
        movement.to_down(value);
      case 'l':
        movement.to_left(value);
      case 'r':
        movement.to_right(value);
    }
  }
}

 

Penni
Penni аватар
Offline
Зарегистрирован: 18.01.2015

Во-первый: зачем Вы в 20 строке опять берете pch если у вас уже в 13 строке всё взято и дальше только со String можно работать. Заменяете в 20 строке pch[k] на command.charAt(k) и все будет хорошо.

Во-вторых: конструкции вида mySerial.println("charAt(): " + command.charAt(0)); не поддерживаются. Надо либо писать шаблон и выводить как в си через << либо заменять на print и println.

В-третьих: после каждого case надо ставить break; иначе будите выполнять все кейзы после верного.

Ну и PS: String Вам тут совсем не нужен, гуглите cstring и используйте. Плюс atoi.

Twilkeris
Offline
Зарегистрирован: 05.02.2016

Penni, большое спасибо! Теперь всё работает. Без Вас бы ничего у меня не получилось.