1、使用串口1(USART1)来通信
2、解读例程的中断服务函数
void USART1_IRQHandler(void) //串口1中断响应程序 其名字不能随便定义
{
u8 Res; //当串口接收到数据 RXNE将被置1
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾) RESET是0
{ //该函数是获取串口的控制器CR1,CR2,CR3的状态
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据 一个字节一个字节的读
if((USART_RX_STA&0x8000)==0)//接收未完成 10000 0000 0000 0000 0x8000 当接受完成时,最高位置1
{ //0xxx xxxx xxxx xxxx 未接受完成是初始值0
if(USART_RX_STA&0x4000)//接收到了0x0d 0100 0000 0000 0000 0x40000
{ //x1xx xxxx xxxx xxxx 当接受到0x0d时,USART_RX_STA的14位会置1
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++; //长度+1 为下一次做准备
if(USART_RX_STA>(USART_REC_LEN-1))
{
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
}
这里定义了一个16位数据USART_RX_STA 来表示 采集的数据长度数据,状态等,相当于一个寄存器
USART_RX_STA 15 14 13-0
接收完成 接收到0x0d 接收的数据长度 没接收加1 表示多了一个字节
USART_RX_STA=0 则为接收数据做准备
//串口进入中断的前提是 数据的最后以回车为准 即 0x0d 0x0a 0x0d是回车的ASCLL码,0x0a是换行的ASCLL码
TStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);固件库提供的串口收发的标志位函数之一
该函数是获取串口的控制器CR1,CR2,CR3的状态;信息如下
理解一下RXNE接受中断与IDLE空闲总线中断的区别
单片机串行口是发送或接收完一帧数据才进入中断的,一次发来的数据,就称为一帧数据,空闲总线中断,串口收到一帧数据后,发生的中断。比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据。STM32单片机带IDLE中断,一帧数据结束后,产生IDLE中断,利用这个中断来接收不定长的数。(产生IDLE中断后 以帧为单位进行判断)当接收到1个字节,就会产生RXNE中断,当接收到一帧数据,就会产生IDLE中断。比如给单片机一次性发送了8个字节,就会产生8次RXNE中断,1次IDLE中断
①当有数据来时RXNE被置1,RESET定义了为0,当有数据来时,中断产生,RXEN为1,不等于0,if语句成立。
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
②将USART1的数据寄存器DR的值赋给res
Res =USART_ReceiveData(USART1);
③这时判断一下是否接受数据完成。 回顾一下之前定义的USART_RX_STA,最高位(15位)接受到0x0a会置1,因为还没接受完成,USART_RX_STA还是0(初始化为0),即
0000 0000 0000 0000
&1000 0000 0000 0000 = 0
if((USART_RX_STA&0x8000)==0) if语句成立
④再判断是否接受了0x0d 0x0d会将USART_RX_STA的14位置1
0000 0000 0000 0000
&0100 0000 0000 0000 = 0
if(USART_RX_STA&0x4000) if语句是假,执行else里的语句
{
if(Res==0x0d)
{
USART_RX_STA|=0x4000; //接收到回车的前一字节 置位状态寄存器
}
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; //将接收的数据 存入数组中
USART_RX_STA++; //长度+1 为下一次做准备
if(USART_RX_STA>(USART_REC_LEN-1))
{
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
⑤数据还没接受完,继续执行else里的语句
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; //将接收的数据 存入数组中
USART_RX_STA++; //长度+1 为下一次做准备
if(USART_RX_STA>(USART_REC_LEN-1))
{
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
USART_RX_STA&0X3FFF 0000 0000 0000 0000
&0011 1111 1111 1111 = 0 将Res接受的数据(一个u8类型字符数据)存放在数据USART_RX_BUF[0] 里
继续执行USART_RX_STA++; 一开始定义的USART_RX_STA是16位的整型数,并初始化位0,这时加1
⑦USART_RX_STA>(USART_REC_LEN-1)为什么要-1,因为定义的buff是200个字节,而数组的下标是0开始计算到199,而STA的值就是数组的下标,最后一次将数据存入到buff里时,执行USART_RX_STA++后USART_RX_STA等于200时已经超过数组范围。例如,我从0开始计算,一次发(0-199)这么多字符的数据(共有200个字符),第200个字符数是0x0d,当存入到199时是,STA的值是200,这时第200个字符是0x0d,就不会执行将res存入buff的语句
⑧如果Res等于0x0d,执行USART_RX_STA|=0x4000;
00xx xxxx xxxx xxxx xxxx
| 0100 0000 0000 0000 0000 将第14位置1.
⑨0x0d下一位是0x0a,那么res= 0x0a,然后执行USART_RX_STA|=0x8000;将第15位置1
if((USART_RX_STA&0x8000)==0)为假,结束函数。
最后0x0a是最后一个字节,RXNE是0。if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)语句为假,结束函数
这时buff里是我们输入的数据