1. 串行输入输出接口的基本概念
串行通信的基本模式:
- 单工传输:一个设备只能发送或接受。
- 半双工:通信双方都可以进行发送和接收,但一台设备不能同时发送和接收。
- 双工传输:可以同时进行双向通通信。
串行通信协议类型:
- 同步串行通信协议:通信双方共用一个时钟,并由时钟来实现发送端和接收端的同步。
- 异步串行通信协议:不需要时钟做同步,但双方必须使用各自的时钟保持相同的传送波特率(每秒传送数据二进制代码的位数,单位是b/s),并以每个字符数据的起始位与发送设备保持同步。数据以相同的帧格式传送,每一帧由起始位、数据位、校验位、停止位组成。
时钟与数据采样
二进制数据在串行传输过程中以数字信号波形的形式出现。无论是发送还是接收,都需要时钟信号对数据进行定位。
- 同步传输:发送端和接收端共用同一个时钟,时钟频率等于波特率,每个数据位只需采样一次,通信速度快但需要额外的时钟线,实现更复杂。
- 异步传输:双方不需要共享时钟,而是各自保持相同的波特率。通常,接收端的时钟频率会设置为波特率的 8、16 或 64 倍,通过多次采样来降低噪声干扰和时钟漂移的影响。例如,时钟频率为波特率的 8 倍时,每接收一个数据位会采样 8 次,从而提高数据的可靠性。虽然异步通信速度略慢,但实现简单、连线更少,广泛应用于实际工程中。
2. UART 通信简介
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是一种常见的串行通信(一次只能传输一个二进制位,数据需要一位一位地传输)协议,广泛应用于嵌入式系统。典型应用包括调试信息输出、外设通信(如 GPS、蓝牙、WiFi 模块)、MCU 之间数据交互
UART控制器基本结构

上图展示了一个异步串行总线控制器的内部结构。主要模块说明如下:
- 波特率发生器(Clock Generator):用于产生发送和采样时钟,决定数据传输速率。
- 发送寄存器(Transmitter Register):用于从总线写入数据到 UART,准备发送。
- 接收寄存器(Receive Register):用于将接收到的数据从 UART 传输到总线。
- 移位寄存器(Shift Register):负责将一个字符的数据逐位发送到 TX 引脚,或从 RX 引脚逐位接收并组装成完整字符。
通过这些模块的协作,UART 能够实现高效、可靠的串行数据收发。
UART 帧通常包括以下部分:
- 空闲(Idle,逻辑高电平 1):总线未传输数据时保持高电平。
- 起始位(Start bit,逻辑低电平 0):通知接收端即将开始传输新字符。
- 数据位(Data bits):紧随起始位的 5~9 位(常用 8 位),表示实际传输的数据内容。
- 奇偶校验位(Parity bit,可选):用于检测数据在传输过程中是否出错。
- 停止位(Stop bit(s),逻辑高电平 1):1 或 2 位高电平,表示本字符传输结束。

上图展示了一个 UART 帧的实际波形:包含 1 个起始位、8 个数据位(D1–D8)和 2 个停止位,共 11 位。
数据位数量、校验位设置、奇偶校验类型以及波特率等参数,需通信双方事先约定一致。
“停止位”本质上是一个最小持续高电平周期,通常为 1~2 位时间。发送端的停止周期可以更长,接收端只需满足最小要求。每帧结束后,接收端会等待下一个起始位,从而实现异步同步。
由于起始位为低电平、停止位为高电平,因此每个字符之间至少有两次电平跳变,便于接收端识别帧边界。
如果线路持续保持低电平超过一个字符周期(发送或接收一个字符的时间),UART 会检测为 Break 条件(断线状态)。
3. 实验
必备开发软件:STM32CubeIDE、STM32CubeMX、Tera Term
实验目标:掌握 UART 基本操作
硬件需求:STM32 开发板(示例型号:STM32F746G-DISCO)
实验步骤
-
CubeMX 工程配置
打开 STM32CubeMX,选择开发板型号,创建新工程。 -
UART 引脚与参数配置
- 选择一个 UART 控制器(如 USART1),模式设为异步模式( Asynchronous),波特率保持默认值 115200。
- 添加DMA配置
- 启用 NVIC 中断
- 选择一个 UART 控制器(如 USART1),模式设为异步模式( Asynchronous),波特率保持默认值 115200。
-
生成代码并导入 IDE
生成代码后,在 STM32CubeIDE 中打开工程。
3.1 轮询方式(Polling)
最简单的方式,通过阻塞方式发送和接收数据。
- 在
main
函数的while(1)
循环中添加如下代码:
char msg[] = "Hello UART\r\n";
HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
uint8_t rxData;
HAL_UART_Receive(&huart1, &rxData, 1, HAL_MAX_DELAY); // 接收 1 字节
- 连接开发板,下载程序。
- 打开 Tera Term,建立串口连接,并通过“设置->串口”菜单设置波特率为 115200。。
- 运行后,串口会输出 "Hello UART",输入任意字符会继续输出。
3.2 中断方式(Interrupt)
适用于数据量较小、实时性要求高的场景。
- 删除轮询方式相关代码。
- 声明全局变量
rxData
,并实现回调函数:
uint8_t rxData;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
HAL_UART_Transmit(&huart1, &rxData, 1, HAL_MAX_DELAY); // 回显
HAL_UART_Receive_IT(&huart1, &rxData, 1); // 重新启动接收
}
}
- 在
main
函数中UART初始化后添加:
HAL_UART_Receive_IT(&huart1, &rxData, 1); // 启用中断接收
- 下载程序,打开 Tera Term,程序运行时输入字符可实现回显。
3.3 DMA 方式
适合大数据量传输,减少 CPU 占用。
- 删除中断方式相关代码。
- 在
while(1)
循环前添加:
uint8_t txBuffer[100] = "UART DMA Example\r\n";
HAL_UART_Transmit_DMA(&huart1, txBuffer, strlen((char*)txBuffer));
- 下载程序,打开 Tera Term,程序运行时可看到串口输出 "UART DMA Example”。