一、概述
本文主要介绍如何配置USART,并通过USART打印验证结果。以stm32f10为例,将PA9、PA10复用为USART功能,使用HSE PLL输出72MHZ时钟 APB2 clk不分频提供配置9600波特率。波特率计算公式如下:
fck即为APB2 clk参考计算:
硬件图:
二、配置流程
1)配置系统时钟输出72MHZ
参考上文STM32 寄存器配置笔记------系统时钟配置 HSE as PLL
2)计算USARTDIV
USARTDIV = fck / 波特率 * 16
temp = (float)(pclk2 * 1000000) / (bound * 16); // cal USARTDIV
3)获取整数部分和小数部分
获取整数和小数部分以及要写进BRR波特率寄存器的值。
mantissa = temp; // get mantissa
fraction = (temp - mantissa) * 16; // get fraction
uart_brr = (mantissa << 4) | fraction;
4) 使能时钟
使能端口A时钟和USART1时钟。
RCC->APB2ENR |= 1 << 2; // enable portA clk
RCC->APB2ENR |= 1 << 14; // enable USART1 clk
5)配置GPIO复用功能
参考手册配置TX、RX的复用功能。
GPIOA->CRH &= 0xFFFFF00F; // reset portA pin9¡¢10 cfg
GPIOA->CRH |= 0x4B0; // pin9 - UART1_TX pp af output pin10 - UART1_RX float input
6)复位USART状态
此处在开启USART前复位一下USART状态,保证USART能够彻底初始化。复位完后需要停止复位,避免USART不停复位
RCC->APB2RSTR |= 1 << 14; // reset USART1
RCC->APB2RSTR &= ~(1 << 14); // stop reset USART1
7)配置波特率使能USART1
USART1->BRR = uart_brr; // set bound param
USART1->CR1 |= 0x200C; // enable usart 8bit data no parity enable tx & rx
三、源码
整个代码调用情况如下:
void uart_init(u32 pclk2,u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
u16 uart_brr;
temp = (float)(pclk2 * 1000000) / (bound * 16); // cal USARTDIV
mantissa = temp; // get mantissa
fraction = (temp - mantissa) * 16; // get fraction
uart_brr = (mantissa << 4) | fraction;
RCC->APB2ENR |= 1 << 2; // enable portA clk
RCC->APB2ENR |= 1 << 14; // enable USART1 clk
GPIOA->CRH &= 0xFFFFF00F; // reset portA pin9¡¢10 cfg
GPIOA->CRH |= 0x4B0; // pin9 - UART1_TX pp af output pin10 - UART1_RX float input
RCC->APB2RSTR |= 1 << 14; // reset USART1
RCC->APB2RSTR &= ~(1 << 14); // stop reset USART1
USART1->BRR = uart_brr; // set bound param
USART1->CR1 |= 0x200C; // enable usart 8bit data no parity enable tx & rx
}
在USART1配置完成后,将PA9、PA10接TTL转USB串口设备在主循环一直打印内容验证是否配置成功。
在使用printf前需要做映射:
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要支持的函数
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef¡¯ d in stdio.h. */
FILE __stdout;
//定义 _sys_exit以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定向fputc函数
//printf的输出,指向fputc, 由fputc输出到串口
//这里使用USART1输出printf信息
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//等待上一次串口数据发送完成
USART1->DR = (u8) ch; //写DR,串口1将发送数据
return ch;
}
#endif