4. UART 通信模式:单工、半双工、全双工对比与应用场景分析
UART 作为最基础的串行通信接口,其通信模式决定了数据在设备间的流动方式。理解单工、半双工、全双工三种模式的区别,是设计高效 UART 驱动的关键前提。本章将从物理层信号流向、驱动实现差异、典型应用场景三个维度进行系统对比。
💡 核心概念: 通信模式由数据线数量与方向控制逻辑共同决定。UART 硬件本身支持全双工(独立的 TX/RX 线),但上层协议或应用场景可能将其限制为半双工或单工模式。
4.1 单工模式 (Simplex)
单工模式下,数据只能沿一个固定方向传输,接收端无法向发送端回传任何数据。UART 硬件只需连接 TX → RX 一条数据线,GND 共地。
4.1.1 技术特征
- 数据线数量: 1 根(TX → RX)+ GND
- 方向控制: 无,硬件固定
- 驱动实现: 发送端只需 TX FIFO 写操作,接收端只需 RX FIFO 读操作
- 流控: 不需要硬件流控(RTS/CTS)
4.1.2 典型应用场景
| 场景 | 说明 | 驱动关注点 |
|---|---|---|
| 传感器数据上报 | 温度/湿度传感器只向主机发送数据 | 接收端中断或 DMA 读取 |
| 广播式日志输出 | 嵌入式设备通过 UART 输出调试日志 | 发送端轮询或 DMA 写入 |
| 单向 LED 控制 | 主机发送命令控制 LED 灯板 | 无需接收处理 |
🔧 驱动提示: 单工模式下,接收端驱动无需考虑发送逻辑,可简化中断处理函数。但需注意接收 FIFO 溢出问题——如果主机读取不及时,数据会被覆盖。
4.2 半双工模式 (Half-Duplex)
半双工模式下,通信双方可以互相发送数据,但同一时刻只能有一方发送。典型实现是使用单根数据线(TX/RX 复用),或通过软件控制方向切换。
4.2.1 技术特征
- 数据线数量: 1 根(TX/RX 共用)+ GND,或 2 根但软件控制方向
- 方向控制: 需要 GPIO 或协议层切换(如 RS-485 的 DE/RE 引脚)
- 驱动实现: 发送前需将 UART 模式切换为 TX,发送完成后切换回 RX
- 流控: 通常需要软件协议避免冲突(如 Modbus 的主从轮询)
4.2.2 方向切换时序
/* 半双工模式切换示例(RS-485 驱动) */
void uart_halfduplex_tx_start(struct uart_port *port)
{
/* 1. 等待当前接收完成 */
while (!(readl(port->membase + UART_LSR) & LSR_TEMT));
/* 2. 切换 GPIO 为发送模式(使能 DE) */
gpiod_set_value(port->rs485->de_gpio, 1);
/* 3. 使能发送器,禁用接收器 */
uart_update_mctrl(port, TIOCM_RTS, 0);
}
void uart_halfduplex_tx_stop(struct uart_port *port)
{
/* 1. 等待发送移位寄存器空 */
while (!(readl(port->membase + UART_LSR) & LSR_TEMT));
/* 2. 切换 GPIO 为接收模式(使能 RE) */
gpiod_set_value(port->rs485->de_gpio, 0);
/* 3. 使能接收器 */
uart_update_mctrl(port, TIOCM_RTS, 1);
}
4.2.3 典型应用场景
| 场景 | 说明 | 驱动关注点 |
|---|---|---|
| RS-485 工业总线 | Modbus RTU 协议,主从轮询通信 | 方向切换时序、发送完成等待 |
| 单线 UART(1-Wire 模拟) | 调试接口或低成本传感器网络 | 开漏输出、上拉电阻、位时序 |
| 红外通信 (IrDA) | 半双工红外收发 | 编码/解码、载波调制 |
⚠️ 常见陷阱: 半双工驱动中最容易出错的是方向切换的“死锁”——发送完成后未及时切回接收模式,导致对方发送的数据丢失。建议在发送完成中断中立即切换方向,并使用定时器做超时保护。
4.3 全双工模式 (Full-Duplex)
全双工模式下,通信双方可以同时发送和接收数据。UART 硬件原生支持此模式,因为 TX 和 RX 是独立的物理线路和 FIFO。
4.3.1 技术特征
- 数据线数量: 2 根(TX ↔ RX 交叉连接)+ GND
- 方向控制: 无,硬件同时支持收发
- 驱动实现: 发送和接收完全独立,可并行处理
- 流控: 需要硬件流控(RTS/CTS)防止 FIFO 溢出
4.3.2 全双工驱动架构
4.3.3 典型应用场景
| 场景 | 说明 | 驱动关注点 |
|---|---|---|
| 标准 UART 调试串口 | Linux 内核早期启动日志 + 交互式 shell | 中断处理、环形缓冲区 |
| 蓝牙 HCI UART 传输 | 蓝牙芯片与主机间的 HCI 命令/事件/数据 | DMA 传输、硬件流控 |
| GPS 模块数据接收 | GPS 持续发送 NMEA 语句,主机可发送配置命令 | 高波特率、DMA 接收 |
| 高速串口屏通信 | MCU 发送绘图命令,屏幕返回触摸事件 | 双缓冲、DMA 乒乓操作 |
4.4 三种模式综合对比
| 对比维度 | 单工 | 半双工 | 全双工 |
|---|---|---|---|
| 数据流向 | 单向固定 | 双向分时 | 双向同时 |
| 物理线数 | 1 根 + GND | 1 根 + GND 或 2 根 | 2 根 + GND |
| 硬件流控 | 不需要 | 可选(RS-485 需 DE/RE) | 推荐(RTS/CTS) |
| 驱动复杂度 | 低 | 中(方向切换逻辑) | 高(并发收发 + 流控) |
| 吞吐量 | 低(单向) | 中(需切换时间) | 高(同时双向) |
| 典型波特率 | 9600 ~ 115200 | 9600 ~ 115200 | 115200 ~ 3Mbps+ |
| Linux 驱动支持 | 标准 UART 驱动 | 需 RS-485 半双工扩展 | 标准 UART 驱动 + 流控 |
4.5 驱动开发中的模式选择策略
📋 决策指南:
- 优先选择全双工 — 如果硬件支持且线数允许,全双工驱动最简单(无需方向切换),且吞吐量最高。
- 半双工用于长距离/多节点 — RS-485 总线必须使用半双工,驱动需重点处理方向切换时序和总线冲突检测。
- 单工用于纯数据采集 — 如果设备只发不收(如传感器),单工模式可节省 CPU 中断开销。
- 流控匹配 — 全双工高波特率必须启用硬件流控,否则 FIFO 溢出会导致数据丢失。
4.5.1 模式切换的驱动接口
在 Linux 内核中,通过 termios 结构体或 TIOCSRS485 ioctl 配置通信模式:
/* 设置半双工 RS-485 模式 */
struct serial_rs485 rs485conf;
rs485conf.flags = SER_RS485_ENABLED; /* 启用半双工 */
rs485conf.flags |= SER_RS485_RTS_ON_SEND; /* 发送时 RTS 高 */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND; /* 发送后 RTS 低 */
rs485conf.delay_rts_before_send = 1; /* 发送前延迟 1ms */
rs485conf.delay_rts_after_send = 1; /* 发送后延迟 1ms */
ioctl(fd, TIOCSRS485, &rs485conf);
/* 设置全双工模式(默认) */
struct termios2 tio;
ioctl(fd, TCGETS2, &tio);
tio.c_cflag &= ~CMSPAR; /* 清除半双工特殊标志 */
ioctl(fd, TCSETS2, &tio);
💡 经验之谈: 在嵌入式 Linux 中,UART 驱动默认工作在全双工模式。如果需要半双工 RS-485,务必在设备树中配置
rs485-mode 属性,并在驱动中实现 uart_ops->rs485_config() 回调函数。
4.6 本章小结
- 单工:最简单,适合单向数据流场景,驱动只需处理单方向 FIFO。
- 半双工:需要方向切换逻辑,驱动复杂度中等,常见于 RS-485 工业总线。
- 全双工:UART 原生模式,吞吐量最高,驱动需处理并发收发和硬件流控。
- 选择依据:根据物理层标准(RS-232/RS-485)、线数限制、吞吐量需求和协议要求综合决定。