先搞懂它是什么
- UART(通用异步收发器):用两根线(TX 发、RX 收)逐位传数据的串行接口,电脑串口、传感器、蓝牙模块调试口大多用它。
- 异步:收发双方没有时钟线,靠双方约定好的“波特率”和对齐方式自己数位,所以收发波特率必须一致。
- 为什么必学:串口是嵌入式开发最常用的“日志出口”和调试手段,SDK 例程统一用 2000000 波特率打印日志,就是这个道理。
层层拆解原理
1. 帧格式:一个字节怎么传
空闲时 TX 保持高电平。发送一个字节按下面的顺序走:
- 起始位:把线拉低,接收方据此对齐后续位数。
- 数据位:常见 8 位(即 8N1 中的 8)。
- 校验位:可选的奇偶校验,用于查错不纠错。
- 停止位:恢复高电平,准备下一帧。
“8N1”的意思是:8 位数据、无校验(None)、1 位停止位——大多数嵌入式串口默认配置。
2. 波特率:双方怎么“数位”
波特率 = 每秒传输的位数(bit/s)。发送方按波特率把每一位“铺”在线上,接收方用同一个波特率采样。只要波特率不一致,接收方就会把位“数错”,得到乱码。
波特率是由外设时钟分频得到的,所以“换时钟源/改分频后没重新算波特率”也会导致乱码。
3. 电平与接口形态
| 形态 | 电平标准 | 典型场景 |
|---|---|---|
| TTL 电平 | 0~3.3V/5V | MCU 与传感器/模组直连 |
| RS-232 | ±12V 左右 | 老式电脑串口,需电平转换芯片 |
| USB 转串口 | 芯片转换 | 电脑调试(如 CH340/CP2102) |
开发板上的 USB 口通常内置了 USB 转串口芯片,所以电脑上看到的是 COM 口,板子内部实际是 TTL 串口。
4. 数据流向:读缓冲与写缓冲
MCU 的 UART 外设一般带接收 FIFO:数据到达后先存进 FIFO,程序稍后去读;程序也可以先写发送 FIFO,由硬件按波特率慢慢发出去。这样程序不必逐位等待,效率更高。
进阶用法:
- 中断接收:有数据到达时触发中断,程序在中断里收数据,不阻塞主流程。
- DMA 接收:硬件把 FIFO 里的数据直接搬进内存,CPU 完全不用参与,适合大数据量传输。
- 流控(RTS/CTS):双方通过额外引脚通知“我忙/我可以收”,防止数据丢失。
结合 SDK 看实现
SDK 里串口初始化同样是“取设备 → 配置波特率 → 注册收发回调/中断”的套路:
struct bflb_device_s *uart0 = bflb_device_get_by_name("uart0");
/* 配置 2000000 波特率,8 数据位,无校验,1 停止位 */
bflb_uart_init(uart0, 2000000, UART_DATA_LEN_8, UART_PARITY_NONE, UART_STOP_BITS_1);打印日志用的 printf 最终也是往这个串口 FIFO 里写数据,再由硬件一位一位发出去——所以“printf 能打印”就说明 UART 通路正常。
常见考点 / 面试题
什么是 8N1?
8 位数据位、无校验位(None)、1 位停止位,是嵌入式串口最常见的帧格式;收发双方必须配置一致。
串口乱码最常见的原因是什么?
波特率不一致(或时钟/分频被改导致波特率计算偏差)、接线 RX/TX 接反、共地问题。先核对波特率,再看接线。
UART 是全双工吗?
是。TX 和 RX 是独立的两根线,可以同时收发;这是它相比 I2C/SPI 共享时钟线的不同点之一。
为什么传数据要分“起始位/数据位/停止位”?
因为没有时钟线,接收方要靠起始位的下降沿对齐采样时刻,数据位承载内容,停止位保证帧与帧之间有明确边界。
中断接收和 DMA 接收有什么区别?
中断接收:每个数据到达都打断 CPU 去搬运,适合小数据量;DMA:硬件直接搬数据到内存,CPU 空闲,适合大批量或高速传输。
遇到问题?
如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

