Расшифруйте код GPS NMEA с помощью Arduino

Я знаю, что об этом спрашивали много раз, но я действительно не могу найти то, что действительно ищу.

Я использую Arduino Uno и GPS Shield, который показывает данные GPS через последовательный порт.

Вот код, который я загружаю в свой Arduino для интерфейса с GPS Shield:

void loop() // run over and over
{
while(!(mySerial.available())){}
Serial.write(mySerial.read());
}

Это всего лишь код. Тем не менее, поскольку он постоянно зацикливается на последовательном мониторе, он также выводит данные GPS каждую секунду.

Вот его вывод каждую секунду:

$GPGGA,013856.000,000.9090,N,9090.90,E,1,09,1.1,316.97,M,0.00,M,,*66
$GPGSA,A,3,07,08,11,1ÿ3,16,19,23,27,42,,,,2.8,1.1,2.5*3F
$GPRMC,013856.000,A,000.9090,N,9090.90,E,0.0,038.1,310814,,,A*62
$GPGSV,ÿ3,1,12,16,26,059,33,27,33,025,44,08,30,330,32,07,31,326,34*7A
$GPGSV,3,2,12,19,58,354,31,01,33,186,18,23,32,221,24,11,5ÿ9,198,31*70
$GPGSV,3,3,12,42,60,129,32,13,38,253,27,32,06,161,,31,01,140,*7E

Поскольку он обновляется каждую секунду, координаты меняются на минимальные, что означает, что GPS Shield работает.

Проблема здесь в том, что я хотел проанализировать данные GPS, особенно на линии GPGGA, и игнорировать другие линии. Я хотел бы проанализировать Индикатор состояния, Широты, N / S, Долготы и E / W.

Я искал библиотеку NMEA (http://nmea.sourceforge.net/), но я понятия не имею, как его использовать.

Может кто-нибудь помочь мне здесь? Спасибо.

1

Решение

Ты можешь использовать TinyGPS разобрать строки NMEA. Если вас интересует только 1 предложение. Вы можете написать собственный анализатор, как показано ниже, только для этого предложения.

int handle_byte(int byteGPS) {
buf[counter1] = byteGPS;
//Serial.print((char)byteGPS);
counter1++;
if (counter1 == 300) {
return 0;
}

if (byteGPS == ',') {
counter2++;
offsets[counter2] = counter1;
if (counter2 == 13) {
return 0;
}   }   if (byteGPS == '*') {
offsets[12] = counter1;   }

// Check if we got a <LF>, which indicates the end of line   if (byteGPS == 10) {

// Check that we got 12 pieces, and that the first piece is 6 characters
if (counter2 != 12 || (get_size(0) != 6)) {
return 0;
}

// Check that we received $GPRMC
// CMD buffer contains $GPRMC
for (int j=0; j<6; j++) {

if (buf[j] != cmd[j]) {
return 0;
}
}

// Check that time is well formed
if (get_size(1) != 10) {

return 0;
}

// Check that date is well formed
if (get_size(9) != 6) {
return 0;
}

SeeedOled.setTextXY(7,0);
for (int j=0; j<6; j++) {
SeeedOled.putChar(*(buf+offsets[1]+j));
}
SeeedOled.setTextXY(7,7);

for (int j=0; j<6; j++) {
SeeedOled.putChar(*(buf+offsets[9]+j));
}

// TODO: compute and validate checksum

// TODO: handle timezone offset

return 0;   }
return 1; }
0

Другие решения

Я искал в Интернете, и лучший ответ будет использовать библиотеку «TinyGPS ++» для Arduino. Почти все связанные с GPS коды уже включены в библиотеку.

1

Данные NMEA представлены в формате GPS (ddmm.ssss), Google хочет использовать их в десятичном стиле (dd.mmssss), в нижней части кода для этого шага есть функция покрытия.

Я написал это, потому что мне не нравятся большие, сложные библиотеки, чтобы делать простые мелочи, особенно когда я пытаюсь понять, как это работает.
Это анализирует предложение GLL, но вы можете изменить искомое предложение и переставить разделы, если это необходимо.

String ReadString;

void setup() {
Serial.begin(9600);  //Arduino serial monitor thru USB cable
Serial1.begin(9600); // Serial1 port connected to GPS
}

void loop() {
ReadString=Serial1.readStringUntil(13);   //NMEA data ends with 'return' character, which is ascii(13)
ReadString.trim();                      // they say NMEA data starts with "$", but the Arduino doesn't think so.
// Serial.println(ReadString);         //All the raw sentences will be sent to monitor, if you want them, maybe to see the labels and data order.

//Start Parsing by finding data, put it in a string of character array, then removing it, leaving the rest of thes sentence for the next 'find'
if (ReadString.startsWith("$GPGLL")) {   //I picked this sentence, you can pick any of the other labels and rearrange/add sections as needed.
Serial.println(ReadString);     // display raw GLL data in Serial Monitor
// mine looks like this: "$GPGLL,4053.16598,N,10458.93997,E,224431.00,A,D*7D"
//This section gets repeated for each delimeted bit of data by looking for the commas
//Find Lattitude is first in GLL sentence, other senetences have data in different order
int Pos=ReadString.indexOf(',');   //look for comma delimetrer
ReadString.remove(0, Pos+1); // Remove Pos+1 characters starting at index=0, this one strips off "$GPGLL" in my sentence
Pos=ReadString.indexOf(','); //looks for next comma delimetrer, which is now the first comma because I removed the first segment
char Lat[Pos];            //declare character array Lat with a size of the dbit of data
for (int i=0; i <= Pos-1; i++){    // load charcters into array
Lat[i]=ReadString.charAt(i);
}
Serial.print(Lat);          // display raw latitude data in Serial Monitor, I'll use Lat again in a few lines for converting
//repeating with a different char array variable
//Get Lattitude North or South
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char LatSide[Pos];           //declare different variable name
for (int i=0; i <= Pos-1; i++){
LatSide[i]=ReadString.charAt(i);  //fill the array
Serial.println(LatSide[i]);       //display N or S
}

//convert the variable array Lat to degrees Google can use
float LatAsFloat = atof (Lat);            //atof converts the char array to a float type
float LatInDeg;
if(LatSide[0]==char(78)) {        //char(69) is decimal for the letter "N" in ascii chart
LatInDeg= ConvertData(LatAsFloat);   //call the conversion funcion (see below)
}
if(LatSide[0]==char(83)) {        //char(69) is decimal for the letter "S" in ascii chart
LatInDeg= -( ConvertData(LatAsFloat));   //call the conversion funcion (see below)
}
Serial.println(LatInDeg,15); //display value Google can use in Serial Monitor, set decimal point value high
//repeating with a different char array variable
//Get Longitude
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char Longit[Pos];             //declare different variable name
for (int i=0; i <= Pos-1; i++){
Longit[i]=ReadString.charAt(i);      //fill the array
}
Serial.print(Longit);      //display raw longitude data in Serial Monitor
//repeating with a different char array variable
//Get Longitude East or West
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char LongitSide[Pos];         //declare different variable name
for (int i=0; i <= Pos-1; i++){
LongitSide[i]=ReadString.charAt(i);      //fill the array
Serial.println(LongitSide[i]);        //display raw longitude data in Serial Monitor
}
//convert to degrees Google can use
float LongitAsFloat = atof (Longit);    //atof converts the char array to a float type
float LongInDeg;
if(LongitSide[0]==char(69)) {        //char(69) is decimal for the letter "E" in ascii chart
LongInDeg=ConvertData(LongitAsFloat);   //call the conversion funcion (see below
}
if(LongitSide[0]==char(87)) {         //char(87) is decimal for the letter "W" in ascii chart
LongInDeg=-(ConvertData(LongitAsFloat)); //call the conversion funcion (see below
}
Serial.println(LongInDeg,15);  //display value Google can use in Serial Monitor, set decimal point value high
//repeating with a different char array variable
//Get TimeStamp - GMT
ReadString.remove(0, Pos+1);
Pos=ReadString.indexOf(',');
char TimeStamp[Pos];          //declare different variable name
for (int i=0; i <= Pos-1; i++){
TimeStamp[i]=ReadString.charAt(i);         //fill the array
}
Serial.print(TimeStamp);   //display raw longitude data in Serial Monitor, GMT
Serial.println("");
}
}

//Conversion function
float ConvertData(float RawDegrees)
{
float RawAsFloat = RawDegrees;
int firstdigits = ((int)RawAsFloat)/100; // Get the first digits by turning f into an integer, then doing an integer divide by 100;
float nexttwodigits = RawAsFloat - (float)(firstdigits*100);
float Converted = (float)(firstdigits + nexttwodigits/60.0);
return Converted;
}
1

Попробуйте это, которое может помочь вам

#include <SoftwareSerial.h>
#include <TinyGPS.h>

TinyGPS gps;
SoftwareSerial ss(3,4);static void smartdelay(unsigned long ms);
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);

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

void loop()
{
float flat, flon;

unsigned short sentences = 0, failed = 0;

gps.f_get_position(&flat, &flon);
Serial.print("LATITUDE: ");
print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 10, 6);
Serial.println(" ");
Serial.print("LONGITUDE: ");
print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 11, 6);
Serial.println(" ");

Serial.print("altitude: ");
print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 7, 2);
Serial.println(" ");
Serial.print("COURSE:");
print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
Serial.println("");

Serial.print("DIRECTION: ");
int d;
print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
d=gps.f_course();
Serial.println();
Serial.println();
smartdelay(1000);

}

static void smartdelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}

static void print_float(float val, float invalid, int len, int prec)
{
if (val == invalid)
{
while (len-- > 1)
Serial.print('*');
Serial.print(' ');
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(' ');
}
smartdelay(0);
}

static void print_int(unsigned long val, unsigned long invalid, int len)
{
char sz[32];
if (val == invalid)
strcpy(sz, "*******");
else
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
Serial.print(sz);
smartdelay(0);
}
static void print_str(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
Serial.print(i<slen ? str[i] : ' ');
smartdelay(0);
}
0
По вопросам рекламы [email protected]