# NMEA0183-C
GPS NMEA0183协议简要解析框架
* 支持解析 RMC、GGA、VTG、HDT等消息字段信息,移植源码者可自行考虑添加新的解析代码。
* 解析方式采用逐个字段解析的方式,能很大程度上节省消耗内存空间。
* 重新编写数据转换函数,不依赖外部库,移植时一般只需包含NMEA0183.h文件即可。
* 代码示例:
char nmea[] = \
"$GNRMC,102219.00,A,2239.11578,N,11406.59325,E,0.009,,291018,,,D*62\r\n"\
"$GNVTG,,T,,M,0.009,N,0.017,K,D*37\r\n"\
"$GNGGA,102220.00,2239.11583,N,11406.59338,E,2,09,1.30,112.7,M,-2.3,M,,0000*52\r\n";
NMEA0183 nmea0183;
unsigned int index = 0;
for(index=0; index<sizeof(nmea); ++index)
{
if(nmea_decode(&nmea0183, nmea[index]))
{
///解析代码成功
}
}
解析成功后得到的数据保存在nmea0183.gpsData结构体缓冲区中。
各个消息字段及各个部分含义:
XXGGA
例如:$GPGGA,062938.00,3110.4700719,N,12123.2657056,E,1,25,0.6,58.9666,M,0.000,M,99,AAAA*50
GGA信息:UTC时分秒、经纬度、GPS状态、卫星数量、高程、差分延迟、基站号
字段0:$GPGGA,语句ID,表明该语句为Global Positioning System Fix Data(GGA)GPS定位信息
字段1:UTC 时间,hhmmss.sss,时分秒格式
字段2:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段3:纬度N(北纬)或S(南纬)
字段4:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段5:经度E(东经)或W(西经)
字段6:GPS状态,解状态0:无效解1:单点定位解2:伪距差分解4:固定解5:浮动解。
字段7:正在使用的卫星数量(前导位数不足则补0)
字段8:HDOP水平精度因子(0.5 - 99.9)
字段9:海拔高度(-9999.9 - 99999.9)
字段10:地球椭球面相对大地水准面的高度
字段11:差分时间(从最近一次接收到差分信号开始的秒数,如果不是差分定位将为空)
字段12:差分站ID号0000 - 1023(前导位数不足则补0,如果不是差分定位将为空)
字段13:校验值
$GPRMC
例:$GPRMC,064457.90,A,3110.4691141,N,12123.2667676,E,0.157,63.0,300713,0.0,W,A05
字段0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
字段1:UTC时间,hhmmss.sss格式
字段2:状态,A=定位,V=未定位
字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段4:纬度N(北纬)或S(南纬)
字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段6:经度E(东经)或W(西经)
字段7:速度,节,Knots
字段8:方位角,度
字段9:UTC日期,DDMMYY格式
字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
字段11:磁偏角方向,E=东W=西
字段16:校验值
$GPVTG
例:$GPVTG,89.68,T,,M,0.00,N,0.0,K*5F
字段0:$GPVTG,语句ID,表明该语句为Track Made Good and Ground Speed(VTG)地面速度信息
字段1:运动角度,000 - 359,(前导位数不足则补0)
字段2:T=真北参照系
字段3:运动角度,000 - 359,(前导位数不足则补0)
字段4:M=磁北参照系
字段5:水平运动速度(0.00)(前导位数不足则补0)
字段6:N=节,Knots
字段7:水平运动速度(0.00)(前导位数不足则补0)
字段8:K=公里/时,km/h
字段9:校验值
代码简要运行过程:
串口传入数据,将数据依次存入数组中,由typedef struct _nmea0183/* NMEA0183结构体对象 */ 来存中的2个结构体来分别存放数据解析状态与结果(typedef struct _gps_nmea)和 GPS数据区域,供上层应用调用(typedef struct _gps_data)。 将结构体指针和对应位字符传入函数unsigned char nmea_decode(NMEA0183* nmea, char c)进行解析。先对每个字符进行判断执行相应操作(详细查看主体函数释意和代码解析)代码使用时循环识别完一条消息后将以“ ,”为分割符,将每一段字符串存入字段域缓冲区。之后处理单个字段域数据,检验信息段是否完整无错,如果校验通过,则将解析得到的数据保存,并提供给用户调用typedef struct _gps_data的结构体数据 ,结构体中的数据根据传来的数据进行实时更新
主要函数释意
unsigned char nmea_decode(NMEA0183* nmea, char c);/* GPS数据解析 */
函数存入一个结构体指针,其中包含两个结构体,和一个选择对应数组的数,首先函数先判断指针是否为空指针,如果被控制成则结束运行,通过后执行下一步switch操作,在其中以逗号为分割字段域符号,以*执行判断当前字段偏移量是否小于字段数组的大小,然后将当前字段设置为终止符并调用static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata)函数,然后增加数据计数器重置偏移量,并根据当前字符是否是*,来设置,当前字段域的校验字符,当是$,意味着新的数据字段,信息传入将所有相关结构数据清零,为下一次接收数据做好准备,函数最后再保存质量与数据,更新校验和 ,最后都返回valid_sentence的值表示解码成功
static unsigned char nmea_term_complete(gps_nmea* pnmea, gps_data* pdata);/* 处理单个字段域数据 */
函数主要是通过,解析到完整的信息,然后,对字段域的字段进行switch选择执行,对vtg和gaa,rmc以及hdt进行选择将完成解析数据反馈出来,如果解析未通过,则返回 已接收gps信息但gps未定位的消息。函数前的字母id也可以是其他多个通话id接受任意两个字符,通过比较数组中的,字符串是否与相应解析字段的字符串相等,来执行对应的解析代码。解析数据时,以确保当前句子类型已知确保第1个解析类型存在,然后根据switch,去选择来解析相应的字段域数据,解析完成后把它复制给铁塔结构体中的数据,以方便用户调用。解析数据的方法判读主要以,协议中的关键字段信息加上字段域号,以字段域号来解析对应的来解析字段
static int sring_to_int(const char* pstr, unsigned char* b);/* 数字字符串处理函数,识别符号并且不检查溢 */
如果是小数,则只返回整数部分,如果转换出错,返回0 , 转换成功标志 0-错误 1-正确
笔记:
static关键字主要有以下含义
当static用于修饰函数内部的局部变量时,该变量称为静态局部变量。它的生命周期贯穿整个程序运行期间,而不是像普通局部变量那样在函数调用结束后被销毁。这意味着静态局部变量在函数调用之间保持其值,可用于记录函数调用之间的状态。static关键字在C语言中主要用于控制变量和函数的生命周期和作用域。对于局部变量,它可以使变量在函数调用之间保持其值;对于全局变量和函数,它可以限制它们的作用域,使其仅在定义它们的文件内部可见
解析的主要概括在于用户将捕捉的信息段或者数据,传入主函数中,主函数通过数据包的判读是否完整有效后,调用协议中的函数来进行解析,传入的参数将以分割符为标志,将每个字段分割后存储在数据缓冲区,解析时按照数据类型的名称和字断域号进行对分割的字段进行相应的解析算法的调用,然后将解析好的值赋值给结构体完成解析。