1、介绍
该文件夹有 usart.c 和 usart.h 两个文件。 作用:件用于串口的初始化和中断接收。 usart.c里面包含了2个函数:void USART1_IRQHandler(void);和void uart_init(u32pclk2,u32 bound); 里面还有一段对串口 printf 的支持代码。如果去掉,则会导致 printf 无法使用,虽然软件编译不会报错,但是硬件上 STM32F4 是无法启动的,这段代码不要去修改。
2、USART1_IRQHandler 函数
void USART1_IRQHandler(void)函数是串口1的中断响应函数,当串口1发生了相应的中断后,就会跳到该函数执行。 这里有一个小小的接收协议:通过这个函数,配合一个数组USART_RX_BUF[],一个接收状态寄存器, USART_RX_STA(这个寄存器就是一个全局变量,由程序员自己添加。只是它起到了一个类似寄存器的功能,才暂且将他称呼为寄存器)。实现对串口数据的接收管理。 USART_RX_BUF 的大小由 USART_REC_LEN 定义,也就是一次接收的数据 最大不能超过 USART_REC_LEN 个字节。USART_RX_STA 是一个接收状态寄存器其各的定义如下表: 设计思路: 当接收到电脑发过来的数据,把接收到的数据保存在USART_RX_BUF中,同时在接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(回车的表示有两个字节:0x0D和0x0A)的第一个字节0x0D时,计数器就不会增加,等待0x0A的到来。但是如果没有0x0A没有到来,就认为这一次接收失败,重新开始下一轮的接收。如果接收到0x0A,则标记记 USART_RX_STA的第15位,这样就完成了一次接收,并等待该位被其他程序清除,从而开始新一轮的接收。而如果迟迟没有收到0x0D,那么在接收数据超过USART_REC_LEN时,就会丢弃前面的数据,重新接收。 代码如下:
#if EN_USART1_RX
u8 USART_RX_BUF[USART_REC_LEN];
u16 USART_RX_STA=0;
void USART1_IRQHandler(void)
{
u8 res;
#if SYSTEM_SUPPORT_OS
OSIntEnter();
#endif
if(USART1->SR&(1<<5))
{
res=USART1->DR;
if((USART_RX_STA&0x8000)==0)
{
if(USART_RX_STA&0x4000)
{
if(res!=0x0a)
USART_RX_STA=0;
else
USART_RX_STA|=0x8000;
}
else
{
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;
}
}
}
}
#if SYSTEM_SUPPORT_OS
OSIntExit();
#endif
}
EN_USART1_RX 和 USART_REC_LEN 都是在 usart.h 文件里面定义的。 当需要使用串口接收的时候,只要在 usart.h 里面设置EN_USART1_RX 为 1 就可以了。不使用的时候,设置, EN_USART1_RX 为 0 即可。这样可以省出部分 sram 和 flash。 我们默认是设置 EN_USART1_RX为 1,也就是开启串口接收的。
SYSTEM_SUPPORT_OS,则是用来判断是否使用操作系统(OS),如果使用了 OS,则调用 OSIntEnter 和 OSIntExit 函数,如果没有使用 OS,则不调用这两个函数(这两个函数用于实现中断嵌套处理,由 UCOS 提供,这里我们先不理会)。
3、uart_init函数
串口1初始化函数:void uart_init(u32 pclk2,u32 bound)。其中的参数pclk是APB2总线的时钟频率;bound设置需要的波特率,比如9600,921600等。 这个函数的重点就是在波特率的设置。由于stm32F4采用了分数波特率,所以STM32F4 的串口波特率设置范围很宽,而且误差很小。 stm32f4的每一个串口都有一个自己独立的波特率寄存器USART_BRR,通过设置该寄存器就可以配置不同的波特率。 STM32F4 有一个接收器过采样设置位:OVER8 位。该位是在USART_CR1寄存器中设置。当OVER8=0时,采用16倍过采样率,可以增加接收器对时钟的容差。当OVER8=1时,可以得到更高的速度。简单总结就是:OVER8=0时,精度高,容错性好;OVER8=1时,容错性差,但是速度快。 我们一般是设置OVER8=0,以得到更好的容错性。后面都是在OVER8=0时进行介绍。 前面提到 STM32F4 的分数波特率概念,其实就是在这个寄存器(USART_BRR)里面体现的。USART_BRR 的最低 4 位(位[3:0],当 OVER8=0 时)用来存放小数部分DIV_Fraction, 紧接着的 12 位(位[15:4])用来存放整数部分 DIV_Mantissa,最高 16 位未使用。 stm32f4波特率的计算公式: 上式中,fPCLKx是给串口的时钟(PCLK1用于串口2~5,PCLK2用于串口1和6);USARTDIV是一个无符号定点数。只要得到USARTDIV的值,就可以得到串口波特率寄存器 USART1->BRR 的值,反过来,只要得到 USART1->BRR 的值,就可以推导出USARTDIV的值。一般我们知道的是波特率,和 PCLKx 的时钟,要求的就是USART_BRR 的值: 假设我们的串口1要设置为115200的波特率,而PCLK2的时钟(即APB2总线时钟频率)是84M。这样我们就有计算:USARTDIV=84000000/(11520016)=45.572 即: DIV_Fraction=160.572=9=0X09; DIV_Mantissa=45=0X2D; 这样,我们就得到了了 USART1->BRR 的值为 0X2D9。只要设置串口1的BRR寄存器值为0X2D9就可以得到115200的波特率。 当然在某些波特率和PCLK2频率下,还是有误差,可以参考芯片中文手册。 下面初始化串口:(8位数据格式,1位停止位,无奇偶校验)
void uart_init(u32 pclk2,u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
temp=(float)(pclk2*1000000)/(bound*16);
mantissa=temp;
fraction=(temp-mantissa)*16;
mantissa<<=4;
mantissa+=fraction;
RCC->AHB1ENR|=1<<0;
RCC->APB2ENR|=1<<4;
GPIO_Set(GPIOA,PIN9|PIN10,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,
GPIO_PUPD_PU);
GPIO_AF_Set(GPIOA,9,7);
GPIO_AF_Set(GPIOA,10,7);
USART1->BRR=mantissa;
USART1->CR1&=~(1<<15);
USART1->CR1|=1<<3;
#if EN_USART1_RX
USART1->CR1|=1<<2;
USART1->CR1|=1<<5;
MY_NVIC_Init(3,3,USART1_IRQn,2);
#endif
USART1->CR1|=1<<13;
}
|