2016年2月17日 星期三

GPS封裝格式與$GPRMC解析

NMEA封裝格式
是由美國國家海洋電子協會(National Marine Electronics AssociationNMEA)制定的GPS協定標準規格,其制定了GPS 上的所有資料格式與資料傳輸的通訊協定,其中還訂下了所有航海電子儀器用的通訊標準,而這些介面協定採用ASCII碼輸出方式,協議定義了若干代表不同含義的語句,語句格式如下所示。
符號(ASCII
定義
HEX
DEX
說明
$
起始位
24
36
語句起始位
  aaccc
地址域
  

前兩位為位識別符,後三位為語句名
“,”
域分隔符號
2C
44
域分隔符號
ddd……ddd
資料塊


發送的資料內容
“*”
校驗和符
2A
42
星號分隔符號,表明後面的兩位數是校驗和
Hh
校驗和


校驗和
/
終止符
0D,0A
13,10
回車,換行
NMEA0183介面協定定義的主要語句有:GGAGLLGSAGSVMSSRMCVTGZDA等。表13-2介紹這些語句所包含的具體內容。

13-2 常見NMEA-0183語句內容[38]

語句
語句內容
GGA
UTC時間、緯度值、經度值、定位狀態(無效、單點定位、差分)、觀測的GPS衛星個數、HDOP值、GPS橢球高、天線架設高度、差分數據齡期、差分基準站編號、校驗和
GLL
UTC時間、緯度值、經度值、定位狀態(無效、單點定位、差分)、校驗和
GSA
定位模式(M-手動,強制二維或三維定位;A-自動,自動二維或三維定位)、定位中使用的衛星ID號、PDOP值、HDOP值、VDOP
GSV
視野中的GPS衛星顆數、PRN編號、衛星仰角、距正北的角度(方位角)、信噪比
MSS
信標台的信號強度、信噪比、信標頻率、串列傳輸速率、通道號
RMC
UTC時間、定位狀態(A-可用,V-可能有錯誤)、緯度值、經度值、對地速度、日期等
VTG
對地速度等
ZDA
UTC時間、年、月、日、當地時區、時區的分鐘值等


1.GPSGlobal Positioning System):全球衛星定位系統
美國的24顆衛星不停地給地面發GPS信號,只要有一台GPS接收設備,就能定位出你所在的位置高度和速度了,它與電子地圖的結合就是通常所說的GPS功能

三、gps資料格式

1.從串列埠中讀出的是文本資料,每次讀出一行,一般情況下,一秒種能收到多行資料

2.有效資料以$GP開頭,分為$GPGGA$GPGSA$GPGSV$GPRMC…


nmea資料如下: 
$GPGGA,121252.000,3937.3032,N,11611.6046,E,1,05,2.0,45.9,M,-5.7,M,,0000*77
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54
$GPVTG,359.95,T,,M,15.15,N,28.0,K,A*04
$GPGGA,121253.000,3937.3090,N,11611.6057,E,1,06,1.2,44.6,M,-5.7,M,,0000*72
$GPGSA,A,3,14,15,05,22,18,26,,,,,,,2.1,1.2,1.7*3D
$GPGSV,3,3,10,29,07,074,,30,07,163,28*7D

注:NMEA0183格式以“$”開始,主要語句有GPGGA,GPRMC,GPGSA,GPGSV,GPVTGGPZDA



2.1 GPS DOP and Active SatellitesGSA)當前衛星資訊

$GPGSA,<1>,<2>,<3>,<4>,,,,,<12>,<13>,<14>, <15>,<16>,<17>,<18>

<1>模式 :M = 手動, A = 自動。 
<2>
定位型式 1 = 未定位, 2 = 二維定位, 3 = 三維定位。 
<3>
<14>PRN 數字:01  32 表天空使用中的衛星編號,最多可接收12顆衛星資訊

      (上面藍色處,總共有12)。 
<15> PDOP
位置精度因數(0.5~99.9) 
<16> HDOP
水準精度因數(0.5~99.9) 
<17> VDOP
垂直精度因數(0.5~99.9) 
<18> Checksum.(
檢查位).


2.2
 GPS Satellites in ViewGSV)可見衛星資訊 
$GPGSV, <1>,<2>,<3>,<4>,<5>,<6>,<7>,?<4>,<5>,<6>,<7>,<8>

<1> GSV語句的總數 
<2> 
本句GSV的編號 
<3> 
可見衛星的總數,00  12。 
<4> 
衛星編號, 01  32。 
<5>
衛星仰角, 00  90 度。 
<6>
衛星方位角, 000  359 度。實際值。 
<7>
訊號雜訊比(C/No), 00  99 dB;無表未接收到訊號。 
<8>Checksum.(
檢查位).

<4>,<5>,<6>,<7>項個別衛星會重複出現,每行最多有四顆衛星。其餘衛星資訊會于次一行出現,若未使用,這些欄位會空白。



2.3Global Positioning System Fix DataGGAGPS定位資訊

$GPGGA,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,M,<10>,M,<11>,<12>*hh

<1> UTC時間,hhmmss(時分秒)格式 
<2> 
緯度ddmm.mmmm(度分)格式(前面的0也將被傳輸) 
<3> 
緯度半球N(北半球)或S(南半球) 
<4> 
經度dddmm.mmmm(度分)格式(前面的0也將被傳輸) 
<5> 
經度半球E(東經)或W(西經) 
<6> GPS
狀態:0=未定位,1=非差分定位,2=差分定位,6=正在估算 
<7> 
正在使用解算位置的衛星數量(00~12)(前面的0也將被傳輸) 
<8> HDOP
水準精度因數(0.5~99.9) 
<9> 
海拔高度(-9999.9~99999.9) 
<10> 
地球橢球面相對大地水準面的高度 
<11> 
差分時間(從最近一次接收到差分信號開始的秒數,如果不是差分定位將為空) 
<12> 
差分站ID0000~1023(前面的0也將被傳輸,如果不是差分定位將為空)


2.4
Recommended Minimum Specific GPS/TRANSIT DataRMC)推薦定位資訊

$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh

<1> UTC時間,hhmmss(時分秒)格式 
<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=資料無效)



2.5 Track Made Good and Ground SpeedVTG)地面速度資訊 
$GPVTG,<1>,T,<2>,M,<3>,N,<4>,K,<5>*hh
<1> 
以真北為參考基準的地面航向(000~359度,前面的0也將被傳輸) 
<2> 
以磁北為參考基準的地面航向(000~359度,前面的0也將被傳輸) 
<3> 
地面速率(000.0~999.9節,前面的0也將被傳輸) 
<4> 
地面速率(0000.0~1851.8公里/小時,前面的0也將被傳輸) 
<5> 
模式指示(僅NMEA0183 3.00版本輸出,A=自主定位,D=差分,E=估算,N=資料無效)



2.6GPZDA日期和時間

$GPZDA,<1>,<2>, <3> , <4> , <5> , <6> *CC

<1> UTC時間,hhmmss(時分秒)格式 
<2> 

<3> 

<4> 

<5> 
本地時區小時便宜量 
<6>
本地時區分鐘便宜量



3.0 程式設計


利用strstr函數和sscanf函數解析GPS資料。

GPS輸出的資料格式如下:
$GPGGA,121252.000,3937.3032,N,11611.6046,E,1,05,2.0,45.9,M,-5.7,M,,0000*77
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54
$GPVTG,359.95,T,,M,15.15,N,28.0,K,A*04
$GPGGA,121253.000,3937.3090,N,11611.6057,E,1,06,1.2,44.6,M,-5.7,M,,0000*72
$GPGSA,A,3,14,15,05,22,18,26,,,,,,,2.1,1.2,1.7*3D
$GPGSV,3,1,10,18,84,067,23,09,67,067,27,22,49,312,28,15,47,231,30*70
$GPGSV,3,2,10,21,32,199,23,14,25,272,24,05,21,140,32,26,14,070,20*7E
$GPGSV,3,3,10,29,07,074,,30,07,163,28*7D

可以看到,GPS模組發送過來的原始資料有很多,但是通常我們只需要其中的一部分資訊就夠用了,比如對於導航的功能,我們只需要以$GPRMC開頭,以換行符結束的一行資訊就夠了。即:
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54

因此我們需要做的就是從讀取的資料中截取以$GPRMC開頭的一行資訊,然後從中解析出經緯度、日期時間等有效資訊即可。

假設從串口讀取的資料存放在一個字串指標char *raw_buf指向的記憶體單元裏,首先我們通過ANSI C提供的strstr()函數找到以$GPRMC開頭以換行符’\n’結束的字串:
/* find "$GPRMC" from raw_buf */
if ((wellhandled_string = strstr(raw_buf, “$GPRMC”)) != NULL)
{
        for (i=0; i         {
                if (wellhandled_string[i] == '\n')
                {
                        wellhandled_string[i] = '\0'; //replace ‘\n’ with null
                }
        }
}
strstr()
 函數的原型是這樣聲明的:
char *strstr(const char *haystack, const char *needle);

strstr()函數可以在字串haystack中搜索字串needle第一次出現的 位置,並且返回指向字串needle首位址的指標,如果沒有搜索到則返回NULL。因此上面的代碼為我們在讀取的原始資料raw_buf裏搜 索$GPRMC第一次出現的位置,並將返回的指針賦給wellhandled_string,這樣如果搜索成功,則wellhandled_string 就會指向以$GPRMC開始的字串,接下來通過一個for迴圈找到換行符’\n’,將其替換為’\0’,即字串結束符。這樣就得到了一個指向有效資料 的字串指標wellhandled_string

然後要做的工作就是從wellhandled_string中提取出經緯度、日期時間等資訊。這個工作就可以交給強大的sscanf函數來實現。sscanf函數的原型如下:
int sscanf(const char *str, const char *format, ...);

我們都比較熟悉scanf這個函數,scanf可以從標準輸入流讀取與指定格式相符的數 據。sscanf則是從const char *str中讀取。它的強大之處在於可以方便地從字串中取出整數、浮點數和字串等各種類型的資料,而且它還具有類似於正則運算式的匹配功 能,sscanf默認是以空格分隔字串的,如果不是以空格來分割的話,就可以使用%[ ]來指定分割的條件。如%[a-z]表示讀取az的所有字元,%[^a-z]表示過濾a-z之間的所有字元,即只要遇到az之間的任意字元,轉換立刻 停止。比如:
sscanf(“abcdefABCDEF”, “%[^A-Z]”, str);
printf(“%s\n”, str);
result is: abcdef
%[^A-Z]
這樣的匹配格式為我們取遇到大寫字母為止的字串。利用這種匹配方式,我們就可以靈活的操作字串,得到我們想要的結果。

現在我們需要從下面的字串中提取有效資訊:
$GPRMC,121252.000,A,3958.3032,N,11629.6046,E,15.15,359.95,070306,,,A*54

GPRMC每個欄位的含義如下:
$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>*hh
<1> UTC
 時間,hhmmss(時分秒)格式 
<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=資料無效)

我們提取1~9九條資訊。用一個結構體存放這些資訊:
typedef struct gps_info
{
        char utc_time[BUF_SIZE];
        char status;
        float latitude_value;
        char latitude;
        float longtitude_value;
        char longtitude;
        float speed;
        float azimuth_angle;
        char utc_data[BUF_SIZE];
}GPS_INFO;

因為每一個欄位之間都是以逗號間隔開的,所以我們可以利用%[^,]來分割字串,這樣用sscanf函數就可以實現對有效資訊的提取:
sscanf(wellhandled_string,"$GPRMC,%[^,],%c,%f,%c,%f,%c,%f,%f,%[^,]",
            rmc_info->utc_time,\
            &(rmc_info->status),&(rmc_info->latitude_value),&(rmc_info->latitude),\
            &(rmc_info->longtitude_value),&(rmc_info->longtitude),&(rmc_info->speed),\
            &(rmc_info->azimuth_angle),\
            rmc_info->utc_data );
這個函數執行後,列印出的保存在struct gps_info結構體裏的資訊如下所示:
utc_time: 024813.640
status: A
latitude: N latitude value: 3158.460693
longtitude: E longtitude value: 11848.374023
speed: 10.050000
azimuth_angle: 324.269989
utc_data: 150706

可見,利用好sscanf函數,可以讓我們可以很高效的處理字串。

sscanf 教學請看

 http://ccckmit.wikidot.com/cp:sscanf



參考資料
http://blog.csdn.net/xmxqiyan/article/details/9134025
http://www.embedu.org/Column/Column196.htm

http://blog.csdn.net/baishengjie/article/details/5294321



這裡有詳細的gps命令解釋跟各家gps廠命令範例

http://www.gpsinformation.org/dale/nmea.htm

gps 模擬器..可以模擬gps裝置 由虛擬串列埠 或 真實串列埠 輸出 pgs 語句作測試



沒有留言 :

張貼留言