本文主要介绍如何配置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