Помогите разобраться с разбором строки

Onionsis
Offline
Зарегистрирован: 11.06.2018

Добрый день!

Есть ардуино нано и модуль gps+glonass. 

Модуль отправляет координаты и т.д. в таком виде:

$GPGGA,013306.40,5553.95206,N,03734.64397,E,1,08,1.16,243.9,M,13.3,M,,*5E
$GPRMC,013306.50,A,5553.95206,N,03734.64397,E,0.041,,110618,,,A*7A
$GPVTG,,T,,M,0.041,N,0.075,K,A*24
$GPRMC,013306.70,A,5553.95207,N,03734.64396,E,0.071,,110618,,,A*7B
$GPVTG,,T,,M,0.071,N,0.132,K,A*25
$GPRMC,013306.80,A,5553.95207,N,03734.64396,E,0.058,,110618,,,A*7F
$GPVTG,,T,,M,0.058,N,0.108,K,A*27
$GPRMC,013306.90,A,5553.95207,N,03734.64395,E,0.121,,110618,,,A*72
$GPVTG,,T,,M,0.121,N,0.223,K,A*22
Необходимо вытащить из строки $GPGGA, содержащиеся в ней координаты и время.
Пробовал использовать вот такой код
#include <SoftwareSerial.h>
SoftwareSerial mySerial(4, 5); // RX, TX

char st = '0';
String time;
String lat;
char lat_s;
String lon;
char lon_s;
char qual;
String sats;
String alt;

boolean renew = false;

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

String readVal() {
  boolean rot = true;
  String buffer;
  while (rot) {
    int b = mySerial.read();
    if ( (('0' <= (char)b) && ((char)b <= '9')) || ((char)b == '.') || (('A' <= (char)b) && ((char)b <= 'Z')) ) { // считываем значения, содержащие цифры, буквы и точку
      buffer += (char)b;
    }
     if ( (char)b == ',' ) rot = false; // заканчиваем читать, когда встречаем запятую

  }
  return buffer;
}

void loop() // run over and over
{
  int b = mySerial.read();
// Serial.write(b);
 //Serial.write(st);

  switch ( st ) { // перебираем состояния
    case '0': if ('&' == b) st = '1'; else st = '0';
      break;
    case '1': if ('G' == b) st = '2'; else st = '0';
      break;
    case '2': if ('P' == b) st = '3'; else st = '0';
      break;
    case '3': if ('G' == b) st = '4'; else st = '0';
      break;
    case '4': if ('G' == b) st = '5'; else st = '0';
      break;
    case '5': if ('A' == b) st = '6'; else st = '0';
      break;
    case '6': if ('.' == b) { // распознали $GPGGA
 {
        time = readVal();
        lat = readVal();
        lat.replace('.', ',');
        lat_s = (char)readVal()[0];
        lon = readVal();
        lon.replace('.', ',');
        lon_s = (char)readVal()[0];
        qual = (char)readVal()[0];
        sats = readVal();
        readVal(); // skip empty
        alt = readVal();
    }
       renew = true;
       st = '0';
     } else st = '0';
      break;
  }

  //if (renew)  {
  //  Serial.print("Time: " + time + " Lat/Lon: " + lat_s + lat + " " + lon_s + lon + "\r\n");
 //   renew = false;
  //}
  delay(10);
  }

При просмотре переменной b вижу такую ерунду, данные искажаются и соответственно распозновать нечего.

Подправьте пожалуйста где и что не так.

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

b должно быть типа char для такого сравнения.

Andy
Andy аватар
Offline
Зарегистрирован: 01.01.2016

Строки начинаются на $, а ты ищешь &

Onionsis
Offline
Зарегистрирован: 11.06.2018

sadman41 пишет:

b должно быть типа char для такого сравнения.

26    int b = mySerial.read();

Правильно понимаю, что эту строку надо поменять так

26

    (char) b = mySerial.read();

Andy пишет:

Строки начинаются на $, а ты ищешь &

Опечатался, когда код возвращал в исходное состояние. Я пробовал начинать искать не с $, а сразу с буквы G

И Главное, что я не понимаю почему так искажаются данные в переменной B.

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

Что-то я невнимательно посмотрел. Вы еще и не проверяете перед чтением имеется ли что-то в буфере mySerial , что не очень правильно. Вот стандартный пример работы с Serial/SoftSerial:

  while (SoftSerial.available() > 0) {
    char inChar = SoftSerial.read();
    Serial.print(inChar);
  }

Конечно, чтение значения прямо в char - это дискуссионный момент, но я предпочитаю делать так, чтобы потом чесать в голове, раздумывая чего это у меня println() хренотень выводит вместо символа.

 

Onionsis
Offline
Зарегистрирован: 11.06.2018

Суть этого когда в том, чтобы "на лету" читать данные из сериала.

И все равно не понимаю, почему оно не работает.

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

На интуитивном уровне мне кажется, что у парсера проблемы с опознаванием конца старой / начала новой строки. И вообще он подозрительный. Например, вот это: case '6': if ('.' == b) - после $GPGGA нет точки.

Так же не знаю, насколько правомерно возвращать указатель на локальную (уничтожаемую при завершении) строку в функции readVal(). С классом String не работал, но нормальные функции работы с памятью так не делают.

Словом, тут в каждой строчке мина заложена. Так что начните с простого - правильной работы с mySerial и четкого определения начала новой строки. При отладочной печати как-нибудь их выделяйте что ли... Я вот, к примеру, не понимаю, что вы считаете неправильным выводом. Как написана программа - так и выводится.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

sadman41 пишет:

Так же не знаю, насколько правомерно возвращать указатель на локальную (уничтожаемую при завершении) строку в функции readVal(). С классом String не работал, но нормальные функции работы с памятью так не делают.

Там не указатель возвращается, а экземпляр класса. С точки зрения памяти там всё норм - внутри класса всё обрабатывается, есть конструкторы копирования, оператор присваивания и т.п. - так что всё норм.

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

А чего не пользуетесь готовыми библиотеками для разбора Какая-нибудь TinyGPS распарсит всё за милую душу.

Onionsis
Offline
Зарегистрирован: 11.06.2018

Это малая часть задач, а в ардуино мини не так много памяти

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

Так можно же взять библиотеку и просто выбросить их неё лишнее. Сама-то по себе она работает и всё нормально парсит.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Onionsis пишет:

Это малая часть задач, а в ардуино мини не так много памяти

Ну надо прямо заметить, что Ардуино Мини отнюдь не любая задача по плечу.

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