【串口按帧接收数据】


前言

在做项目中经常会遇到接收数据的情况,并且在实际的项目过程中,通常是对数据按帧进行接收。每帧数据的大小并不固定,传输数据的过程中,通常选择以连续的特殊字符回车、换行(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的二进制形式为:**** **** **** **** **** (*代表数字01) 

在这里插入图片描述

下面就好理解了。
(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)保持原有数据不变,所得结果便为已接收的数据量。进而可获知串口接收数据的数量。


总结

通过上面详细的讲解,详细大家都对如何进行逐帧接收数据有了比较深入的理解,继续加油啊。
注:相关代码已上传(可免积分下载,大家自行领取)下载代码,请点击此处

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值