U-BLOX GPS 模塊及GPRMC指令解析


      受朋友所托,調試一款GPS模塊,該模塊是UBLOX的NEO-6M GPS模組。想到用這款GPS的人較多,自己日后也有可能在用到這個模塊,就寫下這份筆記。

1. 介紹

基本信息如下:

1, 模塊采用U-BLOX NEO-6M模組,體積小巧,性能優異。

2, 模塊增加放大電路,有利於無緣陶瓷天線快速搜星。

3, 模塊可通過串口進行各種參數設置,並可保存在EEPROM,使用方便。

4, 模塊自帶SMA接口,可以連接各種有源天線,適應能力強。

5, 模塊兼容3.3V/5V電平,方便連接各種單片機系統。

6, 模塊自帶可充電后備電池,可以掉電保持星歷數據。

看到這里,就可以知道,這個模塊是高度集成的,有點類似於西門子華為等公司的GPRS模塊,基本上就是一個小的系統,用戶只需要用AT命令通過串口通信就可以完成所有工作。那么這款模塊的使用,其實就是字符串的解析工作了。

 

2. 通信協議

GPS模塊采用NMEA 0183協議,NMEA 0183是美國國家海洋電子協會(National Marine Electronics Association)為海用電子設備制定的標准格式。目前業已成了GPS導航設備統一的RTCM(Radio Technical Commission for Maritime services)標准協議。

NMEA-0183協議采用ASCII碼來傳遞GPS定位信息,我們稱之為幀。

幀格式形如:$aaccc,ddd,ddd,„,ddd*hh(CR)(LF)

1、“$”:幀命令起始位

2、aaccc:地址域,前兩位為識別符(aa),后三位為語句名(ccc)

3、ddd„ddd:數據

4、“*”:校驗和前綴(也可以作為語句數據結束的標志)

5、hh:校驗和,$與*之間所有字符ASCII碼的校驗和(各字節做異或運算,得到

校驗和后,再轉換16進制格式的ASCII字符)

6、(CR)(LF):幀結束,回車和換行符

在一般的項目中,最常用的指令是第4個,即$GPRMC ,推薦定位信息,長度70字節。$GPRMC(推薦定位信息,Recommended Minimum Specific GPS/Transit Data),$GPRMC語句的基本格式如下:

 $GPRMC,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)*hh(CR)(LF)

(1) UTC時間,hhmmss(時分秒)

(2) 定位狀態,A=有效定位,V=無效定位

(3) 緯度ddmm.mmmmm(度分)

(4) 緯度半球N(北半球)或S(南半球)

(5) 經度dddmm.mmmmm(度分)

(6) 經度半球E(東經)或W(西經)

(7) 地面速率(000.0~999.9節)

(8) 地面航向(000.0~359.9度,以真北方為參考基准)

(9) UTC日期,ddmmyy(日月年)

(10)磁偏角(000.0~180.0度,前導位數不足則補0)

(11) 磁偏角方向,E(東)或W(西)

(12) 模式指示(A=自主定位,D=差分,E=估算,N=數據無效)

舉例如下:

$GPRMC,023543.00,A,2308.28715,N,11322.09875,E,0.195,,240213,,,A*78 

3. PC端顯示數據

GPS模塊有一個PC配置軟件,叫做u-Center,可以對模塊進行參數設置,然后保存到EEPROM,其實也可以通過單片機串口通信進行設置,但是PC端設置更加人性化,可以立刻看到結果。

打開GPS模塊之后,接上u-Center軟件,可以看到如下數據。

 1   $GPGSV,2,2,08,21,15,076,,23,52,270,,26,50,050,,27,52,179,*7D
 2   $GPRMC,132043.00,V,,,,,,,120116,,,N*7F
 3   $GPVTG,,,,,,,,,N*30
 4   $GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
 5   $GPGSV,2,1,08,03,00,230,,07,02,301,,08,24,198,,16,72,000,*7B
 6   $GPGSV,2,2,08,21,15,076,,23,52,270,,26,50,050,,27,52,179,*7D
 7   $GPRMC,132044.00,V,,,,,,,120116,,,N*78
 8   $GPVTG,,,,,,,,,N*30
 9   $GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
10   $GPGSV,2,1,08,03,00,230,,07,02,301,,08,24,198,,16,72,000,*7B
11   $GPGSV,2,2,08,21,15,076,,23,52,270,25,26,50,050,,27,52,179,*7A
12   $GPRMC,132045.00,V,,,,,,,120116,,,N*79
13   $GPVTG,,,,,,,,,N*30
14   $GPGSA,A,1,,,,,,,,,,,,,99.99,99.99,99.99*30
15   $GPGSV,2,1,08,03,00,230,,07,02,301,,08,24,198,,16,72,000,*7B
16   $GPGSV,2,2,08,21,15,076,,23,52,270,,26,50,050,,27,52,179,*7D
17   $GPRMC,132046.00,V,,,,,,,120116,,,N*7A
18   $GPVTG,,,,,,,,,N*30
19   $GPGSV,2,1,08,03,00,230,,07,02,301,,08,24,198,,16,72,000,*7B
20   $GPGSV,2,2,08,21,15,076,07,23,52,270,20,26,50,050,,27,52,179,*78
21   $GPRMC,132049.00,V,,,,,,,120116,,,N*75
22   $GPRMC,133300.00,V,,,,,,,120116,,,N*7A
23   $GPRMC,133301.00,V,,,,,,,120116,,,N*7B
24   $GPRMC,133302.00,V,,,,,,,120116,,,N*78
25   $GPRMC,133303.00,V,,,,,,,120116,,,N*79
26   $GPRMC,133304.00,V,,,,,,,120116,,,N*7E
27   $GPRMC,133305.00,V,,,,,,,120116,,,N*7F
28   $GPRMC,133306.00,A,3949.63075,N,11616.48616,E,0.513,,120116,,,A*7A
29   $GPRMC,133307.00,A,3949.63025,N,11616.48614,E,1.053,,120116,,,A*7C
30   $GPRMC,133308.00,A,3949.63002,N,11616.48641,E,1.101,,120116,,,A*70
31   …………

 

4. PC端軟件配置

      GPS有7種指令數據輸出,如果我們只需要當前經緯度的話,可以屏蔽其他的數據。如果不屏蔽的話,MCU處理的時候,會不停的收到不需要的指令,降低MCU效率。

使用軟件配置,[Config]-->[Configuration], 可以選擇顯示哪些項目,這里只保留GPRMC指令信息輸出,然后保存。界面顯示如下:

 

5. 數據解析

      相對於MCU的處理速度,GPS定位數據更新幾乎可以認為是緩慢變化的信號,每秒都會輸出推薦位置信息,但是即使丟掉幾個也不會影響定位准確性。因此可以使用中斷循環buffer來接收GPS輸出的串口數據,然后在需要的地方讀取buffer,對數據實現一次檢索,找到一個有用的GPS定位數據。

/*******************************************************************************
1.中斷負責把GPS串口數據保存到GPS_Uart_Rcv_Buf,在合適的地方調用此函數開始解析。
2.調用本函數會自動關閉接收,然后處理,期間的GPS數據可以忽略。
3.在合適的地方打開接收。
*******************************************************************************/
uint8_t get_gps_useful_data(uint8_t *weidu, uint8_t *jingdu)
{ 
     uint8_t *p_frame_start = NULL;
     uint8_t *p_useful_frame_start = NULL;
     uint8_t *p_useful_frame_end = NULL;
     int16_t frame_len = 0;
     int16_t rcv_buf_data_len = 0;
     int16_t index = 0;
     int16_t frame_start_point = 0;
     int16_t remain_data_len = 0;
     uint8_t rtn =0;
    
     gps_rcv_enable(FALSE); 
     rcv_buf_data_len = GPS_Rev_Buf_Size;
     p_frame_start = &GPS_Uart_Rcv_Buf[0];
        
    /* data example:
            $GPVTG,,,,,,,,,N*30 
            $GPRMC,132234.00,V,,,,,,,120116,,,N*7D 
            $GPRMC,133735.00,A,3949.63893,N,11616.48419,E,0.296,,120116,,,A*79
    */    
     for(index = 0; index < rcv_buf_data_len; )
     {     
         p_frame_start=strstr(GPS_Uart_Rcv_Buf + index, "$GPRMC,"); //1. find start, "$GPRMC,"
         //$GPRMC,132234.00,V,,,,,,,120116,,,N*7D $GPRMC,133735.00,A,3949.63893,N,11616.48419,E,0.296,,120116,,,A*79
         if(p_frame_start) 
         {
              index = p_frame_start-GPS_Uart_Rcv_Buf;
              if(index>0)
                {
                    memset(GPS_Uart_Rcv_Buf, 0 , index);
                }

              index = index + 7;
              p_useful_frame_start = strstr(GPS_Uart_Rcv_Buf + index, ",A,");//2 find useful data, ",A,"
              frame_start_point = p_useful_frame_start - p_frame_start;
              if((frame_start_point > 20)||(frame_start_point <= 0))//not find useful data
                {
                    continue;
                }
                frame_start_point = p_useful_frame_start-GPS_Uart_Rcv_Buf;
                p_useful_frame_end = strstr(GPS_Uart_Rcv_Buf + frame_start_point, ",A*");//3 find useful data end, ",A*"
                frame_len = p_useful_frame_end - p_frame_start + 1; 
                if((frame_len > GPS_Frame_Buf_Size)||(frame_len <= 50)) // not found frame end
                {
                    continue;
                }
                
                //$GPRMC,133735.00,A,3949.63893,N,11616.48419,E,0.296,,120116,,,A*79
                frame_start_point = p_frame_start - GPS_Uart_Rcv_Buf + 1;
                memset(GPS_Frame_Buf, 0, GPS_Frame_Buf_Size);
                memcpy(GPS_Frame_Buf, GPS_Uart_Rcv_Buf + frame_start_point , frame_len);
//                 if(check_frame_xor(GPS_Frame_Buf) != TRUE) 
//                 {
//                     continue;
//                 }
                //the frame is correct
                rtn = read_gps_data(GPS_Frame_Buf, remain_data_len, weidu, jingdu);
                if(1 == rtn)
                {
                    break; //found weidu,jingdu data
                }
                else
                {
                     continue;
                }
            }
            else
            {
               break;
            } 
        }
        g_gps_data_cnt = 0;
        memset(GPS_Uart_Rcv_Buf, 0, GPS_Rev_Buf_Size);
       return rtn;
}

     上面處理的基本思想是:找到"$GPRMC,"幀頭,然后找到代表定位信息有效的字符",A,",最后找到幀尾",A*"。

     因為實際收到的數據有不完整的,或者無效的定位信息,也有串口接收循環buffer造成的覆蓋數據,因此上面還校驗了數據長度,以及一個標志字符串到另一個字符串直接的長度。

     實際使用中,發現沒有加上校驗也可以很有效的工作,但是為了保證數據安全,最后的異或校驗還有應該有的。

/*******************************************************************************
* Function Name  : 
* Description    : 對GPRMC數據包進行解析,找到經緯度數據
* Input          :  
* Output         :  
* Return         :  
*******************************************************************************/
uint8_t read_gps_data(uint8_t *gps_buf, uint8_t frame_len, uint8_t *weidu, uint8_t *jindu)
 {
     uint8_t *weidu_s = NULL;
     uint8_t *weidu_o = NULL;
     uint8_t *jingdu_o = NULL;
     uint8_t rtn =0;
     //GPRMC,133735.00,A,3949.63893,N,11616.48419,E,0.296,,120116,,,A*79
     weidu_s  = strstr(GPS_Frame_Buf, ",A,");
     weidu_o  = strstr(GPS_Frame_Buf, ",N,");
     jingdu_o = strstr(GPS_Frame_Buf, ",E,");
     if((weidu_s == NULL) || (weidu_o == NULL) ||(jingdu_o == NULL) )
     {
         rtn = FALSE;
     }
     else
     {
          memset(weidu_buf,0,sizeof(weidu_buf));
          memset(jindu_buf,0,sizeof(jindu_buf));
          memcpy(weidu_buf, weidu_s+3, (weidu_o-weidu_s-3));
          memcpy(jindu_buf, weidu_o+3, (jingdu_o-weidu_o-3));
          printf("\r\n---------------------------------------");
          printf("\r\nGet GPS Frame:\r\n%s\r\n", GPS_Frame_Buf);
          printf("\r\n---------------------------------------");
          rtn = TRUE;
     }
    return rtn;
}

6. 總結

      本文總結了GPS模塊的基本使用方法,可以得到經度和緯度信息。對於此類的模塊產品,主要工作有兩大部分:

      1:模塊的熟悉,包括配置和指令的使用,一般可以一邊讀文檔一邊跑下demo體驗效果;

      2:字符串的解析。

      同樣的經驗可以應用於很多串口模塊。

      例如GPRS模塊,藍牙模塊,zigbee模塊,TCP模塊,CAN模塊,485模塊。

      這幾種產品我都使用過,其基本思路是一樣的,調試時候可以先用串口助手模擬MCU來發數據,其實大部分模塊都有自己的PC端工具,可以很快的看到效果。

      使用模塊可以極大地提升項目效率,但是靈活性和成本上會有所犧牲。另外,由於模塊的封閉性,一般都要寫很多的異常保護處理來保證產品的正常工作。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM