GPS項目實戰系列之:GPS數據解析2

2020-08-29 TopSemic

接著上一篇,咱們繼續說GPS數據解析的問題,GPS數據解析的核心問題可以歸結為如何解析以逗號作為分隔符的字符串問題。看似很簡單的一個功能,真正實現起來也那不是那麼容易,在調試的過程中,我就遇到了很多的小問題,在此做個完整的記錄與總結,希望對大家有幫助。

首先給大家介紹一下strtok函數,它是標準函數庫中的一員,標準函數庫是一個工具箱,它能極大地擴展C程式設計師的能力,我們需要熟悉並且靈活的應用。

char *strtok(char *str, const char *delim),功能是分解字符串str 為一組字符串,delim為分隔符。

該函數返回被分解的第一個子字符串,如果沒有可檢索的字符串,則返回一個空指針。

我們看一下這個函數的使用例子,

程序清單1: strtok函數使用示例1

include <stdlib.h>34;Apple,Pear,Potato,11&34;,&34;%s\r\n&34;,&include <stdio.h>include <string.h>int main(void){ char str[] =&34;; char *tokens = strtok (str,&34;); //iterate over tokens.. . while (tokens!= NULL) { printf (&34;,tokens); tokens = strtok (NULL,&34;); } return 0;}

輸出結果如下:

Apple

Pear

Potato

11

和第一個程序輸出的結果完全一致,起初我對這個結果很不理解,我本能的以為第一次調用strtok的返回值是&34;,第二次調用strtok的返回值為&34;,第三次調用後,由於2個逗號之間是空的,我以為返回值會是NULL,然後在第四次調用後,得到&34;。

事實證明我的想法是錯的,錯在第三次調用strok函數後的返回值,並不是我想的那樣返回NULL,實際上第三次調用後,返回值是&34;。也就說當檢索到兩個連續的逗號之間沒有字符串,它會自動往後檢索,把後面的下一個逗號前的字符串返回。

strtok熟悉後,我們需要思考一個重要的問題,就是如何判斷出逗號間為空的狀況。不然直接使用strtok循環的去解析,當出現逗號間為空時,就會出現欄位無法再一一對應的情況。什麼意思呢,看上面的代碼,就是程序並沒法知道第三個欄位是空,解析出來的&34;也不知道對應是第幾個欄位的。

可以考慮採用以下方式來解決,程序裡先去判斷是否有連續逗號(&34;),如果有則將&34;替換為&34;形式,其中@是一個正常情況下該欄位不會出現的字符。這樣操作之後逗號分隔的各個欄位就都有了內容,再進行解析就不會出現上述的問題了。那如何用程序實現字符串的替換功能呢?

即對於上述字符串:&34;

我們希望經過替換後字符串變為:

&34;

大家可以看一下下面的代碼(替換函數strrpl是直接谷哥出來的)

程序清單3:實現字符串替換功能

include <stdlib.h>34;cannot find string \n&34;Apple,Pear,,Potato,11&34;,,&34;,@,&34;%s\n&34;,&34;%s\r\n&34;,&34;Apple,Pear,,,Potato,,11&include <stdio.h>include <string.h>char* strrpl(char *str, char* find, char *replace){ int i; char *pt = strstr(str, find); char *firstStr; if(pt == NULL){ printf(&34;); return NULL; } firstStr = (char* )malloc(100 * sizeof(char)); // copy just until i find what i need to replace // i tried to specify the length of firstStr just with pt - str strncpy(firstStr, str, strlen(str) - strlen(pt)); strcat(firstStr, replace); strcat(firstStr, pt + strlen(find)); for(i = 0; i < strlen(firstStr); i++) str[i] = firstStr[i]; return str;}int main(void){ char str[] =&34;; while (strstr(str, &34;)) strrpl(str, &34;, &34;); printf(&34;,str); char *tokens = strtok (str,&34;); //iterate over tokens.. . while (tokens!= NULL) { printf (&34;,tokens); tokens = strtok (NULL,&34;); } return 0;}

這個代碼運行後出現了如下問題:

看起來像是數組越界了,經過分析可知是str數組越界導致的,由於&34;被替換成&34; ,導致數組長度變長從而產生越界。所以上述代碼不能那麼寫,我們可以通過定義一個新的更長長度的數組來解決。另外還有一點需要注意的是:strok函數執行任務時,它會修改它所處理的字符串,如果源字符串不能被修改,就必須得複製一份,將這份拷貝傳給strok函數。

改進後的代碼如下:

程序清單5:字符串操作時要防止越界

include <stdlib.h>34;cannot find string \n&34;Apple,Pear,,,Potato,,11&34;,,&34;,,&34;,@,&34;%s\n&34;,&34;%s\r\n&34;,&34;$GNRMC,051035.00,A,4000.74054,N,11628.03344,E,0.253,,020320,6.91,W,D*23\n\$GNVTG,,T,,M,0.253,N,0.468,K,D*36\n\$GNGGA,051035.00,4000.74054,N,11628.03344,E,2,08,2.08,3.3,M,-8.3,M,,0000*5D\n\$GNGSA,A,3,29,14,27,42,03,,,,,,,,3.33,2.08,2.60*1F\n\$GNGSA,A,3,87,66,67,,,,,,,,,,3.33,2.08,2.60*1F\n\$GPGSV,5,1,17,03,15,250,28,04,47,302,17,08,03,196,09,09,16,318,13*7B\n\$GPGSV,5,2,17,14,23,157,32,16,72,264,19,21,08,092,20,22,07,230,34*77\n\$GPGSV,5,3,17,23,41,303,,26,72,027,21,27,29,179,28,29,15,039,30*77\n\$GPGSV,5,4,17,31,47,089,15,40,13,251,,41,32,226,31,42,35,140,31*7D\n\$GPGSV,5,5,17,50,42,164,34*48\n\$GLGSV,3,1,10,66,12,192,26,67,44,240,28,68,34,310,,76,25,063,*6E\n\$GLGSV,3,2,10,77,58,357,,78,29,287,,85,01,012,,86,30,057,*60\n\$GLGSV,3,3,10,87,26,128,32,88,00,163,*61\n\$GNGLL,4000.74054,N,11628.03344,E,051035.00,A,D*7A&include <stdio.h>include <string.h>char* strrpl(char *str, char* find, char *replace){ int i; char *pt = strstr(str, find); char *firstStr; if(pt == NULL){ printf(&34;); return NULL; } int len = strlen(str)+1+strlen(replace)-strlen(find); firstStr = (char* )malloc(len); memset(firstStr,0,len); // copy just until i find what i need to replace // i tried to specify the length of firstStr just with pt - str strncpy(firstStr, str, strlen(str) - strlen(pt)); strcat(firstStr, replace); strcat(firstStr, pt + strlen(find)); for(i = 0; i < strlen(firstStr); i++) str[i] = firstStr[i]; free(firstStr); return str;}int main(void){ char str[] = &34;; char *buff; buff = malloc(sizeof(str)+100); memset(buff, 0, sizeof(str)+100); memcpy(buff, str, sizeof(str)); while (strstr(buff, &34;)) strrpl(buff, &34;, &34;); printf(&34;,buff); char *tokens = strtok (buff,&34;); //iterate over tokens.. . while (tokens!= NULL) { printf (&34;,tokens); tokens = strtok (NULL,&34;); } free(buff); return 0;}

這樣再次運行代碼,就可以得到正確的結果了。

有了以上基礎,就可以實際來寫GPS數據解析的代碼了,在上一篇文章的基礎上,我對整個目錄結構做了調整,新的工程總共有5個文件,mian.c為主程序,gnss.c和gnss.h和GNSS數據解析相關,uart.c和uart.h對應串口配置。

運行後,會輸出如下信息:

上述代碼中重點是gnss.c文件中的gps_analyse函數,大家可以好好看看,

int gps_analyse(char *buff,int buff_len,GNSS *gps_data){ char *ptr = NULL; if(strlen(buff)<10) { return -1; } /* 如果buff字符串中包含字符&34;則將$GPRMC的地址賦值給ptr */ if( NULL==(ptr=strstr(buff,&34;)) && NULL==(ptr=strstr(buff,&34;)) ) { return -2; } if(check_nmea_message(ptr, 0, buff_len) <0 ) { printf(&34;); return -3; } char *tmpbuf; tmpbuf = (char *)malloc(strlen(ptr)+100); memset(tmpbuf, 0, strlen(ptr)+100); memcpy(tmpbuf, ptr, strlen(ptr)); while (strstr(tmpbuf, &34;)) strrpl(tmpbuf, &34;, &34;); printf(&34;,tmpbuf); char* pch = strtok(tmpbuf, &34;); // 1 time pch = strtok(NULL, &34;); nmea_get_time(pch, &gps_data->time); // 2 status pch = strtok(NULL, &34;); gps_data->pos_state = *pch; //3 latitude pch = strtok(NULL, &34;); nmea_lat_long_to_double(&gps_data->latitude, pch, strlen(pch)); //4 latitude direction pch = strtok(NULL, &34;); gps_data->NS = *pch; //5 longitude pch = strtok(NULL, &34;); nmea_lat_long_to_double(&gps_data->longitude, pch, strlen(pch)); //6 long direct pch = strtok(NULL, &34;); gps_data->EW = *pch; //7 speed pch = strtok(NULL, &34;); gps_data->speed = 1.852 * strtof(pch, (char **) NULL ) / 3.6; //8 direction pch = strtok(NULL, &34;); gps_data->direction = strtof(pch, (char**)NULL); //9 date pch = strtok(NULL, &34;); nmea_get_date(pch, &gps_data->time); //10 不處理 pch = strtok(NULL, &34;); //11 不處理 pch = strtok(NULL, &34;); //12 mode pch = strtok(NULL, &34;); gps_data->pos_mode = *pch; free(tmpbuf); return 0;}

我在調試過程中遇到了很多的問題,通過自己實際動手搬運、修改、調試代碼收穫了很多知識,主要有以下幾點:

1) 在使用strtof、strtod函數時,一定要加上頭文件39;\0&39;\0'。

3) 要養成初始化指針、內存空間後,立刻賦初值的習慣。

4)strok函數適合用來分割字符串,解析各個欄位。

5)操作字符串/字符數組時一定要注意越界的問題。

相關焦點

  • GPS項目實戰系列1:GPS數據解析1
    前面寫了一系列關於Linux的文章,從這一篇開始換個題目,叫做GPS項目實戰系列,後面的很多篇內容都會圍繞著這個項目展開。這個項目要完成的任務,可以參考之前的這篇文章:今天這篇文章的主題是GPS數據解析,關於GPS的基礎知識,我在很早之前的一篇文章裡有過介紹過,網上也有大量的內容可以參考,不在這裡解釋了。
  • GPS項目實戰系列之:再談一次GPS數據解析
    之前兩篇已經寫過GPS晶片解析的話題,今天之所以又寫一次,是因為又有了一些的新的內容想和大家分享。在上一篇文章裡,我採用的是用strtok函數進行欄位分割,該網友建議試試sscanf,sscanf函數不知道大家平時有沒有用過,它用來分割並處理一串數據比較方便
  • ​車載gps定位器,車載gps定位器的作用
    2、地面控制系統地面控制系統由監測站(Monitor Station)、主控制站(Master Monitor Station)、地面天線(Ground Antenna)所組成,主控制站位於美國科羅拉多州春田市(Colorado Spring)。地面控制站負責收集由衛星傳回之訊息,並計算衛星星曆、相對距離,大氣校正等數據。
  • 松谿縣gps車輛監控管理系統GPS產品型號
    松谿縣gps車輛監控管理系統GPS產品型號超長待機時間,10天(深度休眠模式)(電池為1200MAH),在定位方式的創新上,內置3D加速度傳感器(實現震動報警及智能省電),再加上超長待機,能夠達10天之長,在價格的可比性上,在同類產品相比而言,這款採用雙工模式,既可定位車子連寵物也可以,在價格上迎合大眾普遍消費需求走親民路線
  • CASIO PRT-2GP——登山系列核心GPS定位功能的絕唱
    猶如許巍的歌一樣,卡西歐在1999年發布了世界首個GPS定位手錶PRT-1後,相隔一年後發布了二代GPS手錶PRT-2CP。本來想趁勢暴走,誰知道時代已經不同,二十一世紀似乎不再是日本科技一支獨秀的時代,而GPS定位也已經慢慢普及至全球。
  • 一起來捉妖gps定位漂移解決方法詳解
    一起來捉妖gps定位漂移怎麼辦?不少小夥伴們使用gps定位自己所在的位置輔助抓捕周圍的妖怪,但是卻發現定位並不是自己的位置。而是附近的位置,這是什麼情況?下面是小編分享的攻略,還不了解的可以來關注下!
  • 《一起來捉妖》GPS定位漂移定位不準原因是什麼 gps定位漂移與顯示...
    下面就讓九遊的小編帶著大家一起來了解一下,希望可以幫助大家解決相關問題~ 《一起來捉妖》gps定位漂移與顯示不... 不少玩家反映《一起來捉妖》遊戲存在GPS定位漂移與顯示不準確的情況,那麼這是怎麼回事呢?
  • 基於Nios II及GPS/GSM的汽車狀態監控系統設計
    * 校科研基金項目「基於SOPC的汽車安全監控系統」資助。 Altera公司推出了新一代多種系列FPGA,本設計選用低成本的Cyclone系列器件EP1C12,其具有12 060個邏輯單元,52個M4K RAM塊,239 616個RAM位和2個鎖相環,最大用戶I/O引腳249。系統硬體組成框圖由Nios系統和外部設備兩部分組成,如圖1所示。
  • pokemon go gps signal not found解決辦法_pokemon go顯示gps...
    pokemongo顯示gps signal not found怎麼回事?下面小編就為大家介紹一下pokemongo gps signal not found的解決辦法,希望對大家有所幫助。
  • 位置服務軟體 GPS手機定位—GPSToy試用(組圖)
    進入GPS監控,添加好友,輸入好友帳號(帳號為GPSTOY網站註冊帳號)或手機號碼,添加後進行定位(必須對方授權給您哦,不然沒辦法查詢的)  只要您的好友通過GPSToy mobile for WindowsMobile上傳過gps數據就可以查詢到具體的信息了,如果是定時上傳數據,自然就可以跟蹤了。
  • 華為手機gps信號弱怎麼辦?
    但在使用過程中,手機定位不準、車內搜星能力差、信號弱等問題時不時的會出現,今天跟大家一起來探討下華為手機gps信號弱怎麼辦?2.定位的準確度與GPS衛星的精度及地圖的精確度有關,建議儘量在網絡信號較強、周邊環境空曠無遮擋的地點進行定位和使用導航,以保證信號的正常接收。3.部分保護殼,特別是金屬保護殼,會影響GPS信號強度;4.使用手機導航時,請及時升級導航軟體和地圖等信息,進而獲取最新的路況。5.請重啟手機,或請嘗試先備份數據,再恢復出廠設置。
  • 世界第一個GPS定位手錶——CASIO PRT1
    1999年6月這款號稱世界首發搭載全球定位系統gps的手錶由卡西歐發布,並歸屬於卡西歐登山系列,並以響亮的PRT-1命名,足以見得似乎要開創歷史的決心。綽號Satellite Navi的PRT-1從美國開發的27顆GPS衛星中獲取gps信號。方便用戶根據位置和目的地確定方向和距離。
  • 佳明手持gps公司_華威測繪新穎潮流
    看到很多朋友問有沒有好用的gps土地測量APP推薦,這裡為大家帶來安卓平臺上各種gps土地測量APP下載匯總,在找gps土地測量APP的朋友不要錯過。很多玩家問那款土地畝數測量APP好用,這裡小編帶來土地畝數測量APP的合集推薦,大家可以自行下載使用後再決定使用哪塊。
  • 濟南手持GPS總代理 佳明GPS MAP66s優惠
    圖為:佳明GPS MAP66s產品特點單點定位3-5米,多種GNSS衛星信號支持能記錄RINEX數據3英寸防炫屏幕, MAP66st可支持等高線地圖增強版無線連接功能,設備對設備可穿衛星影像數據,支持Wi-Fi支持WIFI,藍牙, GARMIN設備間的數據傳輸支持高度計,電子羅盤,氣壓測高,2節AA電池可最大續航16小時軍標防震防水級別MIL-STD-810G支持Garmin ExploreM app,增強版戶外使用體驗支持Connect IQ
  • iwatch4gps和蜂窩區別
    iwatch4在2018蘋果秋季新品發布會上正式發布,很多準備購買的iwatch4的用戶都不知道iwatch4 gps和蜂窩區別,為什麼兩者價格上相差這麼多。那我們就一起來看看他們的區別。 iwatch4 gps和蜂窩區別  1、蜂窩數據功能,內存從8G增加到16G,蜂窩版本的背部傳感器保護罩為陶瓷材質,GPS
  • 安徽gps車輛定位儀-高效服務
    gps車輛定位儀哪家好簡而言之,這些都代表著非常技術和管理的水平,很多人並不知道,那麼真的很明白!根據gps理念來看,gps圖像範圍其實是非常廣的,那麼就讓我們來了解一下如何來準確判斷車輛的實時位置,從而準確的發現成都車輛定位儀哪家好。我們在這裡小編給大家簡單的介紹一下成都gps車輛定位儀哪家好,能夠在此非常清晰地了解一下如何來自動的將gps圖像展示給你所需要的車型。
  • 安徽汽車gps定位儀-擇優推薦
    茂林GPS運營中心坐落於中國科技之城安徽合肥,是一家專業從事於汽車電子產品、無線GPS、北鬥GPS定位、弱電產品銷售、設計、施工、維護一體化服務的運營商。追求優質的品質、優質的服務和優質的形象。
  • 貸款車私自拆gps後果是什麼
    我們需要明白的是,貸款機構安裝gps是怕貸款人拒絕履行還款義務,這時有了gps就可以方便進行強制扣車的措施。其次,安裝gps是有很高利潤的,一般車貸機構的gps成本最貴也就兩三百,但是他可以在你貸款的時候用高價賣給你賺取利潤。車貸公司是不怕gps被拆的,貸款車私自拆裝gps屬於主動違約行為,是需要付違約金的,違約金數目一般比較大,很容易得不償失。當車貸公司發現你的gps 被你私自拆除時,就會通過你貸款時留下的地址找到你並對你的車輛進行扣押,嚴重時貸款公司是可以對你進行起訴的。
  • 北鬥最後一顆組網衛星發射後,我國是否可以不再使用GPS了?
    早在幾年前,國產的定位晶片就已經支持格洛納斯,北鬥和gps,三合一,單北鬥工作定位也是很準的,大概能搜到6 7顆星,這就已經足夠強了。 尤其最近火熱的去A化,雖然上頭沒有指示,但我們潛意識裡都在去A,維護項目就那樣了,先保持不變,新項目軟硬兩方面都在儘量去A。GPS是全球定位系統的縮寫,北鬥也屬於此範疇。
  • 揭露山東拆除車gps定位器跟蹤器真面目
    前瞻:【躍翔科技電話微信: 18660938391專業拆除汽車gps定位器跟蹤器】是集生產/拆除與安裝於一體的綜合性汽車gps定位器跟蹤器的服務機構,我們的目標是明確的,以過硬的技術/前沿的設備為顧客排憂解難。始終秉承用戶至上的經營理念。在行業內不斷取得新突破;深知想做大做強,取得顧客信任必須強大自己!