usart文件夹内包含了usart.c和usart.h两个文件。这两个文件用于串口的初始化和中断接收。这里只是针对串口1,比如你要用串口2或者其他的串口,只要对代码稍作修改就可以了。usart.c里面包含了2个函数一个是void
USART1_IRQHandler(void);另外一个是void uart_init(u32 pclk2,u32
bound);里面还有一段对串口printf的支持代码,如果去掉,则会导致printf无法使用,虽然软件编译不会报错,但是硬件上STM32是无法启动的。这段代码不要去修该。
void USART1_IRQHandler(void)函数是一个串口1中断响应函数,当串口1发生了相应的中断后,就会跳到该函数执行。这里我们设计了一个小小的接收协议:通过这个函数,配合一个数组USART_RX_BUF[64],一个接收状态寄存器USART_RX_STA实现对串口数据的接收管理。USART_RX_BUF的最大值为64,也就是一次接收的数据最大不能超过64个字节。USART_RX_STA是一个接收状态寄存器其各的定义如下表:
USART_RX_STA
|
bit7
|
bit6
|
bit5
|
bit4
|
bit3
|
bit2
|
bit1
|
bit0
|
接收完成标志
|
接收到0X0D标志
|
接收到的有效数据个数
|
表2.7.2.2接收状态寄存器位定义表
设计思路如下:
当接收到从电脑发过来的数据,把接收到的数据保存在USART_RX_BUF中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(0X0D,0X0A)的第一个字节0X0D时,计数器将不再增加,等待0X0A的到来,而如果0X0A没有来到,则认为这次接收失败,重新开始下一次接收。如果顺利接收到0X0A,则标记USART_RX_STA的第七位,这样完成一次接收,并等待该位被其他程序清除,从而开始下一次的接收,而如果迟迟没有收到0X0D,那么在接收数据超过64个了,则会丢弃前面的数据,重新接收。函数代码如下:
/ #ifdef EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[64]; //接收缓冲,最大64个字节.
//接收状态
//bit7,接收完成标志
//bit6,接收到0x0d
//bit5~0,接收到的有效字节数目
u8 USART_RX_STA=0; //接收状态标记
void USART1_IRQHandler(void)
{
u8
res;
if(USART1->SR&(1<<5))//接收到数据
{
res=USART1->DR;
if((USART_RX_STA&0x80)==0)//接收未完成
{
if(USART_RX_STA&0x40)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else
USART_RX_STA|=0x80; //接收完成了
}else
//还没收到0X0D
{
if(res==0x0d)USART_RX_STA|=0x40;
else
{
USART_RX_BUF[USART_RX_STA&0X3F]=res;
USART_RX_STA++;
if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
#endif
从上面的代码我们可以看使用了宏定义#ifdef,当需要使用串口接收的时候,我们只要在usart.h里面定义EN_USART1_RX就可以了。不使用的时候,注释掉就可,这样可以省出部分sram和flash。
void uart_init(u32 pclk2,u32
bound)函数是串口1初始化函数。该函数有2个参数,第一个为pclk2,是系统的时钟频率。第二个参数为需要设置的波特率,例如9600,115200等。而这个函数的重点在与设置波特率。在《STM32参考手册》的第480页,24.4.4一节有详细介绍波特率的计算方式。这里我们不再详细介绍。uart_init在不同pclk2频率下初始化的不同波特率有些会存在误差,具体可以参考《STM32参考手册》的第481页的表154。需要注意的是这里初始化的串口都是按8位数据格式,1位停止位,无奇偶校验位的。具体代码如下:
//初始化IO 串口1
//pclk2 CLK2时钟频率(Mhz)
//bound:波特率
void uart_init(u32 pclk2,u32
bound)
{
float
temp;
u16
mantissa;
u16
fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp; //得到整数部分
fraction=(temp-mantissa)*16;
//得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
RCC->APB2ENR|=1<<14; //使能串口时钟
GPIOA->CRH=0X444444B4;//IO状态设置
RCC->APB2RSTR|=1<<14; //复位串口1
RCC->APB2RSTR&=~(1<<14);//停止复位
//波特率设置
USART1->BRR=mantissa; // 波特率设置
USART1->CR1|=0X200C; //1位停止,无校验位.
#ifdef EN_USART1_RX //如果使能了接收
//使能接收中断
USART1->CR1|=1<<8; //PE中断使能
USART1->CR1|=1<<5; //接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级
#endif
}
|