嵌入式 MCU

UART

UART学习笔记。

1. 摘要与目标

UART 是嵌入式系统里最常见的串行通信外设之一,常用于调试日志、MCU 与传感器模块通信、蓝牙/Wi-Fi/GPS 模块接入、串口屏控制,以及通过 RS-232、RS-485 收发器连接更远距离的设备。很多初学者能写出 printf 重定向或调用 HAL_UART_Transmit(),但遇到乱码、丢字节、收不到数据、DMA 只触发一次、RS-485 只能发不能收时,往往不知道问题到底在电平、接线、帧格式、波特率还是软件缓冲。

本文从工程排查角度整理 UART 的核心机制:先建立 TX/RX/GND 与异步串行帧的模型,再解释起始位、数据位、校验位、停止位、波特率误差、接收采样和状态标志,最后把这些机制映射到 STM32 HAL 的阻塞、中断、DMA 与 IDLE 接收方式。

本文适用于常见 MCU 的异步 UART/USART 使用场景,示例以 STM32 HAL 为主。本文重点讨论 TTL/CMOS 电平 UART、USB-TTL 串口模块、RS-232/RS-485 收发器配合 UART 的常见工程问题,不展开 LIN、IrDA、SmartCard、同步 USART 等扩展模式。

学习时可以按三层模型建立理解:硬件层关注 TX/RX/GND、电平标准和收发器;协议层关注帧格式、波特率、采样和错误标志;工程层再将这些流程映射到 HAL API、缓冲区、回调函数和故障排查顺序。

UART 通信从 MCU USART 外设经过 TX/RX/GND 连接到对端设备,可选经过 USB-TTL、RS-232 或 RS-485 收发器进行电平或物理层转换

图 1:UART 本身描述的是异步串行收发逻辑,实际工程还要确认 TX/RX 接线、共地、电平标准和是否经过收发器转换。

2. 原理与关键机制

2.1 核心概念:异步串行收发器

UART 的全称是 Universal Asynchronous Receiver/Transmitter,直译为通用异步收发器。它不是一条带地址和仲裁机制的共享总线,而是 MCU 内部或芯片内部的一个串行收发外设。它负责把 CPU 写入的数据字节转换成按位输出的串行波形,也负责把 RX 引脚上的串行波形重新采样并还原为字节。

UART 最基本的连接包含三类信号:

信号方向作用
TX本机输出发送串行数据到对端 RX
RX本机输入从对端 TX 接收串行数据
GND参考地给双方逻辑电平提供共同参考

两块板子直接使用 TTL/CMOS UART 通信时,通常需要交叉连接:本机 TX 接对端 RX,本机 RX 接对端 TX,并且双方必须共地。如果只接 TX/RX 而没有公共参考地,对端看到的高低电平就没有稳定基准,表现可能是完全收不到、偶发乱码或抗干扰能力很差。

UART 称为“异步”,是因为它不像 SPI 或 I2C 那样额外提供一根时钟线。发送方和接收方必须事先约定波特率、数据位、校验方式和停止位。接收方通过检测起始位来判断一个字符开始,然后依靠自己的本地时钟在每一位的合适位置采样。

因此,UART 的稳定性并不只取决于代码里是否调用了发送函数,还取决于双方配置是否一致、时钟误差是否可接受、物理电平是否兼容,以及接收端是否能及时搬走已经收到的数据。

2.2 UART、USART、TTL、RS-232 与 RS-485 的关系

初学串口时最容易混淆的是 UART、USART、TTL、RS-232 和 RS-485。它们不在同一个层级:

名称更接近哪一层重点
UART控制器/外设逻辑异步串行收发、帧格式、波特率、状态标志
USART控制器/外设逻辑在 UART 基础上还可能支持同步模式
TTL/CMOS UART板级逻辑电平0/3.3 V 或 0/5 V 这类 MCU 引脚电平
RS-232物理层电气标准使用正负电压且逻辑含义与 TTL 不同,需要电平转换芯片
RS-485物理层电气标准差分传输,常用于长线、抗干扰和多节点半双工场景

可以把 UART 理解成“字节如何被拆成位并按时间发出去”的机制,而 RS-232/RS-485 是“这些位在线缆上用什么电压和拓扑传输”的物理层方案。MCU 的 UART 引脚通常不能直接接传统 RS-232 口,因为 RS-232 使用正负电压并且逻辑极性与 TTL/CMOS UART 不同。工程中需要 MAX232、MAX3232 或同类 RS-232 收发器完成电平与极性转换。

RS-485 则常通过收发器把 UART 的 TX/RX 转成差分线 A/B。很多 RS-485 项目使用半双工拓扑,同一时刻只能发送或接收,因此还需要一个方向控制信号,例如 DERE。如果方向切换时机不对,就会出现能发不能收、数据尾字节丢失或总线冲突。

一句话区分

UART 负责“串行帧怎么收发”,TTL/RS-232/RS-485 负责“这些串行位用什么电气形式跑在线上”。不要把 MCU 的 TTL UART 口直接当作 RS-232 口使用。

2.3 帧格式:空闲、起始位、数据位、校验位和停止位

UART 空闲时,TX 线通常保持高电平。发送一个字符时,发送器先把线拉低形成起始位,接收器检测到从高到低的跳变后,认为一帧开始。之后发送器按约定波特率依次发送数据位,常见配置是 8 个数据位,并且通常低位 LSB 先发送。数据位之后可以带 1 位校验位,最后用 1 个或多个停止位让线路回到高电平。

常见的 8N1 配置可以拆成:8 个数据位、No parity 无校验、1 个停止位。它的最小时序可以写成:

空闲高电平 → Start(0) → D0 → D1 → D2 → D3 → D4 → D5 → D6 → D7 → Stop(1) → 空闲高电平

如果配置为 8E1,则表示 8 个数据位、偶校验、1 个停止位:

空闲高电平 → Start(0) → D0..D7 → Even Parity → Stop(1)

起始位和停止位的意义不只是“多出来的两个 bit”。起始位给接收器提供重新同步的边界,停止位则让线路回到空闲状态,并给接收器留出一定恢复时间。如果双方对数据位、校验位或停止位的理解不一致,接收器就会在错误的位置采样,轻则乱码,重则触发帧错误或完全收不到有效字节。

UART 一帧数据从空闲高电平开始,依次经过起始位、低位先发的数据位、可选校验位和停止位,接收端在每个 bit 的中间位置采样

图 2:UART 没有独立时钟线,接收端靠起始位重新对齐,并按约定波特率在每个 bit 的中间区域采样。

2.4 波特率、位时间与接收采样

波特率表示串行线上每秒传输多少个符号。对于常见 UART 场景,一个符号通常对应一个 bit,因此 115200 baud 可以近似理解为每秒传输 115200 bit。单个 bit 的时间为:

bit_time = 1 / baudrate
115200 baud 时,1 bit 约为 8.68 μs
9600 baud 时,1 bit 约为 104.17 μs

UART 接收端通常不会在边沿瞬间采样,因为边沿附近更容易受抖动和上升/下降时间影响。更合理的做法是在检测到起始位后,等待半个 bit 时间附近确认起始位有效,然后在每个后续 bit 的中间位置采样。许多 MCU UART 外设内部会使用 8 倍或 16 倍过采样来提高采样位置的鲁棒性。

由于没有共享时钟,发送端和接收端的本地时钟都会有误差。单个 bit 的误差看起来很小,但一帧数据中采样点会逐位累积偏移。如果总误差太大,接收器本来应该在 bit 中间采样,最后可能偏到相邻 bit 的边界甚至采错 bit。

这就是为什么 UART 两端必须配置相同波特率,而且高速率比低速率更容易暴露时钟误差。速率越高,每个 bit 的时间越短,留给波形边沿、时钟偏差和软件处理的余量也越小。

2.5 数据位、校验位和停止位如何影响有效载荷

UART 的“发送 1 个字节”并不等于线上只发送 8 个 bit。以 8N1 为例,传 8 个数据 bit 还需要 1 个起始位和 1 个停止位,线上至少传 10 个 bit。因此串口理论吞吐量可以粗略估算为:

有效字节速率 ≈ baudrate / 每帧总 bit 数
115200 baud, 8N1:115200 / 10 ≈ 11520 byte/s

如果增加校验位或两个停止位,每个数据字节对应的总 bit 数会更多,有效载荷占比会下降。校验位只能检测部分单 bit 或奇偶性异常,不能替代 CRC、长度字段、帧头帧尾等上层协议校验。停止位增加后,通信效率下降,但接收端有更多恢复时间,在某些容错场景或老设备兼容场景下有意义。

常见配置可以这样记:

配置含义典型场景
8N18 数据位,无校验,1 停止位MCU 调试串口、USB-TTL 模块、常见 AT 指令模块
8E18 数据位,偶校验,1 停止位某些工业协议或设备要求
8O18 数据位,奇校验,1 停止位旧设备或特定协议兼容
9N19 数据位,无校验,1 停止位多机通信、地址标记或特定 MCU 模式

排查乱码时,不要只看波特率,还要同时确认数据位、校验位、停止位和是否存在硬件流控。只要其中一个不一致,接收出来的字节就可能完全偏离预期。

2.6 发送、接收缓冲与状态标志

UART 外设内部通常有发送数据寄存器、接收数据寄存器和移位寄存器。软件写入数据寄存器后,硬件把并行字节搬到移位寄存器,再一位一位从 TX 引脚输出。接收方向相反:RX 引脚上的串行位先进入接收移位寄存器,凑成一个字节后再放入接收数据寄存器,等待软件读取。

这几个状态经常对应到寄存器标志或 HAL 错误码:

常见标志直观含义工程意义
TXE / TXFNF发送数据寄存器可写可以写入下一个字节,但不代表最后一个字节已经完全发出
TC发送完成移位寄存器也发完了,RS-485 切回接收通常要等这个状态
RXNE / RXFNE接收数据寄存器非空软件应尽快读取,否则后续字节可能覆盖或触发溢出
IDLE接收线空闲可用于判断一段不定长数据结束
OREOverrun 溢出软件没有及时取走旧数据,新数据已经到来
FEFraming Error 帧错误停止位位置没有检测到预期空闲电平,常见于波特率或格式错误
PEParity Error 校验错误启用校验后,接收数据的奇偶性不符合配置
NENoise Error 噪声错误采样受到干扰或电气质量较差

不同 STM32 系列的寄存器命名会有差异,具体名称以对应参考手册和 HAL 头文件为准。学习时更重要的是理解它们背后的数据流:软件处理速度如果跟不上硬件接收速度,就会从“偶发乱码”逐渐变成“稳定丢字节”。

2.7 不定长接收:为什么 UART 需要上层帧协议

I2C 和 SPI 的一次传输通常由主机明确控制长度,而 UART 的 RX 线只是不断到达字节流。UART 硬件只能告诉你“收到一个字节”或“出现空闲”,并不知道一个业务消息从哪里开始、在哪里结束。

因此,可靠的 UART 应用通常会在上层定义帧边界。常见做法包括:

边界方式示例优点风险
固定长度每包固定 8 字节解析简单丢 1 字节后容易整体错位
帧头 + 长度0xAA 0x55 Len Data CRC适合二进制协议需要处理假帧头和长度异常
分隔符AT 指令常用 \r\n文本协议直观数据中不能随意出现分隔符
空闲超时Modbus RTU 使用帧间隔思想适合连续字节流超时阈值与波特率、调度延迟相关
IDLE 中断STM32 常用于 DMA 不定长接收CPU 占用低需要正确处理 DMA 计数和缓存边界

对于 STM32 项目,常见结构是:中断或 DMA 负责把字节搬到环形缓冲区,主循环或任务负责按协议解析完整帧。不要在 UART 中断里做大量字符串格式化、复杂解析或阻塞发送,否则接收中断本身会变慢,反过来导致更多丢字节。

UART 接收数据从 RX 引脚进入移位寄存器,再进入接收寄存器并触发 RXNE 或 IDLE,随后由中断或 DMA 搬到环形缓冲区,最后由协议解析器处理完整帧

图 3:UART 硬件只负责还原字节,完整消息边界需要由上层协议、超时或 IDLE 机制来判断。

2.8 硬件流控、半双工与 RS-485 方向控制

当发送方速度高于接收方处理能力时,单纯 TX/RX/GND 三线连接可能会丢数据。硬件流控通过额外信号告诉对端“现在能不能继续发”。常见的 RTS/CTS 可以理解为接收端对发送端的一种硬件节流机制。并不是所有模块都启用硬件流控,如果一端启用、另一端没接线或没配置,可能表现为发送函数阻塞、没有输出或只能发送少量数据。

半双工 UART 只用一根数据线或一组差分线交替收发。RS-485 半双工就是最常见场景之一。发送前需要使能驱动器,发送结束后再关闭驱动器并切回接收。如果只等 TXE 就关闭发送方向,可能最后一个字节还在移位寄存器里没有真正发完,尾字节会被截断。更稳妥的判断通常要等发送完成状态,例如 TC

RS-485 项目还要考虑总线终端电阻、偏置电阻、节点数量、线缆长度、共模干扰和协议层冲突。UART 只解决字节收发,不会自动解决多节点总线上的地址、主从调度、重发和 CRC,这些通常由 Modbus RTU 或自定义协议完成。

3. STM32 HAL 使用方法

STM32 HAL 将 UART/USART 的初始化、发送、接收、中断、DMA 和错误处理封装成一组 API。学习时不必先背所有函数原型,更重要的是理解每类 API 对应哪种底层行为:阻塞函数由当前线程等待完成,中断函数依靠 IRQ 和回调推进,DMA 函数把搬运任务交给 DMA 控制器。

3.1 使用前准备

  1. 从芯片数据手册和原理图确认使用的是哪个 USART/UART 实例、TX/RX 引脚、复用功能、是否经过 USB-TTL、RS-232 或 RS-485 收发器。
  2. 在 CubeMX 或初始化代码中启用 UART 外设时钟和 GPIO 时钟,将 TX/RX 配置为对应复用功能。普通 TTL UART 的 TX 通常是复用推挽输出,RX 是输入或复用输入。
  3. 确认双方配置一致:波特率、数据位、校验位、停止位、硬件流控、单双工模式。
  4. 使用中断接收时启用 USART 中断并配置 NVIC;使用 DMA 时还要启用 DMA 时钟、配置 DMA 通道,并关联到 UART 句柄。
  5. 初次调试建议先使用 115200, 8N1, no flow control 和阻塞发送,确认串口工具能稳定看到日志,再逐步切换到中断或 DMA。

3.2 常用 HAL API

API用途对应的底层机制
HAL_UART_Transmit()阻塞发送固定长度数据软件逐步等待发送寄存器可写,直到数据发送完成或超时
HAL_UART_Receive()阻塞接收固定长度数据软件等待接收寄存器出现数据,直到收到指定长度或超时
HAL_UART_Transmit_IT()中断方式发送函数启动发送后返回,后续由 TX 相关中断继续推进
HAL_UART_Receive_IT()中断方式接收收到指定长度后进入 HAL_UART_RxCpltCallback()
HAL_UART_Transmit_DMA()DMA 发送DMA 将缓冲区数据搬到 UART 发送寄存器
HAL_UART_Receive_DMA()DMA 接收固定长度数据DMA 将 UART 收到的数据搬到内存缓冲区
HAL_UARTEx_ReceiveToIdle_DMA()DMA 接收不定长数据收到指定长度或检测到 IDLE 空闲事件时回调处理
HAL_UART_GetError()读取错误码根据系列 HAL 返回溢出、帧错误、校验错误等错误信息

不同 STM32 HAL 版本和芯片系列的函数名可能略有差异。较新的 HAL 文档中还提供了获取 TX/RX 状态、最后错误码和高级接收模式的函数。实际项目以你工程中 stm32xxxx_hal_uart.h 的声明为准。

3.3 关键参数与配置

参数 / 配置含义常见误区或选择依据
BaudRate波特率两端必须一致;高速更依赖时钟精度和线缆质量
WordLength字长开启校验时,有些系列的字长配置会包含校验位,需按 HAL 文档理解实际数据位
StopBits停止位数量与对端不一致容易触发帧错误或乱码
Parity奇偶校验只能做简单错误检测,不能替代协议 CRC
Mode发送、接收或收发只开 TX 时无法接收,只开 RX 时无法发送
HwFlowCtl硬件流控未接 RTS/CTS 时通常关闭,否则可能卡住发送
OverSampling过采样影响最大波特率和抗误差能力,普通调试优先使用默认配置
Timeout阻塞等待时间太短会误判超时,太长会阻塞任务或主循环

一个最小的阻塞发送示例:

const uint8_t msg[] = "uart ok\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)msg, sizeof(msg) - 1, 100);

一个最小的单字节中断接收示例:

static uint8_t rx_byte;
void uart_rx_start(void)
{
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) {
ring_buffer_push(rx_byte);
HAL_UART_Receive_IT(&huart1, &rx_byte, 1);
}
}

这段代码的重点不是封装通用驱动,而是说明中断接收的基本模式:先启动一次接收,收到 1 字节后进入回调,把字节放入缓冲区,再重新启动下一次接收。真正项目中还要处理错误回调、缓冲区满、并发访问和协议解析。

3.4 阻塞、中断与 DMA 模式

模式常见 API 后缀特点适用场景
阻塞无后缀调用者等待发送或接收完成,逻辑直观但会占用 CPU 时间初次调试、短日志、低频命令响应
中断_IT函数启动后返回,后续靠中断和回调推进中小数据量、希望主循环不被阻塞
DMA_DMA数据搬运由 DMA 完成,CPU 只处理半满、满、IDLE 或完成事件高频接收、大块数据、连续串口流
IDLE + DMAReceiveToIdle_DMA 或手动 IDLE用空闲线判断不定长帧结束AT 指令、传感器不定长输出、自定义协议接收

学习和排查阶段建议先用阻塞发送确认硬件链路,再使用中断接收验证字节到达,最后再切换 DMA。DMA 一旦引入,问题就不再只是 UART 本身,还包括 DMA 通道、缓冲区生命周期、缓存一致性、回调触发条件和多任务同步。

3.5 返回状态、错误码与回调

阻塞 API 常见返回值包括 HAL_OKHAL_ERRORHAL_BUSYHAL_TIMEOUT。返回值不是 HAL_OK 时,不要只反复重试函数,而要读取 UART 错误码,并结合波形和软件状态定位。

HAL_StatusTypeDef status = HAL_UART_Receive(&huart1, buf, len, 100);
if (status != HAL_OK) {
uint32_t error = HAL_UART_GetError(&huart1);
printf("UART status=%d, error=0x%08lX\r\n", status, error);
}

中断或 DMA 模式下,常见回调包括发送完成、接收完成、半传输完成和错误回调。不要在回调里做长时间阻塞操作,也不要在接收中断里直接执行大量 printf。更稳妥的做法是:回调只搬运数据、置标志或释放信号量,实际解析和打印放到主循环或 RTOS 任务里。

4. 故障排查

4.1 排查原则

UART 故障推荐按“电平与接线 → 串口参数 → 波形证据 → 软件缓冲 → 上层协议”的顺序排查。先确认 TX/RX 是否交叉、是否共地、串口工具选择是否正确,再看波特率和 8N1 等配置,最后才深入中断、DMA、环形缓冲区和协议解析。

UART 故障排查从供电共地和 TX/RX 接线开始,依次检查电平转换、波特率与帧格式、逻辑分析仪波形、RX/TX 状态标志、缓冲区与中断 DMA、上层协议边界

图 4:UART 排查不要一上来改代码,先确认物理连接和双方串口参数,再进入状态标志、缓冲区和协议解析。

4.2 问题一:串口助手没有任何输出

  • 发生条件:程序调用了发送函数,但电脑串口工具没有收到字符。
  • 可观察证据:串口助手空白,逻辑分析仪在 MCU TX 引脚看不到波形,或只在错误引脚看到波形。
  • 常见原因:TX/RX 没有交叉、没有共地、选错 COM 口、GPIO 复用配置错误、外设时钟没开、波特率不一致、USB-TTL 模块电平不兼容。
  • 排查顺序:先确认 COM 口和串口工具打开成功;再测 MCU TX 引脚是否有波形;然后检查 TX 是否接到 USB-TTL 的 RX;最后检查 CubeMX 复用功能和初始化代码是否执行。
  • 处理方法:统一使用 115200 8N1 做最小测试;用示波器或逻辑分析仪直接看 TX 引脚;确认 USB-TTL 模块支持目标板电压。

4.3 问题二:收到乱码

  • 发生条件:能收到字符,但内容是乱码、缺字、随机符号或中文日志显示异常。
  • 可观察证据:逻辑分析仪能解码但参数调整后结果变化;串口助手显示固定或随机乱码。
  • 常见原因:波特率不一致、数据位/校验位/停止位不一致、系统时钟配置错误、串口工具字符编码不匹配、RS-232/TTL 电平直接相连。
  • 排查顺序:先确认两端均为 115200 8N1;再用逻辑分析仪按不同波特率尝试解码;检查 MCU 时钟树和 UART 时钟源;最后确认是否需要 RS-232 电平转换。
  • 处理方法:降低波特率到 9600 或 115200 复测;确认系统时钟配置正确;二进制协议不要直接按文本显示。

乱码排查的关键是不要只盯软件字符串。只要逻辑分析仪按照正确波特率能稳定解码,说明硬件发送大概率正常;如果逻辑分析仪也解不出稳定字节,优先看波特率、时钟和电平。

4.4 问题三:接收丢字节或触发 Overrun

  • 发生条件:短数据正常,连续高速输出或大量日志时丢字节。
  • 可观察证据:HAL 错误码中出现 Overrun 类错误,接收帧 CRC 错误率升高,环形缓冲区溢出。
  • 常见原因:接收中断没有及时重启,回调里执行耗时操作,波特率过高,主循环解析太慢,缓冲区太小,DMA 缓冲区边界处理错误。
  • 排查顺序:先确认中断是否持续触发;再检查回调是否只做轻量操作;然后统计环形缓冲区水位;最后根据实际流量调整 DMA 或缓冲区大小。
  • 处理方法:中断里只入队或写环形缓冲;复杂解析放到任务中;高吞吐接收改用 DMA + IDLE;必要时降低波特率或启用硬件流控。

UART 接收比发送更容易出问题,因为外部数据什么时候来由对端决定。只要软件没有及时取走旧数据,硬件接收寄存器就可能被新数据追上。

4.5 问题四:DMA 或中断只工作一次

  • 发生条件:第一次接收或发送正常,第二次调用返回 HAL_BUSY,或后续没有回调。
  • 可观察证据:第一次回调进入,后续不再进入;HAL 状态停在忙状态;DMA 计数器没有重新装载。
  • 常见原因:接收完成后没有重新启动 HAL_UART_Receive_IT(),DMA 不是循环模式却没有重新启动,错误回调没有处理,DMA/USART 中断没有正确使能,缓冲区变量生命周期错误。
  • 排查顺序:先看回调是否执行;再看回调里是否重新启动接收;检查 NVIC 中 USART 和 DMA 中断是否都启用;最后看错误回调是否曾经触发。
  • 处理方法:在完成回调或任务中重新启动接收;处理错误后清理并重启;DMA 缓冲区使用静态或全局存储,不要用已经返回的局部变量。

4.6 问题五:RS-485 只能发送不能接收,或尾字节丢失

  • 发生条件:使用 RS-485 收发器时,发送能看到 A/B 波形,但对端收不到完整帧,或本机收不到回复。
  • 可观察证据:逻辑分析仪显示最后一个字节不完整;DE 引脚过早拉低;总线方向一直保持发送。
  • 常见原因:DE/RE 方向控制错误,发送后未等待 TC 就切回接收,A/B 线接反,终端电阻或偏置异常,多节点同时发送冲突。
  • 排查顺序:先单独看 MCU TX 和 DE 时序;再看收发器 A/B 差分波形;确认发送最后一个停止位结束后才释放 DE;最后检查协议层是否等待从机响应间隔。
  • 处理方法:发送前拉高 DE,等待发送完成后再拉低 DE;确认 A/B 标识;使用 Modbus RTU 等协议时遵守帧间隔和主从时序。

5. 性能、可靠性与安全性

5.1 性能

UART 的有效吞吐量低于波特率对应的裸 bit 速率,因为每个字节还要携带起始位、校验位和停止位。115200 8N1 的有效载荷约为 11.5 KB/s,实际应用中还要扣除协议帧头、长度、CRC、转义和任务调度开销。

提高波特率可以提升吞吐,但会降低时钟误差和线缆质量的裕量。工程中不要只看串口工具能不能打开高波特率,还要确认 MCU 时钟源、过采样配置、USB-TTL 模块、隔离器、RS-232/RS-485 收发器和线缆是否都支持目标速率。

5.2 可靠性

可靠 UART 驱动不应该只关心 HAL_OK。至少要考虑:

  • 接收使用环形缓冲区,避免突发数据直接覆盖。
  • 上层协议带帧头、长度、校验和超时,避免丢 1 字节后永久错位。
  • 错误回调记录 OREFEPE 等错误,并能恢复接收。
  • 中断里不做阻塞发送、复杂解析和大量 printf
  • 高速或不定长接收优先考虑 DMA + IDLE 或双缓冲策略。
  • RTOS 项目中用队列、流缓冲或信号量把 ISR 与任务解耦。

5.3 安全性

UART 常用于调试和板内通信,很多产品会把命令行、日志或升级接口暴露在排针、测试点或外壳内部接口上。发布版本中需要避免把密钥、认证结果、隐私数据或设备控制命令直接打印到串口日志中。若 UART 命令能修改配置、擦写 Flash 或控制设备动作,应增加权限校验、命令白名单、长度检查和异常输入处理。

6. 结论

UART 的学习重点不是背某一个 HAL 函数,而是理解“没有共享时钟的串行字节流如何被收发器可靠还原”。只要掌握 TX/RX/GND 与电平标准、起始位和停止位、8N1 帧格式、波特率误差、接收采样、状态标志、缓冲区和 IDLE/DMA 接收机制,就能把大多数串口问题拆成可验证的硬件、协议或软件问题。实际项目中,最终结论仍应由真实波形、错误码、日志和测试结果支撑。

7. 官方参考资料

  1. Microchip TB3208:Basic Operation of UART with Protocol Support
  2. Microchip TB3331:Debugging Serial Interfaces in Embedded Systems
  3. ST:Getting started with UART
  4. ST:HAL UART How to Use
  5. ST:HAL UART Functions
  6. Analog Devices:Fundamentals of RS-232 Serial Communications
  7. Analog Devices AN-960:RS-485/RS-422 Circuit Implementation Guide