парсинг NMEA

gzp13
Offline
Зарегистрирован: 06.04.2015

Еще один вопрос знатокам) Вот код.



#include <iarduino_OLED.h>
#include <SoftwareSerial.h>
#include <MsTimer2.h>  
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 9600;
//
SoftwareSerial ss(RXPin, TXPin);
iarduino_OLED  myOLED(0x3C);                               // Объявляем объект myOLED, указывая адрес дисплея на шине I2C: 0x3C или 0x3D.
extern uint8_t MediumFontRus[]; // Подключаем шрифт MediumFontRus.
extern uint8_t SmallFontRus[]; 
extern uint8_t BigNumbers[]; 
int flag=0;
int flag1=0;
int flag2=0;
byte n;
byte regim=1;
byte speed1;
float gps_speed;
 void flash() {
  static boolean output = HIGH;
  
  digitalWrite(7, output);
  output = !output;
}
 
void setup(void) {
   MsTimer2::set(150, flash); // 500ms period
  MsTimer2::start();
Serial.begin(57600);
  ss.begin(GPSBaud);
  myOLED.begin();
  delay(200);
  pinMode(7, OUTPUT);
   pinMode(9,OUTPUT);
  digitalWrite(9,HIGH );
  delay(200);
  myOLED.begin(); 
myOLED.setFont(MediumFontRus);                           // Указываем шрифт который требуется использовать для вывода цифр и текста.
myOLED.print(F("УРАГАН-13"), 8,24);
myOLED.print(F("Клеменчев"), 8,60);

  delay(2000);
  myOLED.clrScr();
//myOLED.print(("ГОРОД"), 5,14);
myOLED.setCursor(80,55);
myOLED.setFont(MediumFontRus);
myOLED.print("КМ/Ч");
myOLED.autoUpdate(false);  
}
//
// Эта функция принимает символ из Serial и возвращает
//  указатель на полученную строку или NULL, если строка
//  ещё не получена.
// Строка всегда начинается с $ и заканчивается \r или \n
//
static const int MAX_LEN = 120; // 120 - максимальная длина строки - надо посмотреть правильное значение в описании протокола!

char * getStrFromSerial(void) {
  static bool waitingForStrBegin = true; // истина, если мы ждём начала строки ($)
  static char strBuf[MAX_LEN];  // буфер для строки
  static int ptr = 0; // индекс свободного байта в буфере

  //
  //  Если буфер переполнился, печатаем сообщение и начинаем ждать новую строку
  //
  if (ptr >= MAX_LEN) {
    Serial.println("*** Error: Too long string!!!");
    ptr = 0;
    waitingForStrBegin = true;
    return NULL;
  }
  //
  //  Если в Serial ничего нет - выходим
  //  А если есть, то читаем 1 символ
  //
  if (!ss.available()) return NULL;
  const char c = ss.read();
 
  Serial.print(c);
  //
  //  Если мы ждём начала строки, то сравинваем 
  //  прочитанный символ с '$', если равен - начало найдено
  //
  if (waitingForStrBegin) {
    if (c == '$') {
      ptr = 0;
      strBuf[ptr++] = c;
      waitingForStrBegin = false;
    } 
    return NULL;
  }
  //
  //  Если прочитанный символ - перевод строки или возврат каретки
  //  то считаем, что строка закончилась. Возвращаем её,
  // а сами готовимся ждать новую.
  //
  if (c == '\r' || c == '\n') {
    strBuf[ptr] = '\0';
    waitingForStrBegin = true;
    return strBuf;
  }
  //
  //  Просто записываем символ в строку
  //
  strBuf[ptr++] = c;
  return NULL;
}

//
//  Читаeм долготу и широту, складывает в lon и lat
// Возвращает true, если прочитала и false если нет
//
bool readLatLon(double & time,double & latitude,  double & speed  ) 
{
  

  //  getStrFromSerial() вернёт строку, полученную из Serial
  // или NULL, если строка ещё пока не получена
  //
  const char * str = getStrFromSerial();
  //
  //  Если строка ещё не получена, выходим
  //
  if (str == NULL) return false;
  //
  //  Если строка не начинается с "$GPGGA или GPRMC",
  // то она нам не нужна выходим
  //
;
  const char * prefix = "$GPRMC";
   //  
  //  
  if  ( ! strncmp(str, prefix, strlen(prefix)))
 {
 char * comma = strchr(str, ',');
  //
  //  Если не нашли (строка кривая пришла?) - выходим
  //
  if (!comma) return false;
  //
  //  со следующего символа просле запятой идёт числоа - широта
  //
  time = atof(comma+1);
  //
  //  Ищем вторую запятую после начала числа-широты
  //
 comma = strchr(comma+1, ','); // сначала ищем первую запятую 2
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 3
  if (!comma) return false; // почему-то не нашли :((((
  latitude=atof(comma+1);
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 4
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 5
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 6
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 7
    if (!comma) return false; // почему-то не нашли :((((
     speed=atof(comma+1)*1.852;   // переводим скорость в км/час
//speed=atof(comma+1);

  return true;
}
}

void loop() {
      
 
//myOLED.setFont(BigNumbers);
  //myOLED.print(speed,30,55,0);
  
   //myOLED.print(gps_speed,30,55,0);
  double speed,latitude, time;

   //Читаем время,кол-во спутников,,скорость если успешно прочитались, печатаем
  
 if (readLatLon(time, latitude,speed)) {
//speed=gps_speed;
 
//speed--;
  if (digitalRead(5)==HIGH&&flag==0)  //по нажатию кнопки включается либо режим
 {                                   // ГОРОД либо ТРАССА
  regim++;
    flag=1;
   if (regim>2) regim=1;
 }
  if (digitalRead(6)==LOW&&flag==1)
  {
   flag=0;
   }
   
if (regim==1) 
{  
  myOLED.update(); 
   myOLED.setFont(MediumFontRus); 
    myOLED.print("ГОРОД ", 2,14);
   n=1;
  speed1=1;
}
if (regim==2) 
{
  myOLED.update();
   myOLED.setFont(MediumFontRus); 
   myOLED.print("ТРАССА ", 2,14);
   n=2;
  speed1=2;
}


if (digitalRead(6)==HIGH&&flag2==0 )  // по нажатию кнопки выключается либо включается OLED дисплей
 {                                     // через полевой транзистор
  flag2=1;
  digitalWrite(9,!digitalRead(9));
 
    if (n==1) 
{
     myOLED.begin();
     myOLED.print("КМ/Ч",80,55);
    regim=1;
}
    if (n==2) 
{
    myOLED.begin();
    myOLED.print("КМ/Ч",80,55);
   regim=2;
}
 }   
   
   
 if (digitalRead(6)==LOW &&flag2==1 )
  {
    flag2=0;
   }
   

  if (speed1==1)                          //если скорость более 78км/ч моргает светодиод
  {                                       //если менее-гаснет
    if (speed>=78 )
    {
      digitalWrite(7, !digitalRead(7));
    }
  else 
  {
       digitalWrite(7,LOW);
  }
    }
if (speed1==2)
{
  if (speed>=108)                            //если скорость более 108км/ч моргает светодиод
  {                                       //если менее-гаснет          
     digitalWrite(7, !digitalRead(7));
    }
  else 
  {
    digitalWrite(7,LOW);
  }
 }
 if (latitude>10)
 {
   myOLED.setCursor(95,14); 
   myOLED.setFont(MediumFontRus);
   myOLED.print("GPS",90,14);                 //выводим кол-во спутников
 
 }
 else myOLED.print("NON",90,14);
  
    if (speed<100 && speed>10)                                 // тут при выводе скорости, если число двухзначное
{                                                // закрашиваем младший разряд
   //myOLED.print("  ",59,40);
   //myOLED.print("  ",59,55);
  } 
  if (speed<10)
  {
     myOLED.update();  
    //myOLED.print("  ",44,40);
   //myOLED.print("  ",44,55); 
   
   }
   
   myOLED.update();
  myOLED.setFont(BigNumbers);
 myOLED.print(speed,30,55,0);                         //выводим скорость
  //myOLED.print(gps_speed,30,55,0);
  Serial.println();
    Serial.print("time: ");
    Serial.print(time, 2);
    Serial.print("          latitude: ");
    Serial.print(latitude,0);
    //Serial.print("                      date: ");
    //Serial.println(date, 0);
    Serial.print("                     speed: ");
    Serial.print(speed, 4);
 
 } 
 
  }
 При таком коде данные выводятся как положено, через каждые 200мс. Результат прилагаю.
 
$GPRMC,134218.00,V,,,,,,,181018,,,N*71

time: 134218.00          latitude: 0                     speed: 0.0000
$GPRMC,134218.20,V,,,,,,,181018,,,N*73

time: 134218.20          latitude: 0                     speed: 0.0000
$GPRMC,134218.40,V,,,,,,,181018,,,N*75

time: 134218.39          latitude: 0                     speed: 0.0000
$GPRMC,134218.60,V,,,,,,,181018,,,N*77

time: 134218.59          latitude: 0                     speed: 0.0000

Но мне надо закрасить на экране при выводе скорости два правых разряда, чтобы при скорости менее 10км/ч на дисплее индицировалось однозначное число.(просто если скорость была более 10км/час то младший разряд остается на экране, вот я и затираю его пробелами). Так вот, при раскомментировании строк 276-277   получается вот такой результат.

$GPRMC,134023.20,V,,,,,,,181018,,,N*79

time: 134023.20          latitude: 0                     speed: 0.0000
$GPRMC,134023.40,V,,,,$GPRMC,134023.60,V,,,,,,,181018,,,N*7D

time: 134023.39          latitude: 0                     speed: 248211.7031
$GPRMC,134023.80,V,,,,,,,181018,,,N*73

Почему то сообщение GPRMC выводится не правильно.Как видно еще и вывод информации идет не строго через 200мс.

Можно ли что то предпринять для устранения данной проблемы?

 

renoshnik
Offline
Зарегистрирован: 11.04.2013

gzp13 пишет:

Еще один вопрос знатокам) Вот код.

 При таком коде данные выводятся как положено, через каждые 200мс. Результат прилагаю.
 
$GPRMC,134218.00,V,,,,,,,181018,,,N*71

time: 134218.00          latitude: 0                     speed: 0.0000
$GPRMC,134218.20,V,,,,,,,181018,,,N*73

time: 134218.20          latitude: 0                     speed: 0.0000
$GPRMC,134218.40,V,,,,,,,181018,,,N*75

time: 134218.39          latitude: 0                     speed: 0.0000
$GPRMC,134218.60,V,,,,,,,181018,,,N*77

time: 134218.59          latitude: 0                     speed: 0.0000

Но мне надо закрасить на экране при выводе скорости два правых разряда, чтобы при скорости менее 10км/ч на дисплее индицировалось однозначное число.(просто если скорость была более 10км/час то младший разряд остается на экране, вот я и затираю его пробелами). Так вот, при раскомментировании строк 276-277   получается вот такой результат.

$GPRMC,134023.20,V,,,,,,,181018,,,N*79

time: 134023.20          latitude: 0                     speed: 0.0000
$GPRMC,134023.40,V,,,,$GPRMC,134023.60,V,,,,,,,181018,,,N*7D

time: 134023.39          latitude: 0                     speed: 248211.7031
$GPRMC,134023.80,V,,,,,,,181018,,,N*73

Почему то сообщение GPRMC выводится не правильно.Как видно еще и вывод информации идет не строго через 200мс.

Можно ли что то предпринять для устранения данной проблемы?

Конечно можно . Строка 002 .

gzp13
Offline
Зарегистрирован: 06.04.2015
Конечно можно . Строка 002 .

Переподключился к аппаратному порту, скорость GPS изменил уже на 9600, порт тоже настроен на 9600, результат тот же.Почему то сообщение когда время 144256,40 пропускается, а перед ним выводится не полностью.

$GPRMC,144256.20,V,,,,$GPRMC,144256.40,V,,,,,,,181018,,,N*78

time: 144256.20          latitude: 0                     speed: 267162.8437
$GPRMC,144256.60,V,,,,,,,181018,,,N*7A

time: 144256.59          latitude: 0                     speed: 0.0000
$GPRMC,144256.80,V,,,,,,,181018,,,N*74

time: 144256.79          latitude: 0                     speed: 0.0000
$GPRMC,144257.00,V,,,,$GPRMC,144257.20,V,,,,,,,181018,,,N*7F

time: 144257.00          latitude: 0                     speed: 267164.3437


#include <iarduino_OLED.h>
//#include <SoftwareSerial.h>
#include <MsTimer2.h>  
//static const int RXPin = 4, TXPin = 3;
//static const uint32_t GPSBaud = 9600;
//
//SoftwareSerial ss(RXPin, TXPin);
iarduino_OLED  myOLED(0x3C);                               // Объявляем объект myOLED, указывая адрес дисплея на шине I2C: 0x3C или 0x3D.
extern uint8_t MediumFontRus[]; // Подключаем шрифт MediumFontRus.
extern uint8_t SmallFontRus[]; 
extern uint8_t BigNumbers[]; 
int flag=0;
int flag1=0;
int flag2=0;
byte n;
byte regim=1;
byte speed1;
float gps_speed;
 void flash() {
  static boolean output = HIGH;
  
  digitalWrite(7, output);
  output = !output;
}
 
void setup(void) {
   MsTimer2::set(150, flash); // 500ms period
  MsTimer2::start();
Serial.begin(9600);
  //ss.begin(GPSBaud);
  myOLED.begin();
  delay(200);
  pinMode(7, OUTPUT);
   pinMode(9,OUTPUT);
  digitalWrite(9,HIGH );
  delay(200);
  myOLED.begin(); 
myOLED.setFont(MediumFontRus);                           // Указываем шрифт который требуется использовать для вывода цифр и текста.
myOLED.print(F("УРАГАН-13"), 8,24);
myOLED.print(F("Клеменчев"), 8,60);

  delay(2000);
  myOLED.clrScr();
//myOLED.print(("ГОРОД"), 5,14);
myOLED.setCursor(80,55);
myOLED.setFont(MediumFontRus);
myOLED.print("КМ/Ч");
myOLED.autoUpdate(false);  
}
//
// Эта функция принимает символ из Serial и возвращает
//  указатель на полученную строку или NULL, если строка
//  ещё не получена.
// Строка всегда начинается с $ и заканчивается \r или \n
//
static const int MAX_LEN = 120; // 120 - максимальная длина строки - надо посмотреть правильное значение в описании протокола!

char * getStrFromSerial(void) {
  static bool waitingForStrBegin = true; // истина, если мы ждём начала строки ($)
  static char strBuf[MAX_LEN];  // буфер для строки
  static int ptr = 0; // индекс свободного байта в буфере

  //
  //  Если буфер переполнился, печатаем сообщение и начинаем ждать новую строку
  //
  if (ptr >= MAX_LEN) {
    Serial.println("*** Error: Too long string!!!");
    ptr = 0;
    waitingForStrBegin = true;
    return NULL;
  }
  //
  //  Если в Serial ничего нет - выходим
  //  А если есть, то читаем 1 символ
  //
  if (!Serial.available()) return NULL;
  const char c = Serial.read();
 
  Serial.print(c);
  //
  //  Если мы ждём начала строки, то сравинваем 
  //  прочитанный символ с '$', если равен - начало найдено
  //
  if (waitingForStrBegin) {
    if (c == '$') {
      ptr = 0;
      strBuf[ptr++] = c;
      waitingForStrBegin = false;
    } 
    return NULL;
  }
  //
  //  Если прочитанный символ - перевод строки или возврат каретки
  //  то считаем, что строка закончилась. Возвращаем её,
  // а сами готовимся ждать новую.
  //
  if (c == '\r' || c == '\n') {
    strBuf[ptr] = '\0';
    waitingForStrBegin = true;
    return strBuf;
  }
  //
  //  Просто записываем символ в строку
  //
  strBuf[ptr++] = c;
  return NULL;
}

//
//  Читаeм долготу и широту, складывает в lon и lat
// Возвращает true, если прочитала и false если нет
//
bool readLatLon(double & time,double & latitude,  double & speed  ) 
{
  

  //  getStrFromSerial() вернёт строку, полученную из Serial
  // или NULL, если строка ещё пока не получена
  //
  const char * str = getStrFromSerial();
  //
  //  Если строка ещё не получена, выходим
  //
  if (str == NULL) return false;
  //
  //  Если строка не начинается с "$GPGGA или GPRMC",
  // то она нам не нужна выходим
  //
;
  const char * prefix = "$GPRMC";
   //  
  //  
  if  ( ! strncmp(str, prefix, strlen(prefix)))
 {
 char * comma = strchr(str, ',');
  //
  //  Если не нашли (строка кривая пришла?) - выходим
  //
  if (!comma) return false;
  //
  //  со следующего символа просле запятой идёт числоа - широта
  //
  time = atof(comma+1);
  //
  //  Ищем вторую запятую после начала числа-широты
  //
 comma = strchr(comma+1, ','); // сначала ищем первую запятую 2
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 3
  if (!comma) return false; // почему-то не нашли :((((
  latitude=atof(comma+1);
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 4
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 5
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // сначала ищем первую запятую 6
  if (!comma) return false; // почему-то не нашли :((((
  comma = strchr(comma+1, ','); // теперь ищем вторую запятую 7
    if (!comma) return false; // почему-то не нашли :((((
     speed=atof(comma+1)*1.852;   // переводим скорость в км/час
//speed=atof(comma+1);

  return true;
}
}

void loop() {
      
 
//myOLED.setFont(BigNumbers);
  //myOLED.print(speed,30,55,0);
  
   //myOLED.print(gps_speed,30,55,0);
  double speed,latitude, time;

   //Читаем время,кол-во спутников,,скорость если успешно прочитались, печатаем
  
 if (readLatLon(time, latitude,speed)) {
//speed=gps_speed;
 
//speed--;
  if (digitalRead(5)==HIGH&&flag==0)  //по нажатию кнопки включается либо режим
 {                                   // ГОРОД либо ТРАССА
  regim++;
    flag=1;
   if (regim>2) regim=1;
 }
  if (digitalRead(6)==LOW&&flag==1)
  {
   flag=0;
   }
   
if (regim==1) 
{  
  myOLED.update(); 
   myOLED.setFont(MediumFontRus); 
    myOLED.print("ГОРОД ", 2,14);
   n=1;
  speed1=1;
}
if (regim==2) 
{
  myOLED.update();
   myOLED.setFont(MediumFontRus); 
   myOLED.print("ТРАССА ", 2,14);
   n=2;
  speed1=2;
}


if (digitalRead(6)==HIGH&&flag2==0 )  // по нажатию кнопки выключается либо включается OLED дисплей
 {                                     // через полевой транзистор
  flag2=1;
  digitalWrite(9,!digitalRead(9));
 
    if (n==1) 
{
     myOLED.begin();
     myOLED.print("КМ/Ч",80,55);
    regim=1;
}
    if (n==2) 
{
    myOLED.begin();
    myOLED.print("КМ/Ч",80,55);
   regim=2;
}
 }   
   
   
 if (digitalRead(6)==LOW &&flag2==1 )
  {
    flag2=0;
   }
   

  if (speed1==1)                          //если скорость более 78км/ч моргает светодиод
  {                                       //если менее-гаснет
    if (speed>=78 )
    {
      digitalWrite(7, !digitalRead(7));
    }
  else 
  {
       digitalWrite(7,LOW);
  }
    }
if (speed1==2)
{
  if (speed>=108)                            //если скорость более 108км/ч моргает светодиод
  {                                       //если менее-гаснет          
     digitalWrite(7, !digitalRead(7));
    }
  else 
  {
    digitalWrite(7,LOW);
  }
 }
 if (latitude>10)
 {
   myOLED.setCursor(95,14); 
   myOLED.setFont(MediumFontRus);
   myOLED.print("GPS",90,14);                 //выводим кол-во спутников
 
 }
 else myOLED.print("NON",90,14);
  
    if (speed<100 && speed>10)                                 // тут при выводе скорости, если число двухзначное
{                                                // закрашиваем младший разряд
  // myOLED.drawRect   (59, 28,  78, 57, true , 0);
    //myOLED.print("  ",59,40);
   //myOLED.print("  ",59,55);
  } 
  if (speed<10)
  {
     myOLED.update();  
    //myOLED.drawRect   (44, 28,  78, 57, true , 0);
   myOLED.print("  ",44,40);
   myOLED.print("  ",44,55); 
   
   }
   
   myOLED.update();
  myOLED.setFont(BigNumbers);
 myOLED.print(speed,30,55,0);                         //выводим скорость
  //myOLED.print(gps_speed,30,55,0);
  Serial.println();
    Serial.print("time: ");
    Serial.print(time, 2);
    Serial.print("          latitude: ");
    Serial.print(latitude,0);
    //Serial.print("                      date: ");
    //Serial.println(date, 0);
    Serial.print("                     speed: ");
    Serial.print(speed, 4);
 
 } 
 
  }
 
 

 

APJ
Offline
Зарегистрирован: 25.03.2015

b707 пишет:

APJ пишет:

Сейчас меняю скорость порта этим сообщением-   ss.print("$PUBX,41,1,3,3,38400,0*24\r\n");

Хватает до первого выключения питания.

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

Да, настройки слетают через пару часов без питания.

Пробую перехватывать сообщения с u-centre, выходит какой-то бред.

Скажем это частота 5 Гц, в хексе-   B5 62 06 08 06 00 F4 01 01 00 01 00 0B 77

Если пробовать конвертировать в ASCII, то получается какя-то ерунда.

Как вставить это в код? Скорость меняю этой строчкой - ss.print("$PUBX,41,1,3,3,38400,0*24\r\n");

APJ
Offline
Зарегистрирован: 25.03.2015

Возможно кому нибудь это пригодиться. Изменение настроек U-Blox

void setup()
{

 byte message1[] = {0xB5,0x62,0x06,0x08,0x06,0x00,0xC8,0x00,0x01,0x00,0x01,0x00,0xDE,0x6A};

byte message2[] = {0xB5,0x62,0x06,0x09,0x0D,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x31,0xBF};

  Serial.begin(9600);
  delay(200);
  ss.begin(9600);

ss.println("$PUBX,40,GSV,0,0,0,0,0,0*59");
ss.println("$PUBX,40,GSA,0,0,0,0,0,0*4E");
ss.println("$PUBX,40,VTG,0,0,0,0,0,0*5E");
ss.println("$PUBX,40,ZDA,0,0,0,0,0,0*44");
ss.println("$PUBX,40,GLL,0,0,0,0,0,0*5C"); //Отключаем все посылки кроме GLL и RMC

ss.write(message1, sizeof(message1));  //set 5Hz
//ss.write(message2, sizeof(message2)); //save settings.  Это не  обязательно. Без сохранения будет работать до отключения питания с приёмника