1. UART基础回顾:串行通信原理与帧结构详解

做嵌入式这么多年,UART 是我打交道最多的接口之一。说它简单吧,确实就两根线;说它坑多吧,我早期一个项目因为停止位配置不对,整批设备在高温下丢数据,排查了整整三天。所以这一章,咱们把 UART 的底子彻底捋一遍。

1.1 串行通信 vs 并行通信

先搞清楚一个基本概念:为什么叫“串行”?

并行通信是一次传多位,比如 8 位数据同时通过 8 根线传输。速度快,但线多、成本高、抗干扰差。串行通信则是一位一位地传,只用 1~2 根数据线。速度看似慢,但线少、距离远、成本低。

我个人的习惯是:板内近距离、对延迟敏感的场景用并行(比如 LCD 屏接口);板间通信、长距离、或者引脚紧张时,无脑选串行。UART 就是串行通信的典型代表。

对比项 串行通信 并行通信
数据线数量 1~2 根 8 根以上
传输距离 远(可达几十米) 近(通常 < 1 米)
抗干扰能力 强 弱
硬件成本 低 高
典型应用 UART, SPI, I2C 并口打印机, 旧式总线

1.2 UART 帧结构详解

UART 传输的基本单位叫“帧”。一帧数据包含以下几个部分:

  • 起始位:1 位,固定为低电平(逻辑 0)。告诉接收端“准备接收”。
  • 数据位:5~9 位,常见为 8 位。这是真正的数据内容。
  • 校验位:0 或 1 位,可选。用于简单的错误检测。
  • 停止位:1、1.5 或 2 位,固定为高电平(逻辑 1)。表示一帧结束。

你想想看,为什么要有起始位和停止位?因为 UART 是异步通信,没有单独的时钟线。接收端必须靠起始位的下降沿来同步时钟,再靠停止位来确认帧结束。没有它们,收发双方根本对不上节奏。

核心要点:UART 帧结构 = 起始位(1) + 数据位(5~9) + 校验位(0/1) + 停止位(1/1.5/2)

1.3 起始位详解

起始位是 UART 通信的“发令枪”。

空闲时,TX 线保持高电平。当发送端要发数据时,先把 TX 线拉低一个位时间。接收端检测到这个下降沿后,就知道“数据要来了”,开始按约定的波特率采样后续的位。

我曾经遇到过一个坑:某款 MCU 的 UART 模块对起始位的最小脉宽有要求,如果发送端的下降沿不够陡峭(比如线缆太长导致信号边沿变缓),接收端可能检测不到起始位,整帧数据就丢了。后来我在 TX 线上加了一个 10kΩ 上拉电阻,问题解决。

注意:起始位的下降沿是 UART 同步的关键。信号线过长、电容过大,会导致边沿变缓,接收端可能漏检起始位。建议 TX/RX 走线尽量短,必要时加施密特触发器整形。

1.4 数据位详解

数据位是帧的核心,承载实际信息。

常见配置是 8 位数据,因为一个字节正好 8 位,方便和内存、寄存器对接。但有些老协议或特殊场景会用 7 位(比如 ASCII 字符传输)或 9 位(比如多机通信中的地址/数据标志)。

数据位的传输顺序是 LSB 优先(最低有效位在前)。举个例子,要发送 0x55(二进制 01010101),实际线上先发最低位 1,再依次发 0、1、0、1、0、1,最后发最高位 0。

我建议新手在调试时,用逻辑分析仪抓一下波形,对照着看数据位的顺序,印象会非常深刻。

数据位长度 常见用途 备注
5 位 老式电传机 现在极少用
7 位 ASCII 字符传输 部分 Modbus 协议用
8 位 通用数据通信 最常用,默认配置
9 位 多机通信地址标志 RS-485 多机模式常见

1.5 校验位详解

校验位用于简单的错误检测。UART 支持三种校验模式:

  • 无校验 (None):不发送校验位,帧长度最短。
  • 奇校验 (Odd):数据位 + 校验位中“1”的个数为奇数。
  • 偶校验 (Even):数据位 + 校验位中“1”的个数为偶数。

举个例子:数据位是 0x55(二进制 01010101,有 4 个 1)。

  • 奇校验:校验位应为 1(使总 1 数为 5,奇数)。
  • 偶校验:校验位应为 0(使总 1 数为 4,偶数)。

说实话,校验位只能检测奇数个位的翻转错误。如果两个位同时翻转,校验位就检测不出来了。所以它只适合低噪声环境。我在工业现场一般会用更可靠的 CRC 校验,而不是依赖 UART 的奇偶校验。

经验之谈:如果通信环境噪声较大,建议关闭 UART 的硬件校验,在应用层自己加 CRC 或累加和校验。硬件校验位反而会占用一个位的时间,降低有效数据吞吐量。

1.6 停止位详解

停止位标志一帧的结束,固定为高电平。

停止位可以是 1 位、1.5 位或 2 位。为什么会有 1.5 位这种奇怪的长度?因为早期有些 UART 硬件用 1.5 位来给接收端留出处理时间。现在大多数场景用 1 位停止位就够了。

什么时候用 2 位停止位?

  • 波特率较高时(比如 115200 以上),给接收端更多时间处理。
  • 使用机械继电器或光耦隔离时,信号延迟较大,需要更长的停止位来保证帧间隔。

我记得有一次调试一个 250kbps 的 UART 链路,接收端总是偶尔丢帧。查了半天,发现是停止位太短,接收端的 FIFO 没来得及把数据搬走,下一帧就来了。把停止位从 1 改成 2,问题消失。

1.7 UART 帧结构完整图示

下面我用一张 SVG 图把整个帧结构画出来,方便你对照理解。

UART 帧结构示意图(8N1 配置) 起始位 1 bit 数据位(8 bits) LSB 优先传输 校验位 0/1 bit 停止位 1/1.5/2 bits 典型波形(发送 0x55 = 01010101) 空闲 起始 D0=1 D1=0 D2=1 D3=0 D4=1 D5=0 D6=1 D7=0 无校验 停止位 说明:8N1 配置 = 8 数据位 + 无校验 + 1 停止位。起始位固定为低,停止位固定为高。 数据位按 LSB 优先顺序传输,0x55 的二进制为 01010101,线上先发最低位 D0=1。

1.8 常见帧格式配置

实际项目中,最常见的帧格式是 8N1(8 数据位、无校验、1 停止位)。但不同场景有不同选择:

配置名称 数据位 校验位 停止位 典型场景
8N1 8 无 1 通用串口通信,默认配置
8E1 8 偶校验 1 Modbus RTU 部分实现
8O1 8 奇校验 1 老式终端设备
7E1 7 偶校验 1 ASCII 字符传输
8N2 8 无 2 高波特率或长线传输

我的建议:除非有特殊要求,否则一律用 8N1。它兼容性最好,效率最高。如果通信环境有噪声,不要依赖硬件校验位,在应用层做 CRC 校验更可靠。

1.9 本章小结

UART 帧结构看似简单,但每个位都有它的设计目的。起始位负责同步,数据位承载信息,校验位提供基础检错,停止位保证帧间隔。理解这些基础,后面调波特率、优化性能时才能得心应手。