4

在此处输入图像描述我正在尝试使用 Arduino uno 和以下代码解析传入的 GPGGA NMEA GPS 字符串。我想做的是我只使用 GPGGA NMEA 字符串来获取纬度、经度和高度的值。在下面的代码中,我进行了某些检查以检查传入的字符串是否为 GPGGA,然后存储数组中的其他字符串可以使用 strtok 函数进一步解析,并且可以轻松找出所有 3 个 GPS 坐标。

但我无法弄清楚如何只存储 GPGGA 字符串而不是进一步的字符串。我正在使用 for 循环,但它不起作用。

我没有尝试使用任何库。我遇到过这样的某些现有代码。

这是GPGGA字符串信息链接

我正在尝试具有以下功能 i)检查传入字符串是否为 GPGGA ii)如果是,则将以下字符串存储到 EOL 或最多 *(后跟数组的校验和)在数组中,数组长度是可变的(我无法找出解决方案)iii)然后解析存储的数组(完成,我用不同的数组尝试了这个)

 #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);
    }

编辑 1:考虑到 Joachim Pileborg,在代码中编辑 for 循环。

我正在添加一张图片来显示代码的未定义输出。

输入代码:

$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
4

5 回答 5

3

在快速查看有关 NMEA 0183 协议的链接文章后,我突然想到了:

<CR><LF>结束消息。

这意味着,您应该寻找该序列,而不是不加选择地从串行端口读取。如果找到,您应该终止字符串,并跳出循环。

此外,您可能希望从零初始化数据字符串,以便轻松查看其中是否有任何数据要打印(使用 eg strlen)。

于 2013-11-08T21:04:13.677 回答
0

每次读取字符串时使用“malloc”会产生巨大的计算开销。(并且没有看到相应的 free() 函数调用。没有它,在程序终止或系统内存不足之前,您永远无法取回该内存。)只需选择您将需要的最长字符串的大小,加上 10它,并声明你的字符串数组大小。设置一次就完成了。

有几个 C 函数用于从字符串中获取子字符串,使用 coma 的 strtok() 可能是开销最小的。

您使用的是嵌入式微控制器。保持小,保持开销。:)

于 2014-05-30T04:06:35.303 回答
0

提供此建议以支持您正在做的事情...

if()用以下内容替换循环中的 所有嵌套 s 是否有用:

编辑添加了全局字符串以将 myString 复制到一旦捕获

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
}

现在,from的返回值准确地mySerial.available()告诉您要读取多少字节,您可以读取整个缓冲区,并一次性测试有效性。

于 2013-11-08T21:26:27.277 回答
0

我有一个项目需要从同一个句子中提取相同的信息。我从日志文件中得到了这个

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')

结果是这样的: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
于 2014-02-28T01:38:51.817 回答
0

您可以使用 C 库libnmea中的一些函数。有函数通过逗号将句子拆分为值,然后解析它们。

于 2015-10-21T06:55:49.580 回答