初出茅庐的小李博客之串口数据解析

介绍

串口通信是单片机中最常见的通信方式之一,最近有个需求需要解析上位机发来的数据,简单记录一下解析的思路跟过程。

串口协议如下

通讯协议中各参数说明:

1. Head(包头):
固定占一个字节、固定为 0X1E(回传的 Head 与发送的 Head 相同);
2. PktLenH(包长度高 8 位):
固定占一个字节、包长度高 8 位,本文所述的包长度指整 个包的所有字节数(从第一位包头到最后一位校验位的所有字节个数);(若 DATA 为 空、那么包长度值为 8,若 DATA 为 10个数据、那么包长度值为 18) ;
3. PktLenL(包长度低 8 位):
固定占一个字节、包长度低 8 位;
4.Mod1:
固定占一个字节(回传的 Mod1 与发送的 Mod1 相同)、Mod1 的定义如下: 暂时固定为0X0B: 系统及功能
5. Mod2:
固定占一个字节(回传的 Mod2 与发送的 Mod2 相同)、固定为 0X00;
6. FLAG:
固定占一个字节、包状态主动被动标志位、FLAG 的定义如下: 0XFF: 主动标志,表示这条指令是上位机往模块发数据 (如果是上位机往模块发数据,这个 FLAG 值必须固定为 0XFF) 0X01: 被动标志,代表模块往上位机回传正确 0X05:
被动标志,代表上位机下发的包校验位计算出错或上位机发送了本模块不 支持的指令或其它非法错误 (如输入的数据格式不对等等)
(如果是模块往上位机回传数据、被动标志 FLAG 值可能为 0X01 或 0X05,0X01 代表 正确,0X05提示上位机下发的数据非法)
7. CMD:
命令字(回传的 CMD 与发送的 CMD 相同)、占一个字节; 详见本文件后续具体描述 (不同的命令有不同的 CMD)
8. DATA:
数据域,字节数不固定、可以是发送数据域或者回传数据域
a. 数据域中可以有数据也可以没有数据(具体会在每条 CMD 中详细说明)
b. 计算包的数据域的个数可通过“ (PktLenH<<8 + PktLenL) – 8 ”来计算
9. Chksum:
占一个字节、校验位为包的所有数据校验和(高八位溢出、取低八位即可 得到校验和),校验算法参考附录 1;

校验算法(累加和校验算法)

检验和算法参考程序
unsigned char GetCheckSum(unsigned char *pbuffer, unsigned short len)
{
unsigned char tmp = pbuffer;
unsigned char ucSum = 0;
while (len–)
{
ucSum += (
(tmp++));
}
return (ucSum);
}

备注说明:
本通讯协议包中固定不变的参数为:
包头(1 个字节) + 包长度高 8 位(1 个字节) + 包长度低 8 位(1 个字节) + Mod1(1 个字节) + Mod2(1 个字节) + Flag(1 个字节) + Cmd(1 个字节) + Chksum (1 个字节) = 8 个字节;

解析思路

  1. 先判断帧头是否符合
  2. 再判断字节数目是否合理
  3. 判断校验
    3.1 当校验通过了再判断固定字节跟标志位
    3.2. 解析指令
    3.3. 解析数据

代码记录

int8_t Parse_info(uint8_t  RevBuf[])
{
  uint16_t Buff_Size = 0;
	uint8_t Temp[100] = {0};
	uint8_t Check = 0;
	uint16_t Data_Len = 0;
	uint16_t i = 0;
	if(RevBuf[0] == 0x1E)//帧头
	{
			Buff_Size = RevBuf[1]<<8 | RevBuf[2];
		  printf("收到的字节数是:%02X\r\n",Buff_Size);
			if(Buff_Size>=8)
			{
					Data_Len = Buff_Size - 8;
					printf("收到数据字节个数是:%d \r\n",Data_Len);
					for(i=0;i<Buff_Size;i++)
					{
						Temp[i] = RevBuf[i];
						printf("Temp[%02d]  =  %02X\r\n",i,Temp[i]);
					}
					printf("收到校验结果: %02X\r\n",Temp[Buff_Size-1]);
					Check  = GetCheckSum(Temp,Buff_Size-1);
					printf("计算校验结果: %02X\r\n",Check);
					if(Temp[Buff_Size-1] == Check )
					{
							printf("计算校验结果:通过\r\n");
							if(Temp[3] == 0x0B)
							{
								printf("Mod1标志校验通过: %02X\r\n",Temp[3]);
							}
							else
							{
								return 0x05;//上位机数据非法
							}
							if(Temp[4] == 0x00)
							{
								printf("Mod2标志校验通过: %02X\r\n",Temp[4]);
							}
							else return 0x05;//上位机数据非法
							if(Temp[5] == 0xFF)
							{
								printf("主动标志校验通过: %02X\r\n",Temp[5]);
							}
							else return 0x05;//上位机数据非法
							switch(RevBuf[6])
							{
								 case 0x01:
								 printf("上位机发的指令是: %02X\r\n",RevBuf[6]);
								 printf("执行打开某个GPIO功能\r\n");
								 break;
								 case 0x02:
								 printf("上位机发的指令是: %02X\r\n",RevBuf[6]);
								 printf("执行关闭某个GPIO功能\r\n");
								 break;
								 case 0x11:
								 printf("上位机发的指令是: %02X\r\n",RevBuf[6]);
								 printf("解析时间,回应心跳功能\r\n");
								 printf("上位机发的时间是:%02X%02X-%02X-%02X %02X:%02X:%02X",
								 Temp[7],Temp[8],Temp[9],Temp[10],Temp[11],Temp[12],Temp[13]);
								 break;
							}	
					}
					else
					{
						printf("校验和不通过\r\n");
						return 0x05;//上位机数据非法
					}	
				}
			  else
				{
						printf("字节数检查不通过\r\n");
						return 0x05;//上位机数据非法
				}					
	 }
	 else
	 {
		 printf("帧头校验不通过\r\n");
	  return 0x05;//上位机数据非法
	 }
		
}

  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值