简单理解一下正点原子的串口通讯的协议代码,代码如下
void USART1_IRQHandler(void)
{
u8 res;
u16 USART_RX_STA=0; //接收状态标记
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节
if(USART1->SR&(1<<5)) //接收到数据
{
res=USART1->DR; //接受到的数据给临时变量
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}else //还没收到0X0D
{
if(res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=res;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
首先声明两个全局变量,1、extern u8 USART_RX_BUF[USART_REC_LEN]
,其中USART_REC_LEN
为宏定义的最大字节数,USART_RX_BUF
数组为数据接受缓冲器,将一次协议过程接受到的数据放入此数组,可用于主函数调用分析。2、extern u16 USART_RX_STA
为接受状态标记,此变量为16位。当接受到的一个数据0x0d时bit14置1。当bit14为1且接受到的下一个数据为0x0a时,bit15置1,此时即可认为完成了一次通讯协议。
bit15 | bit14 | bit13~0 |
---|---|---|
接受完成标志 | 接受预完成标志 | 接受有效数据个数 |
0x0a(ASCII码中的换行符) | 0x0d(ASCII码中回车符) | 最多16382个字节 |
临时变量u8 res
用于存放接受到的每个数据。
if(USART1->SR&(1<<5))
即每接收到一个字节就产生中断,把每个字节进入协议分析。
if((USART_RX_STA&0x8000)==0)
“接受完成标志位“”为0也即未完成数据接收,那么进入协议,若此位为1则表面已经完成一次协议跳过之后分析,当主函数完成相应功能后,需要再次接收数据时置0。
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
“接受预完成标志“为0则是还在正常接收数据中,即继续进行协议。若“接受预完成标志“为1,则是已经接收了0x0d,那么判断这次接收到的数据是否为0x0a,若不是那么说明数据接收发生错误,至此重新接收,将数据重头放入缓冲数据接收器覆盖之前的数据。若这次接收的数据是0x0a,那么接收完成标志置1,代表此次协议完成。
if(res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=res;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
若接收到的数据为0x0d则将“接受预完成标志“置1之后等待接收下一个字节。若接收到的数据不是0x0d则此数据为有效数据,将它放入“数据缓冲器“,[USART_RX_STA&0X3FFF]
代表这是接收的第n个数据。if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
当接收到超过设置的最大字节数,代表接收错误则重新开始接收。
最后简单总结一下:每接收到一个字节便产生中断,将此接收到的数据进行协议分析,接收到的有效数据放入接收缓冲器(这是声明的外部数组),并且给USART_RX_STA
即接受状态标志位加1,USART_RX_STA
的0~13位代表这是接受到的第几个数据,若接收到的数据是0x0d则将bit14置1,此数据不是有效数据,有效数据位不会增加。之后的情况1、若下一个接收的数据是0x0a,则将bit15置1且代表此协议完成,在bit15未置0之前不再接收数据2、若下一个接收的数据是不是0x0a,则代表此次数据传输错误,则将USART_RX_STA
清0,再次重新接收数据。
注意:
1、每次正常传输的数据必须以0x0d,0x0a为结尾
2、接收完成标志位也即USART_RX_STA
第15位必须由主函数置0,在置0前不会再接收到数据
3、传输了0x0d未传输0x0a和传输的字节数超过设定数目都会发生传输错误,这会导致重新接收数据且重新的数据又从0开始覆盖接收缓冲器数组里(即之前的数据会被覆盖)
4、USART_RX_STA
和USART_RX_BUF[USART_REC_LEN]
必须声明外部变量才能在主函数使用
此协议可获得:
1、接收到了多少个字节的数据(也即USART_RX_STA
里0~13bit的数量,在主函数可通过USART_RX_STA&0x3FFF
表示)
2、接收到的数据(存放在接收缓冲器数组里,在此代码里为USART_RX_BUF[USART_REC_LEN]
,可在主函数里通过此数组进行处理)