1. UART 基础概念
1.1 UART 通信协议原理
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)是一种采用异步串行通信方式的硬件接口协议。与 SPI、I²C 等同步协议不同,UART 在传输数据时不依赖共享时钟信号,而是通过收发双方预先约定的波特率(Baud Rate)来同步数据采样时刻。
UART 通信的基本链路结构如下:
核心特征: 全双工(两条独立数据线 TX / RX)、异步(无时钟线)、点对点(仅两个设备通信)。
1.2 数据帧结构:起始位 / 数据位 / 校验位 / 停止位
UART 以帧(Frame)为基本传输单元。一帧数据由以下字段按固定顺序组成:
| 字段 | 位宽 | 电平状态 | 功能说明 |
|---|---|---|---|
| 起始位 | 1 bit | 高 → 低(下降沿) | 标志帧开始,接收器以此边沿同步采样时钟 |
| 数据位 | 5 ~ 9 bit(常用 8 bit) | LSB 优先或 MSB 优先 | 承载有效载荷数据 |
| 校验位 | 0 / 1 bit | 奇校验 / 偶校验 / 无 | 可选检错机制 |
| 停止位 | 1 / 1.5 / 2 bit | 高电平 | 帧结束标志,为下一帧起始位提供间隔 |
工程经验: 嵌入式系统中默认配置通常为 8N1(8 数据位、无校验、1 停止位)。该配置在效率和兼容性之间取得最佳平衡。
1.3 波特率计算
波特率(Baud Rate)定义每秒传输的符号数。在 UART 中,一个符号对应一个 bit,因此波特率等于比特率(bps)。
波特率与系统时钟、分频器的关系如下:
核心公式:
波特率 = 系统时钟频率 / (16 × 分频系数)
或:波特率 = 系统时钟频率 / (分频系数)
波特率 = 系统时钟频率 / (16 × 分频系数)
或:波特率 = 系统时钟频率 / (分频系数)
不同 UART 硬件实现的分频方式略有差异,常见两种模式:
| 模式 | 采样倍率 | 分频公式 | 典型应用 |
|---|---|---|---|
| 标准模式 | 16 倍过采样 | DIV = CLK / (16 × BAUD) | STM32、NXP LPC 系列 |
| 高速模式 | 8 倍过采样 | DIV = CLK / (8 × BAUD) | 高波特率场景(≥ 1 Mbps) |
常用波特率与分频系数示例(假设系统时钟 16 MHz,16 倍过采样):
| 目标波特率 | 分频系数(DIV) | 实际波特率 | 误差 |
|---|---|---|---|
| 9600 | 104.167 → 104 | 9615.38 | +0.16% |
| 19200 | 52.083 → 52 | 19230.77 | +0.16% |
| 115200 | 8.681 → 9 | 111111.11 | -3.55% |
| 921600 | 1.085 → 1 | 1000000.00 | +8.51% |
工程警告: 波特率误差应控制在 ±2% 以内,否则接收端采样点偏移可能导致帧错误(Framing Error)。115200 bps 在 16 MHz 下误差 -3.55%,已接近临界值,建议改用 8 倍过采样或调整系统时钟。
1.4 波特率误差与采样窗口
UART 接收器使用过采样技术(通常 16 倍)在每个 bit 周期内采集多个样本,通过多数决确定实际电平值。采样窗口位于每个 bit 的中间区域,以容忍一定的时钟偏差。
波特率误差容忍度取决于以下因素:
- 帧长度: 帧越长(如 9 位数据 + 2 位停止),累积误差越大。
- 过采样倍数: 16 倍过采样比 8 倍过采样容忍度更高。
- 起始位同步精度: 起始位下降沿的检测误差直接影响后续采样点。
经验法则: 对于 8N1 帧(10 bit 总长),16 倍过采样下可容忍约 ±4% 的波特率误差;对于长帧(如 9 位数据 + 2 停止 = 12 bit),容忍度降至 ±3% 以内。
1.5 常见波特率标准与选型建议
| 波特率 | 应用场景 | 线缆长度 | 备注 |
|---|---|---|---|
| 9600 | 调试串口、低速传感器 | ≤ 15 m | 最通用,兼容性最好 |
| 19200 | 工业控制、GPS 模块 | ≤ 10 m | 中等速率 |
| 115200 | 标准调试终端、蓝牙模块 | ≤ 3 m | 嵌入式系统默认首选 |
| 921600 | 高速数据采集、固件下载 | ≤ 1 m | 需注意时钟误差 |
| 2 Mbps+ | RS-485 高速总线 | ≤ 0.5 m | 需硬件流控支持 |
驱动开发建议: 在 Linux 内核 UART 驱动中,波特率通过
termios 结构体的 c_cflag 字段设置,驱动层调用 uart_update_timeout() 和 uart_set_termios() 回调完成分频系数重算。后续章节将深入讲解中断模式下的波特率动态切换实现。