一、首先上代码,正点原子的串口中断服务函数如下
#define USART_REC_LEN 200 //定义最大接收字节数 200
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
u16 USART_RX_STA=0; //接收状态标记
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
void USART1_IRQHandler(void)//串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
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;//接收数据错误,重新开始接收
}
}
}
}
}
可以看到代码后面虽然都有注释,但是初看起来还是比较绕的,下面对其运行逻辑简单介绍下。
一、0d0a是什么意思,以及由来
我们打开原子给的串口调试助手,勾选“发送新行”,然后点击发送,如下图可以看到TX:0D0A,所以0d0a代表的是回车和换行。串口调试助手发送的数据不分大小写。
二、USART_RX_STA代表的意思
USART_RX_STA是定义的一个16位接收状态寄存器,其结构如下:
bit15 | tin14 | bit13-0 |
---|---|---|
接收完成标志 | 接受到了0x0d | 接收到的有效数据个数 |
所以可以通过读USART_RX_STA
来判断数据是否发送完全,以及数据有多少个
三、USART_RX_BUF和USART_REC_LEN
USART_RX_BUF[]表示的是缓存数据
USART_REC_LEN表示最大缓存数据个数
四、串口接收数据步骤,假如接受到的数据是0x11 0x22 0x33
首先进入串口中断,数据是一个一个读取的,第一个数据0x11
来了
Res =USART_ReceiveData(USART1); //读取接收到的数据
此时Res =0x11
,USART_RX_STA=0
然后进行第一个判断,USART_RX_STA&0x4000
等效于0000 0000 0000 0000&0x0100 0000 0000 0000
等效于0
,所以应该执行下图中的oooo
语句
if(USART_RX_STA&0x4000)//接收到了0x0d
{
xxxx
}
else //还没收到0X0D
{
oooo
}
然后进行第二个判断,从上面的分析可知,Res ==0x11
,所以要执行else
里面的语句,首先USART_RX_STA&0X3FFF
等效于0000 0000 0000 0000&0011 1111 1111 1111
等效于0
,即USART_RX_BUF[0]=Res
,即USART_RX_BUF[0]=0x11
至此我们将第一个数据0x11保存至数组USART_RX_BUF[0]中
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;//接收数据错误,重新开始接收
}
}
然后执行USART_RX_STA++
,即USART_RX_STA
变为0+1
为1
。然后执行最后一个判断if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
,由于,USART_REC_LEN-1
等效于(200-1)为199
,而USART_RX_STA==1
,所以这个判断为假,后面的USART_RX_STA=
不会执行。
至此串口中断服务函数执行完毕,其实只执行了下图框框里面的函数。
Res==0x11
USART_RX_BUF[0]==0x11
USART_RX_STA==1
—————————————————————————————
然后第二个数据0x22
来了,Res =0x22
,USART_RX_STA=1
,然后进行第一个判断,USART_RX_STA&0x4000
等效于0000 0000 0000 0001&0x0100 0000 0000 0000
等效于0
,所以应该执行下图中的oooo
语句
if(USART_RX_STA&0x4000)//接收到了0x0d
{
xxxx
}
else //还没收到0X0D
{
oooo
}
然后进行第二个判断,从上面的分析可知,Res ==0x22
,所以要执行else
里面的语句,首先USART_RX_STA&0X3FFF
等效于0000 0000 0000 0001&0011 1111 1111 1111
等效于1
,即USART_RX_BUF[1]=Res
,即USART_RX_BUF[1]=0x22
至此我们将第二个数据0x22保存至数组USART_RX_BUF[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;//接收数据错误,重新开始接收
}
}
然后执行USART_RX_STA++
,即USART_RX_STA
变为1+1
为2
。然后执行最后一个判断if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
,由于,USART_REC_LEN-1
等效于(200-1)为199
,而USART_RX_STA==2
,所以这个判断为假,后面的USART_RX_STA=
不会执行。
至此串口中断服务函数执行完毕,其实只执行了下图框框里面的函数。
Res==0x22
--------有变化
USART_RX_BUF[1]==0x22
--------有变化
USART_RX_STA==2
--------有变化
—————————————————————————————
然后第三个数据0x33
来了,Res =0x33
,USART_RX_STA=2
,然后进行第一个判断,USART_RX_STA&0x4000
等效于0000 0000 0000 0010&0x0100 0000 0000 0000
等效于0
,所以应该执行下图中的oooo
语句
if(USART_RX_STA&0x4000)//接收到了0x0d
{
xxxx
}
else //还没收到0X0D
{
oooo
}
然后进行第二个判断,从上面的分析可知,Res ==0x33
,所以要执行else
里面的语句,首先USART_RX_STA&0X3FFF
等效于0000 0000 0000 0010&0011 1111 1111 1111
等效于0000 0000 0000 0010
等效于十进制的2
,即USART_RX_BUF[2]=Res
,即USART_RX_BUF[2]=0x33
至此我们将第三个数据0x33保存至数组USART_RX_BUF[2]中
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;//接收数据错误,重新开始接收
}
}
然后执行USART_RX_STA++
,即USART_RX_STA
变为2+1
为3
。然后执行最后一个判断if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
,由于,USART_REC_LEN-1
等效于(200-1)为199
,而USART_RX_STA==3
,所以这个判断为假,后面的USART_RX_STA=
不会执行。
至此串口中断服务函数执行完毕,其实只执行了下图框框里面的函数。
Res==0x33
--------有变化
USART_RX_BUF[2]==0x33
--------有变化
USART_RX_STA==3
--------有变化
—————————————————————————————
五、数据发送完毕,发送回车和换行
数据发送完毕后会发送回车和换行,即0x0d
和0x0a
,
首先回车符0x0d
来了,Res =0x0d
,USART_RX_STA=3
,然后进行第一个判断,USART_RX_STA&0x4000
等效于0000 0000 0000 0011&0x0100 0000 0000 0000
等效于0
,所以应该执行下图中的oooo
语句
if(USART_RX_STA&0x4000)//接收到了0x0d
{
xxxx
}
else //还没收到0X0D
{
oooo
}
然后进行第二个判断,从上面的分析可知,Res ==0x0d
,所以要执行USART_RX_STA|=0x4000
即0000 0000 0000 0011|0100 000 0000 0000
即0100 0000 0000 0011
,所以此时USART_RX_STA==0100 0000 0000 0011==0x4003
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;//接收数据错误,重新开始接收
}
}
至此串口中断服务函数执行完毕,其实只执行了下图框框里面的函数。
Res==0x0d
--------有变化
USART_RX_BUF[2]==0x33
--------没变化
USART_RX_STA==0x4003
--------有变化
—————————————————————————————
然后换行符0x0a
来了,Res =0x0a
,USART_RX_STA=0x4003
,然后进行第一个判断,USART_RX_STA&0x4000
等效于0100 0000 0000 0011&0x0100 0000 0000 0000
等效于0100 0000 0000 0000
等效于0x4000
为真,所以应该执行下图中的xxxx
语句
if(USART_RX_STA&0x4000)//接收到了0x0d
{
xxxx
}
else //还没收到0X0D
{
oooo
}
然后进行第二个判断,从上面的分析可知,Res ==0x0a
,所以要执行USART_RX_STA|=0x8000
即0100 0000 0000 0000|1000 000 0000 0000
即1100 0000 0000 0000
,所以此时USART_RX_STA==1100 0000 0000 0000==0xB000
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
至此串口中断服务函数执行完毕,其实只执行了下图框框里面的函数。
Res==0x0a
--------有变化
USART_RX_BUF[2]==0x33
--------没变化
USART_RX_STA==0xB000
--------有变化
—————————————————————————————
至此,所有的数据包括停止数据都发送完毕,分为普通数据和标志
三个数据:0x11、0x22、0x33
两个停止的标志:0x0d、0x0a
Res | USART_RX_STA | USART_RX_BUF[ ] | |
---|---|---|---|
发送0x11 | Res =0x11 | USART_RX_STA=1 | USART_RX_BUF[0]=0x11 |
发送0x22 | Res =0x22 | USART_RX_STA=2 | USART_RX_BUF[1]=0x22 |
发送0x33 | Res =0x33 | USART_RX_STA=3 | USART_RX_BUF[2]=0x33 |
发送0x0d | Res =0x0d | USART_RX_STA=0x4003 | / |
发送0x0a | Res =0x0a | USART_RX_STA=0xB003 | / |