NMEA报文解析程序(c语言)-读报文
程序员文章站
2022-07-12 21:56:58
...
开发工具:DEV
NMEA协议基础知识可参见:GPS理论知识NMEA 0813协议
为完成课程设计而参照网上例子,按照课程要求修改而来
1、在搜集资料过程中发现网上很多都不完整,而且有的会有很多小错误,无法有效运行,自己调试后做了一些修改,能成功运行。
2、因为是上个学期的作业,有些细节不太记得了,但是代码里有修改的地方我都有注释,大家可以参照这些代码段根据自己的需求构建程序。
3、完整工程可以私信我,留下邮箱,看到就会第一时间发送。
4、有错误的地方也希望大家能够指正。
系列一:读报文
//若要查看读取报文的条数,可以在该函数外部定义一个计数变量,在函数内部做自加
//每读一次计数器就加1,注意:不能在函数内部定义,若定义以为内部局部变量则函数每执行一次都会清零计数器
while(fgets(buf,256,fpr) != NULL)/*读取直至文件结束,返回所有命令*/
{
if ((head = strstr(buf, "$"))||(segm == 1))/*NMEA命令起始判定//起始符*/
{
if (head != NULL)
{
strcpy(buf, head);
strcpy(tep,"\0");/*字符串清空处理*/
}
//字符串超长可以再接着收,但如果是错误报文就要丢弃
tail = strstr(buf, "*");
if(!tail)/*断句命令判定//结束符*/
{
//若未找到结束符,则判断是否超长了
segm = 1;
len = strlen(buf);
buf[len-1] = '\0';
strcat(tep, buf);
if(strlen(tep) >= 128)/*命令长度超常越界判定*/
{
segm = 0;
strcpy(tep, "\0");/*字符串清空处理*/
}
}
else
{
segm = 0;
*(tail + 3) = '\0'; //*后面还有两字节校验和数字
strcat(tep, buf); //至此,tep里面得到的就是含完整报文代码的字符串(含$,*,校验和 ,\0
//文本输出语句,有天线检测硬件功能的模块会输出此语句$GNTXT
//天线状态:连接,断路,短路
//文本输出语句反映的是天线连接状态,无位置信息,因此可以丢弃
if(strnstr(tep, "$GNTXT", 6))
{
strcpy(tep, "\0");/*字符串清空处理*/
continue;
}
//校验和字段
if(!NMEA_Checkout(tep))/*有效命令校验值判定*/
{
strcpy((char*)dat,"\0");/*字符串清空处理*/
strcpy(tmp,"\0");/*字符串清空处理*/
strcpy(tep,"\0");/*字符串清空处理*/
}
else//校验成功
{
sign = Package(tep);/*检测封包标志*/
if(sign)
{
if(sign == 1) //同数据包
{
//dat的defination: static u8 dat[512]="\0";
//不清楚dat要把每次同的报文cat在一起的用途
//个人觉得可以将同数据包报文信息的处理删除
strcat((char*)dat, tep);
strcat((char*)dat, "\n");//至此,dat里面得到的就是含完整报文代码的字符串(含$,*,校验和,\0,\n
strcpy(tmp, "\0");/*字符串清空处理*/
strcpy(tep, "\0");/*字符串清空处理*/
}
else/*sign == 2*/
{
strcpy(tmp,"\0");
strcat(tmp, tep);
strcat(tmp,"\n"); //至此,tmp里面得到的就是含完整报文代码的字符串(含$,*,校验和,\0,\n
// Buf = (u8*)dat;
//tmp里才有数据,因此改正为 Buf = (u8*)tmp;
Buf = (u8*)tmp;
if(*Buf != '\0')
{
while (*Buf != '\0')
{
//能够处理的所有报文种类
Buf = NMEA_GPZDA_Analysis(Res, Buf);
Buf = NMEA_GPGGA_Analysis(Res, Buf);
Buf = NMEA_GPGLL_Analysis(Res, Buf);
Buf = NMEA_GPVTG_Analysis(Res, Buf);
Buf = NMEA_GPGSA_Analysis(Res, Buf);
Buf = NMEA_GPGSV_Analysis(Res, Buf);
Buf = NMEA_GPRMC_Analysis(Res, Buf);
}
if((Res->utc.date != 0)&&(Res->utc.month != 0)&&(Res->utc.year != 0))/*日期信息有效*/
{
if(((Res->avhemi) == avhemi_) || (avhemi_ == 'C'))/*输入条件判断*/
{
if(((Res->speed) >= speed_) && ((Res->svnum) >= svnum_))
{
printout(Res,sn_,fpw); //将符合筛选条件的报文中的信息写进文件中
}
}
}
memset(Res, 0, sizeof(Nmea_msg)); //清空该条报文中的所有信息
}
strcpy((char*)dat, "\0");
strcat((char*)dat, tmp);//至此,该条新报文就处理完了
//至此,dat里面得到的就是含完整报文代码的字符串(含$,*,校验和,\0,\n
} //若是老报文,重复的数据就不用在比较和写进结果文件里了
}
else
{
strcpy((char*)dat,"\0");
strcpy(tmp, "\0");/*字符串清空处理*/
strcpy(tep, "\0");/*字符串清空处理*/
}
}//校验成功的数据处理完毕
}
}
else
continue;
}
自己画了个大概的流程图
上一篇: Vue数据双向绑定原理