STM32 USART 外设
USART 是 STM32 内部集成的硬件外设,可以根据数据寄存器的一个字节数据自动生成数据帧时序,通过 TX 引脚发送,也可以自动接收 RX 引脚的数据帧时序,拼接为一个字符数据,存放至数据寄存器中。
STM32 内置的 USART 外设技术参数:
- 自带波特率发生器: 最大值4.5Mbits/s
- 可配置数据位长度 (8或9)、停止位长度 (0.5/1/1.5/2)
- 可选校验位:无校验/奇校验/偶校验
- 支持同步模式、硬件流控制、DMA、智能卡、lrDA、LIN
STM32F103C8T6 拥有三个 USART 资源: USART1、USART2、USART3 (USART1挂载在 APB1 总线,其余挂载在 APB2 总线)
STM32 USART 结构

STM32 USART 外设当发送数据寄存器向发送位移寄存器传输完毕数据后会置一个 TXE 标志位,通过判断该标志位即可判断是否可以写入下一个数据;接收部分与发送同理,包含一个 RXNE 标志位(1)。
- 该标志位也可以连接&申请中断。
数据帧
STM32 USART 外设在配置数据帧长度(字长)的时候,共有 4 种选择:
波特率发生器
发送器和接收器的波特率由波特率寄存器 BRR 中的 DIV 确定,其计算公式如下:
\[
Baud = \frac{f_{PCLK2/1}}{(16 * DIV)}
\]
标准库操作 USART 外设
初始化 USART 外设
- 开启时钟: USART 外设时钟、 GPIO 时钟
分别开启需要使用的 GPIO 端口和 USART 外设的时钟:
RCC_APB2Periph_USART1
RCC_APB2Periph_GPIOA
| RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
-
GPIO 初始化
- 将 TX 引脚配置为复用推挽输出
| GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
-
将 RX 引脚配置为复用输入
引脚输入模式可以设置为: 上拉输入、浮空输入。
| GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = SERIAL_RX_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(SERIAL_TRX_GROUP, &GPIO_InitStructure);
|
-
配置 USART 结构体
| USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1, &USART_InitStructure);
|
USART 配置结构体功能对照表
结构体成员 |
功能 |
USART_BaudRate |
波特率 |
USART_HardwareFlowControl |
硬件流控制 |
USART_Mode |
串口模式 |
USART_Parity |
校验位 |
USART_StopBits |
停止位 |
USART_WordLength |
字长 |
不同结构体成员的配置选择
Usart_hardwareflowcontrol
- USART_HardwareFlowControl_None —— 不适用硬件流控制
- USART_HardwareFlowControl_RTS —— 仅使用 RTS
- USART_HardwareFlowControl_CTS —— 仅使用 CTS
- USART_HardwareFlowControl_RTX_CTS —— 同时使用 RTS 和 CTS
Usart_mode
- USART_Mode_Tx —— 仅发送模式
- USART_Mode_Rx —— 仅接收模式
如果需要同时使用发送和接收功能,使用 |
或运算符将二者连接即可。
Usart_parity
- USART_Parity_No —— 无校验
- USART_Parity_Even —— 偶校验
- USART_Parity_Odd —— 奇校验
Usart_stopbits
- USART_StopBits_0_5 —— 0.5 校验位长度
- USART_StopBits_1 —— 1 校验位长度
- USART_StopBits_1_5 —— 1.5 校验位长度
- USART_StopBits_2 —— 2 校验位长度
Usart_wordlength
- USART_WordLength_8b —— 8 位字长
- USART_WordLength_9b —— 9 位字长
- 开启 USART 功能
如果需要使用 USART 接收功能,则需要 在开启 USART 功能前配置中断相关代码。
| USART_Cmd(USART1, ENABLE);
|
发送&接收数据
发送相关功能函数
| void Serial_SendByte(uint8_t DByte){
USART_SendData(USART1, DByte);
// wait USART Flag to TEX
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE)){}
}
|
| void Serial_SendArray(uint8_t* Array, uint16_t Length){
for (uint16_t i = 0; i < Length; i++){
Serial_SendByte(Array[i]);
}
}
|
| void Serial_SendString(char* String){
for (uint8_t i = 0; String[i] != '\0'; i++){
Serial_SendByte(String[i]);
}
}
|
| // String Send Number
void Serial_SendNumber(uint32_t Number, uint8_t Length){
for (uint8_t i = 0; i < Length; i++){
// Function: Serial_Pow —— 指数计算函数
Serial_SendByte(Number / Serial_Pow(10, Length - i - 1) % 10 + '0');
}
}
|
| void Serial_Printf(char *format, ...){
char String[MAX_BUFFER];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
Serial_SendString(String);
}
|
轮询判断接收
通过重复判断接收标志位,判断是否有数据输入。
USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
USART_ReceiveData(USART1);
中断接收
如果需要使用中断接收数据,则需要在初始化流程中加入配置中断的相关代码。
在 USART 配置函数中新增如下代码
| // USART IT Config Init
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
// NVIC Init
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
|
中断初始化完毕后,当 RX 引脚接收到数据后,会向 NVIC 申请中断,数据读取操作可以在回调函数内进行操作。
uint8_t USART_RxFlage;
uint8_t USART_RxData;
| void USART1_IRQHandler(void){
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET){
USART_RxData = USART_ReceiveData(USART1);
USART_RxFlage = 1;
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
}
|
封装外部函数,读取寄存器数据和标志位。
| uint8_t Get_RxFlage (void){
if (USART_RxFlage == 1){
USART_RxFlage = 0;
return 1;
}
else{
return 0;
}
}
uint8_t Get_RxData(void){
return USART_RxData;
}
|
发送&接收数据包