程序員Tim 提供了一個(gè)非常完善的NMEA解碼庫,直接使用該解碼庫,可以避免重復(fù)發(fā)明輪子的工作。在野火提供的GPS模塊資料的“NMEA0183解碼庫源碼”文件夾中也包含了該解碼庫的源碼,野火提供的STM32程序就是使用該庫來解碼NMEA語句的。
該解碼庫目前最新為0.5.3版本,它使用純C語言編寫,支持windows、winCE 、UNIX平臺,支持解析GPGGA,GPGSA,GPGSV,GPRMC,GPVTG這五種語句(這五種語句已經(jīng)提供足夠多的GPS信息),解析得的GPS數(shù)據(jù)信息以結(jié)構(gòu)體存儲,附加了地理學(xué)相關(guān)功能,可支持導(dǎo)航等數(shù)據(jù)工作,除了解析NMEA語句,它還可以根據(jù)隨機(jī)數(shù)產(chǎn)生NMEA語句,方便模擬。
0.nmealib簡介
nmealib是一個(gè)基于C語言的用于nmea協(xié)議的開源庫。雖然nmea體積小巧,但是卻具備了不少功能。
分析NMEA語句并把結(jié)果保存在合適的C語言結(jié)構(gòu)體中。
除了解析NMEA語句之外,還可以產(chǎn)生NMEA語句。
支持多種NMEA語句,包括GPGGA, GPGSA, GPGSV, GPRMC, GPVTG。
解析算法層次嚴(yán)謹(jǐn)。
附加地理學(xué)相關(guān)功能,可支持導(dǎo)航等數(shù)據(jù)工作。
1.目錄介紹
nmealib的目錄還是非常清晰的,下面簡單介紹一下。
include\nmealib文件夾中存在nmealib相關(guān)的頭文件
src文件夾存放nmealib相關(guān)源文件,該文件夾中的內(nèi)容和include\nmealib文件夾相對應(yīng)
samples文件夾存放若干例子,一些簡單易懂的例子。
2.示例代碼
[cpp]view plaincopy
#include
#include
#include
intmain()
{
//被測試的GPS模塊輸出數(shù)據(jù),僅有GPRMC格式
chargps_str[]="$GPRMC,013257.00,A,3129.51829,N,12022.10562,E,0.093,,270813,,,A*7A\r\n";
nmeaINFOinfo;//nmea協(xié)議解析結(jié)果結(jié)構(gòu)體
nmeaPARSERparser;//nmea協(xié)議解析載體
nmea_zero_INFO(&info);//填入默認(rèn)的解析結(jié)果
nmea_parser_init(&parser);//為解析載體分配內(nèi)存空間
//調(diào)用函數(shù)完成GPS信息解析,最終結(jié)果保留于info數(shù)組中
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);//釋放解析載體的內(nèi)存空間
return0;
}
圖1 程序輸出結(jié)果
利用nmealib解析GPS模塊的輸出結(jié)果大致可以分為三步,第一步定義和初始化GPS信息結(jié)構(gòu)體和解析載體結(jié)構(gòu)體,第二步調(diào)用nmea_parse函數(shù)完成解析工作,第三步釋放解析載體所占用的內(nèi)存空間。如果仔細(xì)查看nmea_parser_init部分的代碼,便會發(fā)現(xiàn)函數(shù)中使用了C標(biāo)準(zhǔn)庫的malloc函數(shù),該函數(shù)會在RAM中的heap空間開辟一個(gè)空間,這就需要使用完該載體之后立刻釋放,所以nmea_parser_init和nmea_parser_destroy需要成對出現(xiàn)。
[cpp]view plaincopy
typedefstruct_nmeaINFO
{
intsmask;/**
nmeaTIMEutc;/**
intsig;/**
intfix;/**
doublePDOP;/**
doubleHDOP;/**
doubleVDOP;/**
doublelat;/**
doublelon;/**
doubleelv;/**
doublespeed;/**
doubledirection;/**
doubledeclination;/**
nmeaSATINFOsatinfo;/**
}nmeaINFO;
nmeaINFO是一個(gè)很關(guān)鍵的結(jié)構(gòu)體,該結(jié)構(gòu)體中保存了nmea語句解析的結(jié)果。例如lat代表緯度,lon代表精度,speed代表速度。需要注意的是lat和lon的數(shù)值格式和百度地圖的格式是有區(qū)別,而速度的單位為KM/H,相對于“節(jié)”這個(gè)單位,公里每小時(shí)要好理解的多。
GPS模塊可以輸出的內(nèi)容很多,但是最基本的信息可通過GPRMC獲得。GPRMC的具體格式如下內(nèi)容所示:
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC時(shí)間,hhmmss.sss(時(shí)分秒.毫秒)格式
<2> 定位狀態(tài),A=有效定位,V=無效定位
<3> 緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸)
<4> 緯度半球N(北半球)或S(南半球)
<5> 經(jīng)度dddmm.mmmm(度分)格式(前面的0也將被傳輸)
<6> 經(jīng)度半球E(東經(jīng))或W(西經(jīng))
<7> 地面速率(000.0~999.9節(jié),前面的0也將被傳輸)
<8> 地面航向(000.0~359.9度,以正北為參考基準(zhǔn),前面的0也將被傳輸)
<9> UTC日期,ddmmyy(日月年)格式
<10> 磁偏角(000.0~180.0度,前面的0也將被傳輸)
<11> 磁偏角方向,E(東)或W(西)
<12> 模式指示(僅NMEA0183 3.00版本輸出,A=自主定位,D=差分,E=估算,N=數(shù)據(jù)無效)
在不同的情況下測試GPS模塊,可以獲得以下三種不同形式的輸出內(nèi)容:
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時(shí)間信息,其中V代表定位錯(cuò)誤。
【第三種】GPS定位異常,甚至沒有UTC時(shí)間信息,其中V代表定位錯(cuò)誤。
通過測試,nmealib處理第一種情況沒有任何問題,但是連續(xù)處理第二種和第三種情況會產(chǎn)生問題,產(chǎn)生問題的主要原因是動態(tài)開辟的空間沒有被釋放。解決該問題需要修改nmealib的源代碼。如果不想修改nmealib源代碼,可以在串口接收GPS輸出內(nèi)容時(shí)直接過濾帶有V的字符串,這種方法簡單有效,同樣可以獲得準(zhǔn)確的GPS坐標(biāo)信息。
3.若干注意點(diǎn)
3.1 重置解析載體緩沖區(qū)
由于nmealib雖然使用C語言,但是相關(guān)測試環(huán)境均基于PC環(huán)境,所以在嵌入式環(huán)境下需要對相關(guān)參數(shù)(宏定義)進(jìn)行修改。例如context.h文件中,定義了待處理的nmea緩沖區(qū)的大小,相關(guān)宏定義如下
#define NMEA_DEF_PARSEBUFF (1024)
#define NMEA_MIN_PARSEBUFF (256)
示例代碼的分析中提到,解析載體parser通過動態(tài)內(nèi)存分配的方法開辟空間,該空間位于RAM空間中的heap部分,如果heap部分設(shè)置的太小,將會導(dǎo)致MCU進(jìn)入不可預(yù)知的狀態(tài)或者直接掉入斷言中。
在編譯器設(shè)置中,option->linker,cstack和heap的大小設(shè)置如下圖所示,此時(shí)heap的大小僅有512個(gè)字節(jié),而解析載體卻需要1024個(gè)字節(jié),那么分配內(nèi)存時(shí)勢必會產(chǎn)生問題,而工程的編譯卻不會有任何問題。
圖2 不合適的HEAP大小設(shè)置
[cpp]view plaincopy
if(0==(parser->buffer=malloc(buff_size)))
nmea_error("Insufficientmemory!");//此時(shí)會發(fā)生內(nèi)存分配錯(cuò)誤
else
{
parser->buff_size=buff_size;
resv=1;
}
在這種情況下可以適當(dāng)減少緩沖區(qū)的大小,例如修改如下:
#define NMEA_DEF_PARSEBUFF (256)
#define NMEA_MIN_PARSEBUFF (128)
同時(shí)可以把HEAP空間大小的調(diào)整一下。
圖3 合適的HEAP大小設(shè)置
當(dāng)然緩沖區(qū)的大小也是視情況而定,若GPS模塊僅輸出GPRMC語句,那么256字節(jié)的緩沖區(qū)已經(jīng)足夠了。但是如果GPS模塊輸出GPGGA, GPGSA, GPGSV, GPRMC, GPVTG等多種數(shù)據(jù),那么256字節(jié)的緩沖區(qū)也有可能不夠使用。
3.2 注意nmeaINFO結(jié)構(gòu)體大小
nmeaINFO結(jié)構(gòu)體左右360字節(jié),若該結(jié)構(gòu)體類型的變量勢必會占用較多的CSTACK(全局變量的情況除外),在嵌入式編程中像nmeaINFO類型的變量也可算的上是中型“人物”了。所以在調(diào)試的過程中可以打開IDE的stack查看功能(進(jìn)入debug模式,view->stack),觀察當(dāng)前函數(shù)的CSTACK使用情況,尤其要注意CSTACK越界的情況。
圖4 查看CSTACK空間占用情況
從上圖可以看出,CSTACK的大小為2048字節(jié)(2K),此時(shí)被占用752字節(jié),占用率為36%,完全在可以接受的范圍內(nèi)。
4.總結(jié)
nmealib的使用可以縮短GPS的開發(fā)周期,這里只是簡單的舉例了nmealib的基本功能,更多的功能可以查看samples文件夾中的例子,并在實(shí)踐中不斷熟悉提高。
-
gps
+關(guān)注
關(guān)注
22文章
2896瀏覽量
166257 -
C語言
+關(guān)注
關(guān)注
180文章
7605瀏覽量
136887
原文標(biāo)題:GPS nmealib學(xué)習(xí)筆記
文章出處:【微信號:gh_dae0718828df,微信公眾號:gh_dae0718828df】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論