from:http://blog.csdn.net/xukai871105/article/details/12834421

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.示例代码

[cpp] view plaincopyprint?
  1. #include <nmea/nmea.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. int main()
  5. {
  6. // 被测试的GPS模块输出数据,仅有GPRMC格式
  7. char gps_str[] = "$GPRMC,013257.00,A,3129.51829,N,12022.10562,E,0.093,,270813,,,A*7A\r\n";
  8. nmeaINFO info;                  // nmea协议解析结果结构体
  9. nmeaPARSER parser;              // nmea协议解析载体
  10. nmea_zero_INFO(&info);          // 填入默认的解析结果
  11. nmea_parser_init(&parser);      // 为解析载体分配内存空间
  12. // 调用函数完成GPS信息解析,最终结果保留于info数组中
  13. if( (nmea_parse(&parser, gps_str, (int)strlen(gps_str), &info)) > 0 )
  14. {
  15. printf("longitude   %.5f\r\n",info.lon);
  16. printf("latitude    %.5f\r\n",info.lat);
  17. printf("speed       %.2f\r\n",info.speed);
  18. }
  19. nmea_parser_destroy(&parser);   // 释放解析载体的内存空间
  20. return 0;
  21. }
#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需要成对出现。
[cpp] view plaincopyprint?
  1. typedef struct _nmeaINFO
  2. {
  3. int     smask;      /**< Mask specifying types of packages from which data have been obtained */
  4. nmeaTIME utc;       /**< UTC of position */
  5. int     sig;        /**< GPS quality indicator (0 = Invalid; 1 = Fix; 2 = Differential, 3 = Sensitive) */
  6. int     fix;        /**< Operating mode, used for navigation (1 = Fix not available; 2 = 2D; 3 = 3D) */
  7. double  PDOP;       /**< Position Dilution Of Precision */
  8. double  HDOP;       /**< Horizontal Dilution Of Precision */
  9. double  VDOP;       /**< Vertical Dilution Of Precision */
  10. double  lat;        /**< Latitude in NDEG - +/-[degree][min].[sec/60] */
  11. double  lon;        /**< Longitude in NDEG - +/-[degree][min].[sec/60] */
  12. double  elv;        /**< Antenna altitude above/below mean sea level (geoid) in meters */
  13. double  speed;      /**< Speed over the ground in kilometers/hour */
  14. double  direction;  /**< Track angle in degrees True */
  15. double  declination; /**< Magnetic variation degrees (Easterly var. subtracts from true course) */
  16. nmeaSATINFO satinfo; /**< Satellites information */
  17. } 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大小设置
[cpp] view plaincopyprint?
  1. if(0 == (parser->buffer = malloc(buff_size)))
  2. nmea_error("Insufficient memory!");        //  此时会发生内存分配错误
  3. else
  4. {
  5. parser->buff_size = buff_size;
  6. resv = 1;
  7. }
    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,我从他那里学到很多东西,也帮助我解决了很多“疑难杂症”。

GPS nmealib学习笔记 .相关推荐

  1. GPS nmealib学习笔记

    GPS nmealib学习笔记 标签: GPSnmealibCSTACKHEAP 2013-10-17 11:12 4274人阅读 评论(7) 收藏 举报  分类: 嵌入式ARM(24)  版权声明: ...

  2. nmealib linux编译,GPS nmealib学习笔记

    0.nmealib简介nmealib是一个基于C语言的用于nmea协议的开源库.虽然nmea体积小巧,但是却具备了不少功能.分析NMEA语句并把结果保存在合适的C语言结构体中.除了解析NMEA语句之外 ...

  3. c语言 GPS nmealib学习笔记

    0.nmealib简介nmealib是一个基于C语言的用于nmea协议的开源库.虽然nmea体积小巧,但是却具备了不少功能.分析NMEA语句并把结果保存在合适的C语言结构体中.除了解析NMEA语句之外 ...

  4. Arduino模块学习笔记(一)—GPS模块的使用

    Arduino模块学习笔记(一)--GSP模块的使用 文章目录 Arduino模块学习笔记(一)--GSP模块的使用 所需组件 一.模块使用介绍 1.GPS模块(在室内时,一般获取不到位置信息) 2. ...

  5. GTSAM Tutorial学习笔记

    GTSAM Tutorial学习笔记 GTSAM Tutorial学习笔记 1. 基本原理 2. Demo代码 3. LIO-SAM中部分代码分析 3.1 预积分因子图 3.2 关键帧因子图 GTSA ...

  6. Android学习笔记:短信控制手机之“短信开启定位”

    2019独角兽企业重金招聘Python工程师标准>>> 首先,我必须说,我是菜鸟.接触Android不就久,在这里记下,第一想让自己有更加深刻的印象,第二也想和大家一起分享.如果出现 ...

  7. 视觉SLAM十四讲学习笔记---前三讲学习笔记总结之SLAM的作用、变换和位姿表示

    经过半年学习SLAM相关知识,对SLAM系统有了一些新的认识,故回看以前的学习记录,做总结和校正. 前三讲学习笔记如下: 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 视觉S ...

  8. 视觉SLAM十四讲学习笔记-第二讲-初识SLAM

    专栏系列文章如下: 视觉SLAM十四讲学习笔记-第一讲_goldqiu的博客-CSDN博客 "定位"和"建图",可以看成感知的"内外之分". ...

  9. 英语学习笔记2019-12-06

    英语学习笔记2019-12-06 At the beginning of this term, we talked about the talent show which would be carri ...

最新文章

  1. mlcc激光雷达与相机外参标定初体验
  2. 深度残差收缩网络:借助注意力机制实现特征的软阈值化
  3. 彻底理解乐观锁和悲观锁的区别
  4. 运行 命令 linux,Linux基本命令运行
  5. html文件设置成mac屏保,Mac怎么设置屏幕保护?如何设置Mac屏幕保护程序?
  6. java jdk 序列化_JDK 11:Java序列化的终结开始了吗?
  7. FPGA学无止境(目录篇)
  8. 会议通知|第3届全国高校大数据教学研讨会
  9. 软件dfmea_最全最专业解析!详解DFMEA新版六步法~fmea软件
  10. 知网查重原理以及降重举例
  11. mysql 索引失效的7种情况
  12. SpringBoot基础-refresh方法解析
  13. 搜索引擎和知识图谱那些事
  14. android 手表解决方案,智能手表解决方案
  15. 通过Mixamo生成人物动画并导入Unity实现资源可用的方法
  16. 基于51单片机智能手机锂电池充电器设计
  17. 教育:构造主义和机能主义
  18. Apollo 3.5硬件和系统安装指南
  19. pdf怎么加水印,pdf加水印简单方法
  20. 网页3D编辑器Stone教程:如何实现路径动画

热门文章

  1. 电脑麦克风没声音怎么办?3个方法快速解决
  2. Python — 词汇表(一)
  3. android开发股票数据接口,股票数据接口-股票数据接口api
  4. unity技美27——优化项目内美术3D,2D等资源,详解unity打包体的潜规则与案例
  5. Houdini 导出.ass文件
  6. Parameter index out of range (1 > number of parameters, which is 0)
  7. php投影,ppt投影怎么显示备注
  8. noip模拟赛 斐波那契
  9. 语音控制小车运动APP(基于百度语音识别)
  10. 在受控主机上创建文件或目录