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解析}
原创粉丝点击