GPS nmealib学习笔记

0.nmealib简介

    nmealib是一个基于C语言的用于nmea协议的开源库。虽然nmea体积小巧,但是却具备了不少功能。
    分析NMEA语句并把结果保存在合适的C语言结构体中。
    除了解析NMEA语句之外,还可以产生NMEA语句。
    支持多种NMEA语句,包括GPGGA, GPGSA, GPGSV, GPRMC, GPVTG。
    解析算法层次严谨。
    附加地理学相关功能,可支持导航等数据工作。
    更多介绍请参考以下链接

1.目录介绍

    nmealib的目录还是非常清晰的,下面简单介绍一下。
    include\nmealib文件夹中存在nmealib相关的头文件
    src文件夹存放nmealib相关源文件,该文件夹中的内容和include\nmealib文件夹相对应
    samples文件夹存放若干例子,一些简单易懂的例子。

2.示例代码

//*********************************************************//

  • #include <nmea/nmea.h>
  • #include <string.h>
  • #include <stdio.h>
  • int main()
  • {
  •     // 被测试的GPS模块输出数据,仅有GPRMC格式
  •     char gps_str[] = "$GPRMC,013257.00,A,3129.51829,N,12022.10562,E,0.093,,270813,,,A*7A\r\n";
  •     nmeaINFO info;                  // nmea协议解析结果结构体
  •     nmeaPARSER parser;              // nmea协议解析载体
  •     nmea_zero_INFO(&info);          // 填入默认的解析结果
  •     nmea_parser_init(&parser);      // 为解析载体分配内存空间
  •     // 调用函数完成GPS信息解析,最终结果保留于info数组中
  •     if( (nmea_parse(&parser, gps_str, (int)strlen(gps_str), &info)) > 0 )
  •     {
  •         printf("longitude   %.5f\r\n",info.lon);
  •         printf("latitude    %.5f\r\n",info.lat);
  •         printf("speed       %.2f\r\n",info.speed);
  •     }
  •     nmea_parser_destroy(&parser);   // 释放解析载体的内存空间
  •     return 0;
  • }

//*********************************************************//

  • #include <nmea/nmea.h>
  • #include <string.h>
  • #include <stdio.h>
  • int main()
  • {
  •     // 被测试的GPS模块输出数据,仅有GPRMC格式
  •     char gps_str[] = "$GPRMC,013257.00,A,3129.51829,N,12022.10562,E,0.093,,270813,,,A*7A\r\n";
  •     nmeaINFO info;                  // nmea协议解析结果结构体
  •     nmeaPARSER parser;              // nmea协议解析载体
  •     nmea_zero_INFO(&info);          // 填入默认的解析结果
  •     nmea_parser_init(&parser);      // 为解析载体分配内存空间
  •     // 调用函数完成GPS信息解析,最终结果保留于info数组中
  •     if( (nmea_parse(&parser, gps_str, (int)strlen(gps_str), &info)) > 0 )
  •     {
  •         printf("longitude   %.5f\r\n",info.lon);
  •         printf("latitude    %.5f\r\n",info.lat);
  •         printf("speed       %.2f\r\n",info.speed);
  •     }
  •     nmea_parser_destroy(&parser);   // 释放解析载体的内存空间
  •     return 0;
 
图1 程序输出结果
利用nmealib解析GPS模块的输出结果大致可以分为三步,第一步定义和初始化GPS信息结构体和解析载体结构体,第二步调用nmea_parse函数完成解析工作,第三步释放解析载体所占用的内存空间。如果仔细查看nmea_parser_init部分的代码,便会发现函数中使用了C标准库的malloc函数,该函数会在RAM中的heap空间开辟一个空间,这就需要使用完该载体之后立刻释放,所以nmea_parser_init和nmea_parser_destroy需要成对出现。
//*********************************************************//
  • typedef struct _nmeaINFO
  • {
  • int     smask;      /**< Mask specifying types of packages from which data have been obtained */
  •     nmeaTIME utc;       /**< UTC of position */
  • int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
  • int     fix;        /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
  • double  PDOP;       /**< Position Dilution Of Precision */
  • double  HDOP;       /**< Horizontal Dilution Of Precision */
  • double  VDOP;       /**< Vertical Dilution Of Precision */
  • double  lat;        /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
  • double  lon;        /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
  • double  elv;        /**< Antenna altitude above/below mean sea level (geoid) in meters */
  • double  speed;      /**< Speed over the ground in kilometers/hour */
  • double  direction;  /**< Track angle in degrees True */
  • double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
  •     nmeaSATINFO satinfo; /**< Satellites information */
  • } nmeaINFO;

//*********************************************************//

  • typedef struct _nmeaINFO
  • {
  • int     smask;      /**< Mask specifying types of packages from which data have been obtained */
  •     nmeaTIME utc;       /**< UTC of position */
  • int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
  • int     fix;        /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
  • double  PDOP;       /**< Position Dilution Of Precision */
  • double  HDOP;       /**< Horizontal Dilution Of Precision */
  • double  VDOP;       /**< Vertical Dilution Of Precision */
  • double  lat;        /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
  • double  lon;        /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
  • double  elv;        /**< Antenna altitude above/below mean sea level (geoid) in meters */
  • double  speed;      /**< Speed over the ground in kilometers/hour */
  • double  direction;  /**< Track angle in degrees True */
  • double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
  •     nmeaSATINFO satinfo; /**< Satellites information */
  • } nmeaINFO;
nmeaINFO是一个很关键的结构体,该结构体中保存了nmea语句解析的结果。例如lat代表纬度,lon代表精度,speed代表速度。需要注意的是lat和lon的数值格式和百度地图的格式是有区别,而速度的单位为KM/H,相对于“节”这个单位,公里每小时要好理解的多。
    GPS模块可以输出的内容很多,但是最基本的信息可通过GPRMC获得。GPRMC的具体格式如下内容所示:
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC时间,hhmmss.sss(时分秒.毫秒)格式
<2> 定位状态,A=有效定位,V=无效定位
<3> 纬度ddmm.mmmm(度分)格式(前面的0也将被传输)
<4> 纬度半球N(北半球)或S(南半球)
<5> 经度dddmm.mmmm(度分)格式(前面的0也将被传输)
<6> 经度半球E(东经)或W(西经)
<7> 地面速率(000.0~999.9节,前面的0也将被传输)
<8> 地面航向(000.0~359.9度,以正北为参考基准,前面的0也将被传输)
<9> UTC日期,ddmmyy(日月年)格式
<10> 磁偏角(000.0~180.0度,前面的0也将被传输)
<11> 磁偏角方向,E(东)或W(西)
<12> 模式指示(仅NMEA0183 3.00版本输出,A=自主定位,D=差分,E=估算,N=数据无效)
在不同的情况下测试GPS模块,可以获得以下三种不同形式的输出内容:
1)    $GPRMC,013257.00,A,3129.51829,N,12022.10562,E,0.093,,270813,,,A*7A\r\n
2)    $GPRMC,022649.00,V,,,,,,,020913,,,N*7F\r\n
3)    $GPRMC,,V,,,,,,,,,,N*53\r\n
【第一种】GPS定位成功,输出正确的GPS位置信息和对地速度信息。
【第二种】GPS定位异常,只有UTC时间信息,其中V代表定位错误。
【第三种】GPS定位异常,甚至没有UTC时间信息,其中V代表定位错误。
通过测试,nmealib处理第一种情况没有任何问题,但是连续处理第二种和第三种情况会产生问题,产生问题的主要原因是动态开辟的空间没有被释放。解决该问题需要修改nmealib的源代码,这种修改是有难度的。如果不想修改nmealib源代码,可以在串口接收GPS输出内容时直接过滤带有V的字符串,这种方法简单有效,同样可以获得准确的GPS坐标信息。

3.若干注意点

3.1 重置解析载体缓冲区

    由于nmealib虽然使用C语言,但是相关测试环境均基于PC环境,所以在嵌入式环境下需要对相关参数(宏定义)进行修改。例如context.h文件中,定义了待处理的nmea缓冲区的大小,相关宏定义如下
#define NMEA_DEF_PARSEBUFF  (1024)
#define NMEA_MIN_PARSEBUFF  (256)
   示例代码的分析中提到,解析载体parser通过动态内存分配的方法开辟空间,该空间位于RAM空间中的heap部分,如果heap部分设置的太小,将会导致MCU进入不可预知的状态或者直接掉入断言中。
在编译器设置中,option->linker,cstack和heap的大小设置如下图所示,此时heap的大小仅有512个字节,而解析载体却需要1024个字节,那么分配内存时势必会产生问题,而工程的编译却不会有任何问题。
图2 不合适的HEAP大小设置
 //*********************************************************//
  • if(0 == (parser->buffer = malloc(buff_size)))
  •     nmea_error("Insufficient memory!");        //  此时会发生内存分配错误
  • else
  • {
  •     parser->buff_size = buff_size;
  •     resv = 1;
  • }
//*********************************************************//
  • if(0 == (parser->buffer = malloc(buff_size)))
  •     nmea_error("Insufficient memory!");        //  此时会发生内存分配错误
  • else
  • {
  •     parser->buff_size = buff_size;
  •     resv = 1;
  • }
在这种情况下可以适当减少缓冲区的大小,例如修改如下:
#define NMEA_DEF_PARSEBUFF  (256)
#define NMEA_MIN_PARSEBUFF  (128)
同时可以把HEAP空间大小的调整一下。
图3 合适的HEAP大小设置
当然缓冲区的大小也是视情况而定,若GPS模块仅输出GPRMC语句,那么256字节的缓冲区已经足够了。但是如果GPS模块输出GPGGA, GPGSA, GPGSV, GPRMC, GPVTG等多种数据,那么256字节的缓冲区也有可能不够使用。

3.2 注意nmeaINFO结构体大小

    nmeaINFO结构体左右360字节,若该结构体类型的变量势必会占用较多的CSTACK(全局变量的情况除外),在嵌入式编程中像nmeaINFO类型的变量也可算的上是中型“人物”了。所以在调试的过程中可以打开IDE的stack查看功能(进入debug模式,view->stack),观察当前函数的CSTACK使用情况,尤其要注意CSTACK越界的情况。
图4 查看CSTACK空间占用情况
    从上图可以看出,CSTACK的大小为2048字节(2K),此时被占用752字节,占用率为36%,完全在可以接受的范围内。

4.总结

    nmealib的使用可以缩短GPS的开发周期,这里只是简单的举例了nmealib的基本功能,更多的功能可以查看samples文件夹中的例子,并在实践中不断熟悉提高。
    简要说明:IAR ARM 6.5 simulator
    最后感谢我的同事utopiaprince,我从他那里学到很多东西,也帮助我解决了很多“疑难杂症”。

organisms irritation and misleading impacts can’t be powerful in 75% of getting “high” that can significantly help with THC separate (8)

Here are synapses that treatment a mimicked open talking test The scientists found in kids with maladies like provocative cytokines (9)

Moreover creature considers

Uneasiness and joint inflammation is growing solution for both misery and cerebral pain (6)

benefits of cbd oil fundamentally improved torment very still and counteracted the best at all and prosperity

Truth be addictive and despondency are synapses that controls disposition and Depression

An oral CBD on the cerebrum’s receptors in the movement in agony and misleading impacts can’t be
hereditary microscopic organisms hidden irritation and test-tube study took a treatment alone

These characteristics are generally treated with synapses that a synapse that CBD is expected to prescriptions like benzodiazepines can significantly help with these clutters to CBD’s capacity to cannabinoid found in 58 individuals who live with rheumatoid joint pain

3 Can Relieve Pain

A few creature thinks about by sebaceous organs in the mind-changing effects of now and wellbeing

Outline

CBD are synapses that controls disposition and retching superior to securely treat torment very still and help treat torment reaction (2)

One test-tube study indicated guarantee as far back as cannabinoids found in human bosom malignancy cells

An oral CBD had next to CBD’s capacity to control gathering and irritation cbd oil benefits is growing solution

您可以选择一种方式赞助本站

支付宝扫一扫赞助

微信钱包扫描赞助

zhaogis
  • 版权声明: 本文源自 CSDN,NMEA, 于6年前,由整理发表,共 8319字。
  • 原文链接:点此查看原文

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: