前言
在做项目中经常会遇到接收数据的情况,并且在实际的项目过程中,通常是对数据按帧进行接收。每帧数据的大小并不固定,传输数据的过程中,通常选择以连续的特殊字符回车、换行(0x0d和0x0a)作为一帧数据的结束标志,以此对接收各帧数据进行区分。接下来以串口接收数据为例进行讲解。
一、任务要求
通过串口接收一帧数据,数据总长度为66字节(其中有效数据长度为64字节,每帧数据以"0x0d"和"0x0a"作为结束标志,在有效数据部分不会出现特殊字符"0x0d"或"0x0a")。
二、实现代码
1.使用接收状态标记
我们通过串口中断对数据是按字节逐个接收的,每次中断只能接收一个字节数据。为完成任务,需要对接收的数据进行计数,记录下已接收数据的个数。需要注意,在接收的前64个字节数据中,特殊字符"0x0d"或"0x0a"均不得出现,如果检测出在有效数据部分出现特殊字符"0x0d"或"0x0a",则表明此帧数据出现错误,再继续接收已毫无意义。同时如果接收到的数据量已达到64字节,则接收的第65个字节的数据必须是"0x0d",接收的第66个字节的数据必须是"0x0a",否则也代表此帧数据出现错误。在编程中,为完成上述要求,我们可以定义多个变量,各个条件均有对应的变量作为标志,最后通过多个变量协助,完成任务。其实还有一种比较巧妙的方法,就是利用数据的对应的二进制位进行标记,这样只需一个变量就可完成多个变量的工作,使程序变得简洁。
我们定义一个16位的变量,作为数据的接收状态标记。接收状态标记的前14个位用于计数,第15位用于标记是否接收到"0x0d"(如已接收到"0x0d",则第15位置1),第16位用于标记此帧数据是否已接收完成(如已接收完此帧数据,则第16位置1)。
u8 Frame_REC_BUF[Frame_REC_LEN]; //存储串口接收的帧中数据
/*
帧数据接收状态标记:Frame_RX_STA
bit13~0,接收到的有效字节数目
bit14,接收到0x0d
bit15,接收完成标志
*/
u16 Frame_RX_STA=0; //帧数据接收状态标记
void USART1_IRQHandler(void){ //串口1中断服务程序
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){ //接收中断(接收到的数据必须是0x0d oxoa结尾)
Res =USART_ReceiveData(USART1);
if((Frame_RX_STA&0x8000)==0)
{//接收未完成
if(Frame_RX_STA&0x4000)
{//接收到了0x0d
if(Res!=0x0a)
Frame_RX_STA=0;//接收错误,重新开始
else
Frame_RX_STA|=0x8000; //接收已完成
}else
{ //还未接收到0X0d
if(Res==0x0d)
Frame_RX_STA|=0x4000;
else
{
Frame_REC_BUF[Frame_RX_STA&0X3FFF]=Res ; //将接收到的数据存入数组
Frame_RX_STA++; //数据长度计数加1
if(Frame_RX_STA>(Frame_REC_LEN-1))
Frame_RX_STA=0;//接收数据错误,重新接收
}
}
}
}
}
2.代码详解
下面将对代码中难点进行讲解。
代码中涉及一些接收状态标记(Frame_RX_STA)和16位数据的与、或操作,可能会让读者感觉眼花缭乱,难以理解,我们先将这些数据对应的二进制形式表示出来:
0x8000的二进制形式为: 1000 0000 0000 0000
0x4000的二进制形式为: 0100 0000 0000 0000
0X3FFF的二进制形式为: 0011 1111 1111 1111
接收状态标记Frame_RX_STA的二进制形式表示为:
Frame_RX_STA的二进制形式为:**** **** **** **** **** (*代表数字0或1)
下面就好理解了。
(1)Frame_RX_STA&0x8000:通过按位与操作,可对接收状态标记Frame_RX_STA中的第16位进行检测,只有第16位为1时,所得结果才不为0,进而获知帧数据是否接收完成。
(2)Frame_RX_STA&0x4000:通过按位与操作,可对接收状态标记Frame_RX_STA中的第15位进行检测,只有第15位为1时,所得结果才不为0,进而获知是否在串口中接收到”0x0d”
(3)Frame_RX_STA|=0x8000:通过按位或操作,可将接收状态标记Frame_RX_STA中的第16位进行置位为1,而其他位保持原有数据不变,进而标记接收一帧数据已完成。
(4)Frame_RX_STA|=0x4000:通过按位或操作,可将接收状态标记Frame_RX_STA中的第15位进行置位为1,而其他位保持原有数据不变,进而标记已接收到”0x0d”。
(5)Frame_RX_STA&0X3FFF:通过按位与操作,可将接收状态标记Frame_RX_STA中的第15位和第16位数据置0,而前14位数据(bit0~bit13)保持原有数据不变,所得结果便为已接收的数据量。进而可获知串口接收数据的数量。
总结
通过上面详细的讲解,详细大家都对如何进行逐帧接收数据有了比较深入的理解,继续加油啊。
注:相关代码已上传(可免积分下载,大家自行领取)下载代码,请点击此处