NMEA-0183信息整理与分析
来源:互联网 发布:网络游戏破解软件大全 编辑:程序博客网 时间:2024/06/06 04:01
主要针对NMEA协议进行了整理。分为三个基础数据梳理函数和五个常用GPS解析函数。
三个基础数据处理函数:
1:逗号位置处理函数:
//从buf里面得到第cx个逗号所在的位置//返回值:0~0XFE,代表逗号所在位置的偏移.// 0XFF,代表不存在第cx个逗号 u8 NMEA_Comma_Pos(u8 *buf,u8 cx)//buf为指针变量,cx为第几个逗号
2.m^n函数:用于计算m^n次方
//m^n函数//返回值:m^n次方.u32 NMEA_Pow(u8 m,u8 n)
3.字符串转换为数字函数
//str转换为数字//buf:数字存储区//dx:小数点位数,返回给调用函数 //小数点位数//返回值:转换后的数值//应该是数值,不含小数,但是你知道了位数,位数在形参指针里int NMEA_Str2num(u8 *buf,u8*dx);//buf 和 dx 都是指针变量。
五个解析函数:
1.GPGSV 2.GNGGA 3.GNGSA 4.GNRMC 5.GNVTG
知识点补充:
包含文件:string.h 函数名: strstr
函数原型:extern char *strstr(char *str1, const char *str2);
strstr(str1,str2)
str1: 被查找目标 string expression to search.
str2: 要查找对象 The string expression to find.
返回值:若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。
详解代码
//从buf里面得到第cx个逗号所在的位置//返回值:0~0XFE,代表逗号所在位置的偏移.// 0XFF,代表不存在第cx个逗号 u8 NMEA_Comma_Pos(u8 *buf,u8 cx) //buf是指针变量{ u8 *p=buf;//指针变量地址给了值,p表示啥,p也是指针变量,其实这个是两条语句 u8 while(cx) { if(*buf=='*'||*buf<''||*buf>'z') return OXFF;//遇到‘*‘或者非法字符,则不存在第cx个逗号 if(*buf==',')cx--; buf++;//指针变量移动位置 } return buf-p; }
//m^n函数//返回值:m^n次方.u32 NMEA_Pow(u8 m,u8 n){ u32 result = 1; while(n--)result*=n; return result }
//str转换为数字//buf:数字存储区//dx:小数点位数,返回给调用函数 //小数点位数//返回值:转换后的数值//应该是数值,不含小数,但是你知道了位数,位数在形参指针里int NMEA_Str2num(u8 *buf,u8*dx);//buf 和 dx 都是指针变量。res是16位的{ u8 *p=buf;//p变为指针变量 u32 ires=0,fres=0; u8 ilen=0,flen=0,i; u8 mask = 0;//mask = 0x00; int res; while(1)//得到整数和小数的长度 不停的进行遍历 { if(*p=='-'){mask|=0x02;p++;}//是负数。mask=0X02是负数 if(*p==','||(*p=='*')){}break;//遇到结束了 if(*p=='.'){mask|=0x01;p++;}//遇到小数点了。 else if(*p>'9'||(*p<'0')) //有非法字符 { ilen = 0; flen = 0; break; } if (mask&0X01)flen++; else ilen++; // p++; } if(mask&0x02)flen++;//去掉负号,为啥这就是减掉符号了 for(i=0;i<ilen;i++) { ires+=NMEA_Pow(10,ilen-1-i)*(buf[i]-'0'); //应该是NMEA_Pow是取几个10,10的多少次方,buf[i]上的值 } if(flen>5)flen=5; //最多取5位小数 for(i=0;i<flen;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; }
【1】分析GPGSV信息
//分析GPGSV信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
//【结果】:得到所有卫星的卫星总数,每个卫星的编号,仰角,方位角,信噪比,对实际没有什么太大用处
$GPGSV,3,1,11,18,73,129,19,10,71,335,40,22,63,323,41,25,49,127,06*78
$GPGSV,3,1,11,[18,73,129,19],[10,71,335,40],[22,63,323,41],[25,49,127,06]*78
/*
(1) GSV 语句总数。【3】
(2) 本句 GSV 的编号。【1】
(3) 可见卫星的总数(00~12,前面的 0 也将被传输)。【11】
(4) 卫星编号(01~32,前面的 0 也将被传输)。【18】 【10】
(5) 卫星仰角(00~90 度,前面的 0 也将被传输)。【73】【71】
(6) 卫星方位角(000~359 度,前面的 0 也将被传输)【129】【335】
(7) 信噪比(00~99dB,没有跟踪到卫星时为空)。【19】【40】
void NMEA_GPGSV_Analysis(nmeg_msg *gpsx,u8 *buf){ u8 *p,*p1,dx; u8 len,i,j,slx=0; u8 posx; p=buf; p1=(u8*)strstr((const char *)p,"$GPGSV");//p1应该是$的指针变量 len=p1[7]-'0';//得到GPGSV的条数,应该是3,看例子 posx=NMEA_Comma_Pos(p1,3); //得到可见卫星总数【11】 if(posx!=0XFF)gpsx->svnum=NMEA_Str2num(p1+posx,&dx);// for(i=0;i<len;i++) { p1=(u8*)strstr((const char *)p,"$GPGSV"); for(j=0;j<4;j++) { posx=NMEA_Comma_Pos(p1,4+j*4); if(posx!=0XFF)gpsx->slmsg[slx].num=NMEA_Str2num(p1+posx,&dx); //得到卫星编号 else break; posx=NMEA_Comma_Pos(p1,5+j*4); if(posx!=0XFF)gpsx->slmsg[slx].eledeg=NMEA_Str2num(p1+posx,&dx);//得到卫星仰角 else break; posx=NMEA_Comma_Pos(p1,6+j*4); if(posx!=0XFF)gpsx->slmsg[slx].azideg=NMEA_Str2num(p1+posx,&dx);//得到卫星方位角 else break; posx=NMEA_Comma_Pos(p1,7+j*4); if(posx!=0XFF)gpsx->slmsg[slx].sn=NMEA_Str2num(p1+posx,&dx); //得到卫星信噪比 else break; slx++; } p=p1+1;//切换到下一个GPGSV信息 }}
【2】GNGGA信息
//分析GNGGA信息,这里就用到了679 如果要用记得自己加
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
/*
$GNGGA 语句的基本格式如下(其中 M 指单位 M, hh 指校验和, CR 和 LF 代表回车
换行,下同):
$GNGGA,(1),(2),(3),(4),(5),(6),(7),(8),(9),M,(10),M,(11),(12)*hh(CR)(LF)
举例如下:
$GNGGA,095528.000,2318.1133,N,11319.7210,E,1,06,3.7,55.1,M,-5.4,M,,0000*69
(1) UTC 时间,格式为 hhmmss.ss;【095528.000】
(2) 纬度,格式为 ddmm.mmmmm(度分格式);【2318.1133】
(3) 纬度半球, N 或 S(北纬或南纬);【N】
(4) 经度,格式为 dddmm.mmmmm(度分格式);【11319.7210】
(5) 经度半球, E 或 W(东经或西经);【E】
(6) GPS 状态, 0=未定位, 1=非差分定位, 2=差分定位;【1】
(7) 正在使用的用于定位的卫星数量(00~12)【06】
(8) HDOP 水平精确度因子(0.5~99.9)【3.7】
(9) 海拔高度(-9999.9 到 9999.9 米)【55.1】
(10) 大地水准面高度(-9999.9 到 9999.9 米)【-5.4】
(11) 差分时间(从最近一次接收到差分信号开始的秒数,非差分定位,此项为空)【空】
(12) 差分参考基站标号(0000 到 1023, 首位 0 也将传送,非差分定位,此项为空)【空】
void NMEA_GNGGA_Analysis(nmea_msg *gpsx,u8 *buf){ u8 *p1,dx; //dx不知道干嘛用的 u8 posx; //是变量 p1=(u8*)strstr((const char *)buf,"$GNGGA"); //从首地址放入一般都是GPS所有数据,然后的到p1为$GNGGA的首地址 posx=NMEA_Comma_Pos(p1,6);//得到GPS状态//代表逗号所在位置的偏移 if(posx!=0XFF)gpsx->gpssta=NMEA_Str2num(p1+posx,&dx); ////buf:数字存储区,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); }
【3】分析GNGSA信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
/*
$GNGSA 语句的基本格式如下:
$GNGSA,(1),(2),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(3),(4),(5),(6)*hh(CR)(LF)
举例如下:
$GNGSA,A,3,14,22,24,12,,,,,,,,,4.2,3.7,2.1*2D
$GNGSA,A,3,209,214,,,,,,,,,,,4.2,3.7,2.1*21
注 1: 精度因子值越小,则准确度越高。
(1) 模式, M = 手动, A = 自动。【A】
(2) 定位类型, 1=未定位, 2=2D 定位, 3=3D 定位。【3】
(3) 正在用于定位的卫星号(01~32)【3】【14】【22】(一共有12个)
(4) PDOP 综合位置精度因子(0.5-99.9)【4.2】
(5) HDOP 水平精度因子 1(0.5-99.9)【3.7】
(6) VDOP 垂直精度因子(0.5-99.9)【2.1】
void NMEA_GNGSA_Analysis(nmea_msg *gpsx,u8 *buf){ u8 *p1,dx; //dx为后面用的但没有体现小数点右面保留几位啊 u8 posx; // u8 i; 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); //将卫星编号逐1手机过来 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); }
【4】分析GNRMC信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
/*
$GNRMC(推荐定位信息, Recommended Minimum Specific GPS/Transit Data)
$GNRMC 语句的基本格式如下:
$GNRMC,(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)*hh(CR)(LF)
举例如下:
$GNRMC,095554.000,A,2318.1327,N,11319.7252,E,000.0,005.7,081215,,,A*73
(1) UTC 时间, hhmmss(时分秒)【095554.000】
(2) 定位状态, A=有效定位, V=无效定位【A】
(3) 纬度 ddmm.mmmmm(度分)【2318.1327】
(4) 纬度半球 N(北半球)或 S(南半球)【N】
(5) 经度 dddmm.mmmmm(度分)【11319.7252】
(6) 经度半球 E(东经)或 W(西经)【E】
(7) 地面速率(000.0~999.9 节)【000.0】
(8) 地面航向(000.0~359.9 度,以真北方为参考基准)【005.7】
(9) UTC 日期, ddmmyy(日月年)【081215】
(10) 磁偏角(000.0~180.0 度,前导位数不足则补 0)【】
(11) 磁偏角方向, E(东)或 W(西)【】
(12) 模式指示(A=自主定位, D=差分, E=估算, N=数据无效)【A】
void NMEA_GNRMC_Analysis(nmea_msg *gpsx,u8 *buf){ u8 *p1,dx; u8 posx; u32 temp; //32位变量去读取时间数据,格式是不清楚的,实际数字例如095554.000 float rs; p1=(u8*)strstr((const char *)buf,"$GNRMC");//"$GNRMC",经常有&和GNRMC分开的情况,故只判断GPRMC. posx=NMEA_Comma_Pos(p1,1); //得到UTC时间 if(posx!=0XFF) { //这里数据存在一个算法,我不知道这个时间是什么原理,但是能算出来 temp=NMEA_Str2num(p1+posx,&dx)/NMEA_Pow(10,dx); //得到UTC时间,去掉ms gpsx->utc.hour=temp/10000;//95554/10000 = 9 gpsx->utc.min=(temp/100)%100;//955%100 = 55 gpsx->utc.sec=temp%100; //54 } posx=NMEA_Comma_Pos(p1,3); //得到纬度 ddmm.mmmmm(度分)【2318.1327】 if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx);//取整2318 gpsx->latitude=temp/NMEA_Pow(10,dx+2); //得到°//23° rs=temp%NMEA_Pow(10,dx+2); //得到'//2318%(10^2)=18' //【这句子历程是5,我跟人感觉好像是6呢,好奇怪,这里怎么算出来的】 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); //得到经度 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,9); //得到UTC日期 if(posx!=0XFF) { temp=NMEA_Str2num(p1+posx,&dx); //得到UTC日期 gpsx->utc.date=temp/10000; gpsx->utc.month=(temp/100)%100; gpsx->utc.year=2000+temp%100; } }
【5】GNVTG(地面速度信息, Track Made Good and Ground Speed)
$GNVTG 语句的基本格式如下:
$GNVTG,(1),T,(2),M,(3),N,(4),K,(5)*hh(CR)(LF)
举例如下:
$GNVTG,005.7,T,,M,000.0,N,000.0,K,A*11
(1)以真北为参考基准的地面航向(000~359 度,前面的 0 也将被传输)【005.7】
(2)以磁北为参考基准的地面航向(000~359 度,前面的 0 也将被传输)【】
(3) 地面速率(000.0~999.9 节,前面的 0 也将被传输)【000.0】
(4) 地面速率(0000.0~1851.8 公里/小时,前面的 0 也将被传输)【000.0】
(5) 模式指示(A=自主定位, D=差分, E=估算, N=数据无效)【A】
*/
//分析GNVTG信息
//gpsx:nmea信息结构体
//buf:接收到的GPS数据缓冲区首地址
void NMEA_GNVTG_Analysis(nmea_msg *gpsx,u8 *buf){ u8 *p1,dx; u8 posx; p1=(u8*)strstr((const char *)buf,"$GNVTG"); //$GNVTG,(1),T,(2),M,(3),N,(4),K,(5)*hh(CR)(LF) //第7个逗号后面是(4)即地面速率 posx=NMEA_Comma_Pos(p1,7); //得到地面速率 if(posx!=0XFF) { gpsx->speed=NMEA_Str2num(p1+posx,&dx); //得到速度,后面为啥扩大1000倍表示不理解 if(dx<3)gpsx->speed*=NMEA_Pow(10,3-dx); //确保扩大1000倍 }}
//提取NMEA-0183信息//gpsx:nmea信息结构体//buf:接收到的GPS数据缓冲区首地址void GPS_Analysis(nmea_msg *gpsx,u8 *buf){ NMEA_GPGSV_Analysis(gpsx,buf); //GPGSV解析 NMEA_BDGSV_Analysis(gpsx,buf); //BDGSV解析 NMEA_GNGGA_Analysis(gpsx,buf); //GNGGA解析 NMEA_GNGSA_Analysis(gpsx,buf); //GPNSA解析 NMEA_GNRMC_Analysis(gpsx,buf); //GPNMC解析 NMEA_GNVTG_Analysis(gpsx,buf); //GPNTG解析}
- NMEA-0183信息整理与分析
- NMEA信息的读取与处理
- NMEA-0183国外开源库源代码分析-序言
- NMEA-0183国外开源库源代码分析-README
- NMEA-0183
- NMEA-0183国外开源库源代码分析-GNU LICENSE
- NMEA-0183国外开源库源代码分析-tok.h
- NMEA library数据处理过程分析
- GPS NMEA-0183协议
- NMEA-0183标准
- NMEA-0183协议解析
- NMEA-0183协议详解
- NMEA 0183协议解析
- NMEA-0183协议
- NMEA 0183协议解析
- NMEA-0183协议详解
- GPS NMEA-0183协议介绍
- GPS NMEA-0183协议详解
- Java
- 【小白】selenium入门(三)学习笔记
- 推荐系统重要会议和期刊
- Java实现红黑树
- angularJS 单击ng-click和双击ng-dblclick嵌套或者出现在同一元素 避免事件互相干扰方法
- NMEA-0183信息整理与分析
- CentOS7 ssh
- Xen复制虚拟机
- 解决org.xml.sax.SAXParseException:Content is not allowed in prolog
- redis(1)
- FastJSON、Gson和Jackson性能对比和共同缺点,注意事项
- 如何用js得到当前页面的url信息方法(JS获取当前网址信息)
- Elasticsearch(八)elasticsearch数据输入和输出
- WordCount的实例