Parsing code for GPS NMEA string

不羁的心 提交于 2019-12-22 08:58:02

问题


i am trying to parse the incoming GPGGA NMEA GPS string using Arduino uno and below code. What i am trying to do is that i am using only GPGGA NMEA string to get the values of Latitude, longitude and altitude.In my below code, i had put certain checks to check if incoming string is GPGGA or not, and then store the further string in a array which can be further parsed suing strtok function and all the 3 GPS coordinates can be easily find out.

But i am unable to figure out how to store only GPGGA string and not the further string.I am using a for loop but it isn't working.

I am not trying to use any library.I had came across certain existing codes like this.

Here is the GPGGA string information link

i am trying to have following functionlity i) Check if incoming string is GPGGA ii) If yes, then store the following string upto EOL or upto * (followed by checksum for the array) in a array, array length is variable(i am unable to find out solution for this) iii) Then parse the stored array(this is done, i tried this with a different array)

 #include <SoftwareSerial.h>

    SoftwareSerial mySerial(10,11);  // 10 RX / 11 TX

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

    void loop()
    {
    uint8_t x;
    char gpsdata[65];

    if((mySerial.available()))
    {
    char c = mySerial.read();
    if(c == '$')
      {char c1 = mySerial.read();
       if(c1 == 'G')
         {char c2 = mySerial.read();
          if(c2 == 'P')
            {char c3 = mySerial.read();
             if(c3 == 'G')
               {char c4 = mySerial.read();
                if(c4 == 'G')
                   {char c5 = mySerial.read();
                    if(c5 == 'A')
                       {for(x=0;x<65;x++)
                        { 
                        gpsdata[x]=mySerial.read();


    while (gpsdata[x] == '\r' || gpsdata[x] == '\n')
                    {
                    break;
                    }

                        }

                       }
                       else{
                          Serial.println("Not a GPGGA string");
                        }
                   }
               }

            }     

         }

      }

    }

    Serial.println(gpsdata);
    }

Edit 1: Considering Joachim Pileborg, editing the for loop in the code.

I am adding a pic to show the undefined output of the code.

Input for the code:

$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76
$GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A
$GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70
$GPGSV,3,2,11,02,39,223,19,13,28,070,17,26,23,252,,04,14,186,14*79
$GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76
$GPRMC,092750.000,A,5321.6802,N,00630.3372,W,0.02,31.66,280511,,,A*43
$GPGGA,092751.000,5321.6802,N,00630.3371,W,1,8,1.03,61.7,M,55.3,M,,*75
$GPGSA,A,3,10,07,05,02,29,04,08,13,,,,,1.72,1.03,1.38*0A
$GPGSV,3,1,11,10,63,137,17,07,61,098,15,05,59,290,20,08,54,157,30*70
$GPGSV,3,2,11,02,39,223,16,13,28,070,17,26,23,252,,04,14,186,15*77
$GPGSV,3,3,11,29,09,301,24,16,09,020,,36,,,*76
$GPRMC,092751.000,A,5321.6802,N,00630.3371,W,0.06,31.66,280511,,,A*45

回答1:


After a quick check of the linked article on the NMEA 0183 protocol, this jumped out at me:

<CR><LF> ends the message.

This means, that instead of just read indiscriminately from the serial port, you should be looking for that sequence. If found, you should terminate the string, and break out of the loop.

Also, you might want to zero-initialize the data string to begin with, to easily see if there actually is any data in it to print (using e.g. strlen).




回答2:


Offering this as a suggestion in support of what you are doing...

Would it not be useful to replace all of the nested if()s in your loop with something like:

EDIT added global string to copy myString into once captured

char globalString[100];//declare a global sufficiently large to hold you results


void loop() 
{
    int chars = mySerial.available();
    int i;
    char *myString;
    if (chars>0)
    {
        myString = calloc(chars+1, sizeof(char));
        for(i=0;i<chars;i++)
        {
            myString[i] = mySerial.read();
            //test for EOF
            if((myString[i] == '\n') ||(myString[i] == '\r'))
            {
                //pick this...
                myString[i]=0;//strip carriage - return line feed(or skip)
                //OR pick this... (one or the other. i.e.,I do not know the requirements for your string)
                if(i<chars)
                {
                    myString[i+1] = mySerial.read() //get remaining '\r' or '\n'
                    myString[i+2]=0;//add null term if necessary
                }

                break;
            }
        }
        if(strstr(myString, "GPGGA") == NULL)
          {
               Serial.println("Not a GPGGA string");   
               //EDIT
               strcpy(globalString, "");//if failed, do not want globalString populated
          }
          else
          {    //EDIT
               strcpy(globalString, myString);
          }

    }
    //free(myString) //somewhere when you are done with it
}

Now, the return value from mySerial.available() tells you exactly how many bytes to read, you can read the entire buffer, and test for validity all in one.




回答3:


Just add these code it will work. use pin 8 and 9 as tx and rx

Main.cgps.hgps.c




回答4:


Just add these code it will work. use pin 8 and 9 as tx and rx

  1. gps.h
  2. main.c
  3. gps.c



回答5:


I have a project that will need to pull the same information out of the same sentence. I got this out of a log file

import serial
import time
ser = serial.Serial(1)

ser.read(1)
read_val = ("nothing")

gpsfile="gpscord.dat"
l=0

megabuffer=''
def buffThis(s):
        global megabuffer
        megabuffer +=s
def buffLines():
        global megabuffer
        megalist=megabuffer.splitlines()
        megabuffer=megalist.pop()
        return megalist

def readcom():
        ser.write("ati")
        time.sleep(3)
        read_val = ser.read(size=500)
        lines=read_val.split('\n')
        for l in lines:
                if l.startswith("$GPGGA"):
                        if l[:len(l)-3].endswith("*"):
                                outfile=open('gps.dat','w')
                                outfile.write(l.rstrip())
                                outfile.close()

readcom()

while 1==1:
    readcom()

answer=raw_input('not looping , CTRL+C to abort')

The result is this: gps.dat

$GPGGA,225714.656,5021.0474,N,00412.4420,W,0,00,50.0,0.0,M,18.0,M,0.0,0000*5B



回答6:


Using "malloc" every single time you read a string is an enormous amount of computational overhead. (And didn't see the corresponding free() function call. Without that, you never get that memory back until program termination or system runs out of memory.) Just pick the size of the longest string you will ever need, add 10 to it, and declare that your string array size. Set once and done.

There are several C functions for getting substrings out of a string, strtok() using the coma is probably the least overhead.

You are on an embedded microcontroller. Keep it small, keep overhead down. :)




回答7:


You could use some functions from the C library libnmea. Theres functions to split a sentence into values by comma and then parse them.



来源:https://stackoverflow.com/questions/19868156/parsing-code-for-gps-nmea-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!