stm32串口接收程序 分帧处理
接收程序是所有单片机入门教程的必经之路,但是很多教程和例程只讲了如何去接收一个8位的字符数据,但实际操作时我们常常需要接收的是各式各样的数据帧,这一章主要介绍如何去进行分帧操作。
采用状态机的分帧方式
采用状态机的方式可以完成目前绝大多数的串口数据的分帧操作。
目前比较常用的数据帧格式由帧头,数据帧种类,数据帧长度,数据帧内容,帧尾,校验码等部分组成,像一些毫米波雷达、激光雷达等模块的数据帧都采用这种方式我们以一款简单的miniMPU模块为例进行分帧处理。
miniMPU的返回的数据帧有两种一种是接收的原始数据、如三轴加速度、大气压等,另一种是经过处理后的计算数据如俯仰角等。数据帧示例如下A55A12A1……78B4。
其中A55A为数据帧的帧头;12为数据帧的长度即0X12=18;A1代表接收的是第一种数据。……代表采集到的数据,按说明书解析即可,78为数据的校验码,计算方式为将……部分采集到的所有数值相加最后的8位字符即为校验码,B4为帧尾。
分帧操作的代码如下
void USART1_IRQHandler(void) //串口1中断服务程序
{
static u8 states = 0;//状态机状态码
static u8 i=0;//二维数组的第一个参数
static u8 j=0;//二维数组的第二个参数
static u8 check=0;//校验码
static strlen=0;//本次接收数据帧的长度
u8 res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的8位字符
switch(states)
{
case 0://case 0,1判断是否收到帧头,如果是,接收数据长度,否,继续等待帧头。
if(res == 0xA5)
{
i=0;
j=1;
USART1_RX_BUF[0][0]=0;//第一位为标志位,为0代表改数据为有误数据或未接收完成,为一代表可用
USART1_RX_BUF[1][0]=0;
check=0;
states = 1;
}
break;
case 1:
if(res == 0x5A)
{
states = 2;
}
else
states = 0;
break;
case 2://接收数据长度,如果长度异常,放弃这帧数据返回状态1等待下一帧数据
states = 3;
if(res>10&&res<50)
{
strlen=res;
}
else
states = 0;
break;
case 3://判断接收数据帧种类,如果异常放弃这帧数据
states = 4;
if(res==0xA1)
{
i = 0;
}
else if(res==0xA2)
{
i = 1;
}
else
states = 0;
break;
case 4://接收其余的数据并判断数据是否正常
USART1_RX_BUF
[j]=res;
j++;
if(j>strlen-2)//由于并没有接收数据长度位和数据种类位所以需要-2,具体长度根据接收的数据帧格式和代码进行修改,不可照抄。
{
for(j=0;j
{
check=check+USART1_RX_BUF[j];//按照数据帧说明计算校验码,不可照抄
}
if(USART1_RX_BUF[strlen-4]==check)//验证校验码是否正确
{
if(USART1_RX_BUF[strlen-3]==0xB4)//验证数据帧结尾是否正确
{
USART1_RX_BUF[0]=1;//接收完成,数据帧正常
}
}
states = 0;//返回状态0等待下一帧数据
}
}
break;
}
}
USART_ClearFlag(USART1,USART_FLAG_TC);
}
接收结束的二维数组USART1_RX_BUF中数组USART1_RX_BUF[0]接收的第一种数据,USART1_RX_BUF[1]接收的第二种数据,每个数组的第一位为接收状态(0为错误,1为接收完成)其余位位接受到的具体数值。
代码请思考修改后在使用,勿直接照抄。代码逻辑上可能还存在一些bug希望各位大佬多多指教。
觉得还不错的化记得点赞啊