2、寄存器版——stm32的system文件夹(usart文件夹)

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 //如果使能了接收
//串口 1 中断服务程序
//注意,读取 USARTx->SR 能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN];//接收缓冲,最大 USART_REC_LEN 个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到 0x0d
//bit13~0,接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
void USART1_IRQHandler(void)
{
	u8 res;
#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS.
	OSIntEnter();
#endif
	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;//接收数据错误,重新开始接收
				}
			}
		}
	}
#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 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=16
0.572=9=0X09;
DIV_Mantissa=45=0X2D;
这样,我们就得到了了 USART1->BRR 的值为 0X2D9。只要设置串口1的BRR寄存器值为0X2D9就可以得到115200的波特率。
当然在某些波特率和PCLK2频率下,还是有误差,可以参考芯片中文手册。
下面初始化串口:(8位数据格式,1位停止位,无奇偶校验)

//初始化 IO 串口 1
//pclk2:PCLK2 时钟频率(Mhz)
//bound:波特率
void uart_init(u32 pclk2,u32 bound)
{
	float temp;
	u16 mantissa;
	u16 fraction;
	temp=(float)(pclk2*1000000)/(bound*16);//得到 USARTDIV@OVER8=0
	mantissa=temp; //得到整数部分
	fraction=(temp-mantissa)*16; //得到小数部分@OVER8=0
 	mantissa<<=4;
	mantissa+=fraction;
	RCC->AHB1ENR|=1<<0; //使能 PORTA 口时钟
	RCC->APB2ENR|=1<<4; //使能串口 1 时钟
	GPIO_Set(GPIOA,PIN9|PIN10,GPIO_MODE_AF,GPIO_OTYPE_PP,GPIO_SPEED_50M,
GPIO_PUPD_PU);//PA9,PA10,复用功能,上拉输出
	GPIO_AF_Set(GPIOA,9,7); //PA9,AF7
	GPIO_AF_Set(GPIOA,10,7);//PA10,AF7
	//波特率设置
	USART1->BRR=mantissa; //波特率设置
	USART1->CR1&=~(1<<15); //设置 OVER8=0
	USART1->CR1|=1<<3; //串口发送使能
#if EN_USART1_RX //如果使能了接收
//使能接收中断
	USART1->CR1|=1<<2; //串口接收使能
	USART1->CR1|=1<<5; //接收缓冲区非空中断使能
	MY_NVIC_Init(3,3,USART1_IRQn,2);//组 2,最低优先级
#endif
	USART1->CR1|=1<<13; //串口使能
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值