串口通信 USART
基于 STM32F103 · 零基础讲解串/并行、同步/异步、单/半/全双工、波特率、数据帧格式与查询/中断/DMA 三种收发方式。
🎯学习目标
- 理解通信的基本概念,了解常见串行通信接口;
- 熟悉标准库和 HAL 库中 USART 的库函数;
- 掌握 USART 标准库异步模式的配置方法;
- 掌握查询方式、中断方式、DMA 方式三种应用;
- 掌握基于标准库和 HAL 库开发 USART 应用的方法。
1通信方式分类
通信方式可从三个维度分类:
串行 vs 并行
串行通信
Serial并行通信
Parallel2同步/异步 · 三种工作方式
同步通信 vs 异步通信
| 对比 | 同步通信 | 异步通信 |
|---|---|---|
| 方式 | 连续串行传送,收发时钟严格同步 | 以字符(数据帧)为单位,加起始/停止位 |
| 速率 | 较高 | 较低 |
| 实现 | 需同步时钟,较复杂 | 设备实现简单、成本低 |
单工 / 半双工 / 全双工
单工
任何时刻只能单方向通信,一端固定发、一端固定收。例:广播、电视、灯塔
半双工
双方都能收发,但不能同时进行。例:对讲机
全双工
双方可同时收发数据。例:手机
3通信传输速率与波特率
- 传输速率(比特率):每秒传输的二进制位数,单位 bit/s(bps),衡量速度快慢。
- 字符速率:每秒所传输的字符数。
- 波特率 = 字符速率 × 每个字符包含的位数。
4异步串行通信数据帧格式 ⭐(核心考点)
异步串行通信的标准数据帧由起始位、数据位、校验位、停止位四部分组成。通信传输速率与数据帧格式一起称为通信协议。
| 组成 | 说明 |
|---|---|
| 起始位 | 占 1 位,位于帧开头,以逻辑 "0" 表示传输开始 |
| 数据位 | 要发送的数据,长度 5~8 位 |
| 校验位 | 占 1 位,用于检测数据是否有效(无/奇/偶校验) |
| 停止位 | 一帧结束标志,可为 1、1.5 或 2 位 |
| 空闲位 | 传输完毕用 "1" 表示线路无数据传输 |
5UART 与 RS-232
UART(Universal Asynchronous Receiver Transmitter,通用异步收发传输器)是全双工通用异步串行收/发模块,用于打印调试信息、上下位机通信、ISP 下载等。
RS-232 接口
RS-232 是美国电子工业协会(EIA)制定的串行通信物理接口标准,规定电气和物理特性,常采用 DB-9 形式。对可靠性要求不高时用三线制(Tx/Rx/GND)即可全双工通信,最高速率约 20kbps。
| 针脚 | 符号 | 功能 |
|---|---|---|
| 2 | RxD | 接收数据(输入) |
| 3 | TxD | 发送数据(输出) |
| 5 | GND | 信号地 |
| 7/8 | RTS/CTS | 请求发送/清除发送(硬件流控) |
6STM32 的 USART 内部结构
USART 内部由三部分构成:波特率发生器、发送/接收控制单元、数据收发寄存器单元。
关键状态位(SR 寄存器)
| 标志位 | 含义 |
|---|---|
| TXE | 发送数据寄存器空(数据已转移到移位寄存器,可写下一个) |
| TC | 发送完成 |
| RXNE | 读数据寄存器非空(收到数据,可读出) |
| IDLE | 检测到总线空闲 |
| ORE/NE/FE/PE | 过载/噪声/帧/校验 错误标志 |
USART 接口与引脚
STM32F103 大容量产品有 5 个串口:USART1/2/3 功能全,UART4/UART5 不支持同步模式(只有异步功能)。USART 异步模式至少需 Rx、Tx 两个引脚,使用复用 I/O 功能。
| 串口 | TX 引脚 | RX 引脚 | GPIO 配置 |
|---|---|---|---|
| USART1 (APB2) | PA9 | PA10 | TX:复用推挽 / RX:浮空输入 |
| USART2 (APB1) | PA2 | PA3 | 同上 |
| USART3 (APB1) | PB10 | PB11 | 同上 |
7USART 三种编程模式 ⭐(核心考点)
查询(轮询)方式
循环查询 SR 状态位(TXE/RXNE)决定是否收发。简单但占用 CPU。
中断方式
使能中断,事件发生时进 ISR 处理。CPU 利用率高。
DMA 方式
大批量数据连续传输,几乎不占 CPU。
中断方式:主要中断事件
发送期间:发送完成(TC)、清除发送(CTS)、发送数据寄存器空(TXE);接收期间:空闲检测(IDLE)、溢出错误(ORE)、接收数据寄存器非空(RXNE)、校验错误(PE)等。
| 中断标志 | 使能位 | STM32 定义 | 事件 |
|---|---|---|---|
| TXE | TXEIE | USART_IT_TXE | 发送数据寄存器空 |
| TC | TCIE | USART_IT_TC | 发送完成 |
| RXNE | RXNEIE | USART_IT_RXNE | 接收数据就绪(可读) |
| IDLE | IDLEIE | USART_IT_IDLE | 检测到空闲线路 |
DMA 方式
USART 收发分别映射到不同 DMA 通道,如 USART1_Rx → DMA1 通道5,USART1_Tx → DMA1 通道4,适合大批量数据连续传输。
8USART 标准库函数与编程步骤
USART 标准库函数定义在 stm32f10x_usart.c,头文件声明共 29 种函数。
初始化结构体
typedef struct {
uint32_t USART_BaudRate; // 波特率,如 115200
uint16_t USART_WordLength; // 数据位 8b/9b
uint16_t USART_StopBits; // 停止位 1/0.5/2/1.5
uint16_t USART_Parity; // 校验 No/Even/Odd
uint16_t USART_Mode; // Rx / Tx
uint16_t USART_HardwareFlowControl; // 硬件流控
} USART_InitTypeDef;
常用库函数
| 函数 | 功能 |
|---|---|
USART_Init() | 初始化串口参数 |
USART_Cmd() | 使能/失能串口 |
USART_SendData() | 发送单个数据 |
USART_ReceiveData() | 接收数据 |
USART_GetFlagStatus() | 查询状态标志(TXE/TC/RXNE…) |
USART_ITConfig() | 使能串口中断 |
USART_GetITStatus() | 查询中断状态 |
USART_ClearITPendingBit() | 清除中断标志 |
USART_DMACmd() | 配置 DMA 与 USART 通道 |
标准库配置步骤(7 步)
| 步骤 | 操作 |
|---|---|
| ① | 声明 GPIO 和 USART 初始化结构体 |
| ② | 使能 GPIO 时钟和串口时钟(RCC_APB2PeriphClockCmd) |
| ③ | TX 配复用推挽输出、RX 配浮空输入 |
| ④ | 设置波特率、数据位、停止位、校验位 |
| ⑤ | USART_Init() 初始化串口 |
| ⑥ | USART_Cmd() 使能串口 |
| ⑦ | 编写应用程序(若用中断则写 USARTx_IRQHandler()) |
9UART 的 HAL 库函数
HAL 库 UART 函数定义在 stm32f1xx_hal_uart.c。三种收发方式各有对应函数:
| 方式 | 发送 | 接收 |
|---|---|---|
| 轮询 | HAL_UART_Transmit() | HAL_UART_Receive()(带超时) |
| 中断 | HAL_UART_Transmit_IT() | HAL_UART_Receive_IT() |
| DMA | HAL_UART_Transmit_DMA() | HAL_UART_Receive_DMA() |
中断接收完成会回调 HAL_UART_RxCpltCallback(),发送完成回调 HAL_UART_TxCpltCallback(),用户在回调内编写处理程序。
⭐重点例题
void USART_Init_Config(void) {
GPIO_InitTypeDef gp; USART_InitTypeDef us;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
// PA9 = TX 复用推挽输出
gp.GPIO_Pin=GPIO_Pin_9; gp.GPIO_Speed=GPIO_Speed_50MHz;
gp.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_Init(GPIOA,&gp);
// PA10 = RX 浮空输入
gp.GPIO_Pin=GPIO_Pin_10; gp.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,&gp);
// 115200 / 8位 / 1停止 / 无校验 / 收发
us.USART_BaudRate=115200; us.USART_WordLength=USART_WordLength_8b;
us.USART_StopBits=USART_StopBits_1; us.USART_Parity=USART_Parity_No;
us.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
us.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(USART1,&us); USART_Cmd(USART1,ENABLE);
}
int main(void){
char Temp; USART_Init_Config();
while(1){
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)){ // 收到数据
Temp=USART_ReceiveData(USART1);
USART_SendData(USART1,Temp); // 原样回发
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); // 等发完
}
}
}
关键点:发送前后用 TXE/TC 标志判断;TX=复用推挽、RX=浮空输入;收发双方波特率必须一致。
fputc()(输出)和 fgetc()(输入),勾选 Keil 的 Use MicroLIB,并 #include <stdio.h>。
int fputc(int ch, FILE *f) { // printf 重定向
USART_SendData(USART1, (uint8_t)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET); // 等寄存器空
return ch;
}
int fgetc(FILE *f) { // scanf/getchar 重定向
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
return (int)USART_ReceiveData(USART1);
}
// 之后即可: printf("点亮LED灯\n"); ch=getchar();
提示:输出字符串时若丢失第一个字符,可在发送前调用 USART_ClearFlag(USARTx,USART_FLAG_TC) 复位 TC 标志。
/* main 中开启接收中断 */
HAL_UART_Receive_IT(&huart1, (uint8_t*)&RxBuffer, 1);
/* 接收完成回调:回发并重新开启接收 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
HAL_UART_Transmit(&huart1,(uint8_t*)&RxBuffer,1,0);
HAL_UART_Receive_IT(&huart1,(uint8_t*)&RxBuffer,1); // 必须重新开启
}
关键点:HAL 中断接收是"一次性"的,回调里必须重新调用 HAL_UART_Receive_IT() 才能持续接收。
🎯自测(点击展开)
串行通信和并行通信的区别?
单工、半双工、全双工分别举一个例子?
异步串行数据帧由哪几部分组成?
波特率怎么计算?
USART 的 TX、RX 引脚应配置为什么模式?
USART 有哪三种编程(收发)方式?
RS-232 与 STM32 相连为什么要电平转换?
📝强化题库
选择题点选即时判分;填空题输入后"检查"或"显示答案"。