获取整数的位数_从NMEA0183到GNSS定位数据获取(二)软件篇
作者:良知猶存
轉載授權以及圍觀:歡迎添加微信公眾號:Conscience_Remains
總述
? ??GPS我們都知道,一種用來全球定位的系統,后來俄羅斯推出了格洛納斯定位系統,中國推出了北斗定位,歐盟有伽利略,印度與日本也有有發展。所以后來把覆蓋全球的自主地利空間定位的衛星系統成為GNSS。
? ? 現在衛星定位那么熱,那么作為一個嵌入式人怎么獲取這些數據為我們所用呢?下面就聽作者一一道來。
上一篇文章的傳送門從NMEA0183到GNSS定位數據獲取(一)原理篇
需要資料和代碼的朋友可以關注公眾號回復GNSS解析獲得自動回復的鏈接。
三、程序介紹
上一篇文章介紹了NMEA-0183的協議內容,當我們知道數據格式,那對于底層的開發人員來說就是如何把我們需要的數據解析出來。
話不多說上實例來看:
還是這張圖,上面可以看到SOC與模塊只是串口相連?
我們第一步就是先配置通訊IO,STM32和Linux大家自行選擇
外設配置好了,接下來就開始對”模塊“發過來的數據動手了。
$GNGGA,032220.291,,,,,0,0,,,M,,M,,*5D
$GNRMC,032220.291,V,,,,,0.00,0.00,140716,,,N*5D
$GNVTG,0.00,T,,M,0.00,N,0.00,K,N*2C
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$BDGSA,A,1,,,,,,,,,,,,,,,*0F
$GPGSV,2,1,07,23,,,31,08,,,49,30,,,33,16,,,45*7E
$GPGSV,2,2,07,07,,,44,27,,,49,26,,,43*72
$BDGSV,1,1,03,10,,,47,04,,,40,07,,,48*62
$GNGLL,,,,,032220.291,V,N*6F
首先先定義一個結構體,用來對解析好的數據進行存放。
//GPS NMEA-0183協議重要參數結構體定義 //衛星信息__packed typedef struct { u8 num; //衛星編號 u8 eledeg; //衛星仰角 u16 azideg; //衛星方位角 u8 sn; //信噪比 }nmea_slmsg;//UTC時間信息__packed typedef struct { u16 year; //年份 u8 month; //月份 u8 date; //日期 u8 hour; //小時 u8 min; //分鐘 u8 sec; //秒鐘}nmea_utc_time; //NMEA 0183 協議解析后數據存放結構體__packed typedef struct { u8 svnum; //可見衛星數 nmea_slmsg slmsg[12]; //最多12顆衛星 nmea_utc_time utc; //UTC時間 u32 latitude; //緯度 分擴大100000倍,實際要除以100000 u8 nshemi; //北緯/南緯,N:北緯;S:南緯 u32 longitude; //經度 分擴大100000倍,實際要除以100000 u8 ewhemi; //東經/西經,E:東經;W:西經 u8 gpssta; //GPS狀態:0,未定位;1,非差分定位;2,差分定位;6,正在估算. u8 posslnum; //用于定位的衛星數,0~12. u8 possl[12]; //用于定位的衛星編號 u8 fixmode; //定位類型:1,沒有定位;2,2D定位;3,3D定位 u16 pdop; //位置精度因子 0~500,對應實際值0~50.0 u16 hdop; //水平精度因子 0~500,對應實際值0~50.0 u16 vdop; //垂直精度因子 0~500,對應實際值0~50.0 u16 course; //航向 int altitude; //海拔高度,放大了10倍,實際除以10.單位:0.1m u32 speed; //地面速率,放大了1000倍,實際除以10.單位:0.001公里/小時 }nmea_msg;其次因為協議是以字符串的形式發過來的,我們要把解析的信息進行符號的定義以及字符的轉化,準備了以下兩個函數:
//從buf里面得到第cx個逗號所在的位置//返回值:0~0XFE,代表逗號所在位置的偏移.// 0XFF,代表不存在第cx個逗號 u8 NMEA_Comma_Pos(u8 *buf,u8 cx){ u8 *p=buf; while(cx) { if(*buf=='*'||*buf<' '||*buf>'z')return 0XFF;//遇到'*'或者非法字符,則不存在第cx個逗號 if(*buf==',')cx--; buf++; } return buf-p; }//str轉換為數字,以','或者'*'結束//buf:數字存儲區//dx:小數點位數,返回給調用函數//返回值:轉換后的數值/*遇到冒號以及豎杠、注釋的斜杠的時候進行返回*/int NMEA_Str2num(u8 *buf,u8*dx){ u8 *p=buf; u32 ires=0,fres=0; u8 ilen=0,flen=0,i; u8 mask=0; int res; while(1) //得到整數和小數的長度 { if(*p=='-'){mask|=0X02;p++;}//是負數 if(*p==','||(*p=='*')||(*p=='|')||(*p==':')\ ||(*p=='!') ||(*p=='/'))break;//遇到結束了 if(*p=='.'){mask|=0X01;p++;}//遇到小數點了 else if(*p == 0)//截至符 0 { break; } else if(*p>'9'||(*p<'0')) //有非法字符 { ilen=0; flen=0; break; } if(mask&0X01)flen++; else ilen++; p++; } if(mask&0X02)buf++; //去掉負號 for(i=0;i//得到整數部分數據 { ires+=NMEA_Pow(10,ilen-1-i)*(buf[i]-'0');// } if(flen>5)flen=5; //最多取5位小數 *dx=flen; //小數點位數 for(i=0;i//得到小數部分數據 { fres+=NMEA_Pow(10,flen-1-i)*(buf[ilen+1+i]-'0'); } res=ires*NMEA_Pow(10,flen)+fres; if(mask&0X02)res=-res; return res;}還有一個是在例如經緯度的轉化的時候需要用到的次方的函數:
//m^n函數//返回值:m^n次方.u32 NMEA_Pow(u8 m,u8 n){ u32 result=1; while(n--)result*=m; return result;}因為項目的需求沒有對協議全部的解析,只是針對性的進行了解析。其余大家想要解析的數據也是類似:
下面是以GPGGA 解析為例:其他標志頭的數據大家以此類推。
從上面圖片可以看到本條信息帶有14條信息,但是我只解析了第六個、第七個和第九個字節的數據。雖然這條信息中也有UTC時間,但是一般都是建議在*RMC中獲得。
//分析GPGGA信息//gpsx:nmea信息結構體//buf:接收到的GPS數據緩沖區首地址void NMEA_GPGGA_Analysis(nmea_msg *gpsx,u8 *buf){ u8 *p1,dx; u8 posx; p1 = (u8*)strstr((const char *)buf,"$GNGGA");//GN 標志開頭 if(p1 == NULL) { p1=(u8*)strstr((const char *)buf,"$GPGGA");//或者GP開頭的標志 你也可以用BD開頭的標志 } posx=NMEA_Comma_Pos(p1,6); //得到GPS狀態 if(posx!=0XFF) gpsx->gpssta=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,7); //得到用于定位的衛星數 if(posx!=0XFF) gpsx->posslnum=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,9); //得到海拔高度 if(posx!=0XFF) gpsx->altitude=NMEA_Str2num(p1+posx,&dx); }//分析GPGSA信息//gpsx:nmea信息結構體//buf:接收到的GPS數據緩沖區首地址void NMEA_GPGSA_Analysis(nmea_msg *gpsx,u8 *buf){ u8 *p1,dx; u8 posx; u8 i; p1=(u8*)strstr((const char *)buf,"$GPGSA"); if(p1 == NULL) p1 = (u8*)strstr((const char *)buf,"$GNGSA"); posx=NMEA_Comma_Pos(p1,2); //得到定位類型 if(posx!=0XFF)gpsx->fixmode=NMEA_Str2num(p1+posx,&dx); for(i=0;i<12;i++) //得到定位衛星編號 { posx=NMEA_Comma_Pos(p1,3+i); if(posx!=0XFF)gpsx->possl[i]=NMEA_Str2num(p1+posx,&dx); else break; } posx=NMEA_Comma_Pos(p1,15); //得到PDOP位置精度因子 if(posx!=0XFF)gpsx->pdop=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,16); //得到HDOP位置精度因子 if(posx!=0XFF)gpsx->hdop=NMEA_Str2num(p1+posx,&dx); posx=NMEA_Comma_Pos(p1,17); //得到VDOP位置精度因子 if(posx!=0XFF)gpsx->vdop=NMEA_Str2num(p1+posx,&dx); }//分析GPRMC信息//gpsx:nmea信息結構體//buf:接收到的GPS數據緩沖區首地址void NMEA_GPRMC_Analysis(nmea_msg *gpsx,u8 *buf){ u8 *p1,dx; u8 posx; u32 temp; float rs; p1 = (u8*)strstr((const char *)buf,"GNRMC"); //GNSS if(p1 == NULL) { p1=(u8*)strstr((const char *)buf,"GPRMC");//"$GPRMC",經常有&和GPRMC分開的情況,故只判斷GPRMC. } posx=NMEA_Comma_Pos(p1, 1); //得到UTC時間 hhmmss.ss if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx); //得到UTC時間,去掉ms gpsx->utc.hour=temp/10000; gpsx->utc.min=(temp/100)%100; gpsx->utc.sec=temp%100; } posx=NMEA_Comma_Pos(p1,2);/*判斷RMC數據狀態,A=數據有效 V=數據無效*/ if(posx!=0XFF) { u8* p2=(u8*)strstr((const char *)(p1+posx), "A"); if(p2 == NULL) { posx = 0; //數據無效 TODO } } posx=NMEA_Comma_Pos(p1,3); //得到緯度 ddmm.mmmm if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx); gpsx->latitude=temp/NMEA_Pow(10,dx+2); //得到° rs=temp%NMEA_Pow(10,dx+2); //得到' gpsx->latitude=gpsx->latitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//轉換為° } posx=NMEA_Comma_Pos(p1,4); //南緯還是北緯 if(posx!=0XFF) gpsx->nshemi=*(p1+posx); posx=NMEA_Comma_Pos(p1,5); //得到經度 dddmm.mmmm if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx); gpsx->longitude=temp/NMEA_Pow(10,dx+2); //得到° rs=temp%NMEA_Pow(10,dx+2); //得到' gpsx->longitude=gpsx->longitude*NMEA_Pow(10,5)+(rs*NMEA_Pow(10,5-dx))/60;//轉換為° } posx=NMEA_Comma_Pos(p1,6); //東經還是西經 if(posx!=0XFF) gpsx->ewhemi=*(p1+posx); posx=NMEA_Comma_Pos(p1,8); //得到方位 度 if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx); gpsx->course = temp*10; } posx=NMEA_Comma_Pos(p1, 9); //得到UTC日期 ddmmyy if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx, &dx); gpsx->utc.date = temp/10000; gpsx->utc.month = (temp/100)%100; gpsx->utc.year = 2000+temp%100; } }?這就是我分享的第二篇NMEA-0183到GNSS數據的文章,里面代碼都是實踐過的。如果大家有什么更好的思路,歡迎分享交流哈。
更多分享,掃碼關注我總結
以上是生活随笔為你收集整理的获取整数的位数_从NMEA0183到GNSS定位数据获取(二)软件篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022年CPA考试学习方法分享,需注意
- 下一篇: 股票787开头是什么股