GPS-nmealib学习
生活随笔
收集整理的這篇文章主要介紹了
GPS-nmealib学习
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
GPS nmealib學習筆記
標簽: GPSnmealibCSTACKHEAP 2013-10-17 11:12 4269人閱讀 評論(7) 收藏 舉報
本文章已收錄于:
分類: 嵌入式ARM(24) 作者同類文章X nmealib簡介 目錄介紹 示例代碼 若干注意點 1 重置解析載體緩沖區 2 注意nmeaINFO結構體大小 總結
? ? 分析NMEA語句并把結果保存在合適的C語言結構體中。
? ? 除了解析NMEA語句之外,還可以產生NMEA語句。
? ? 支持多種NMEA語句,包括GPGGA, GPGSA, GPGSV, GPRMC, GPVTG。 ? ? 解析算法層次嚴謹。
? ? 附加地理學相關功能,可支持導航等數據工作。
? ? 更多介紹請參考以下鏈接
? ? include\nmealib文件夾中存在nmealib相關的頭文件
? ? src文件夾存放nmealib相關源文件,該文件夾中的內容和include\nmealib文件夾相對應 ? ? samples文件夾存放若干例子,一些簡單易懂的例子。
#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需要成對出現。
[cpp] view plaincopyprint?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坐標信息。
#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?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字節的緩沖區也有可能不夠使用。
圖4 查看CSTACK空間占用情況 ? ? 從上圖可以看出,CSTACK的大小為2048字節(2K),此時被占用752字節,占用率為36%,完全在可以接受的范圍內。
? ? 示例工程鏈接:【bitbucket】 與50位技術專家面對面20年技術見證,附贈技術全景圖
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
目錄(?)[+]
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 程序輸出結果 利用nmealib解析GPS模塊的輸出結果大致可以分為三步,第一步定義和初始化GPS信息結構體和解析載體結構體,第二步調用nmea_parse函數完成解析工作,第三步釋放解析載體所占用的內存空間。如果仔細查看nmea_parser_init部分的代碼,便會發現函數中使用了C標準庫的malloc函數,該函數會在RAM中的heap空間開辟一個空間,這就需要使用完該載體之后立刻釋放,所以nmea_parser_init和nmea_parser_destroy需要成對出現。
[cpp] view plaincopyprint?
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?
在這種情況下可以適當減少緩沖區的大小,例如修改如下:
#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文件夾中的例子,并在實踐中不斷熟悉提高。? ? 示例工程鏈接:【bitbucket】 與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的GPS-nmealib学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: __attribute__函数的作用
- 下一篇: 单片机自动调光C语言,51单片机触控调光