一、UART 基础回顾:异步串行通信原理与帧格式
各位同学,咱们正式开始这门课之前,先把 UART 的老底儿翻出来晒晒。你可能会说:“UART 嘛,我用了好几年了,有啥好讲的?” 嗯,我当年也是这么想的,直到有一次在产线上被一个波特率偏差问题折腾了整整两天…… 从那以后,我养成了一个习惯:每次调 UART,先把基础概念在心里过一遍。
1.1 异步串行通信——没有时钟线,怎么对得上?
UART 的全称是 Universal Asynchronous Receiver/Transmitter,通用异步收发器。说白了,它就是一种不需要额外时钟线的串行通信方式。
你想想看,SPI 和 I²C 都有时钟线(SCLK、SCL),收发双方靠这根线同步。但 UART 只有两根数据线:TX(发送)和 RX(接收)。没有时钟线,两边怎么对齐节奏?
答案就藏在“异步”这两个字里。收发双方各自用自己的时钟,但必须提前约定好一个相同的“节拍”——这就是波特率。我习惯把波特率理解成“每秒敲多少下鼓点”,两边鼓点频率一致,才能踩在同一个拍子上。
1.2 帧格式——一帧数据长什么样?
UART 的数据是一帧一帧传的。每一帧就像一个小信封,里面装着你要发的数据,外面包着“信封皮”。这个信封皮包括:起始位、数据位、校验位(可选)、停止位。
我画了一张帧格式的结构图,你先看一眼整体,我再拆开讲。
好,咱们一个一个拆开看。
起始位(Start Bit)
空闲时,TX/RX 线都是高电平。发送端要发数据了,先把线拉低一个 bit 的时间。这个高→低跳变就是起始位。接收端检测到这个跳变,就知道“要开始收数据了”。
我在项目中遇到过一个问题:接收端没检测到起始位,整包数据全丢了。后来发现是线太长,信号上升沿变缓了。嗯,起始位的检测对信号质量很敏感,后面讲故障定位时会细说。
数据位(Data Bits)
起始位之后,就是真正的数据了。常见配置是 8 位数据(1 字节),也有 5、6、7、9 位的。数据位按LSB 先发的顺序传输。比如你要发 0x55(二进制 01010101),先发最低位 1,再发 0、1、0、1、0、1,最后发最高位 0。
校验位(Parity Bit)
校验位是可选的,用于简单的错误检测。分三种:
- 无校验(None):不发送校验位,帧里没有这个字段。
- 奇校验(Odd):数据位中 1 的个数 + 校验位 = 奇数。
- 偶校验(Even):数据位中 1 的个数 + 校验位 = 偶数。
举个例子:数据位是 0x55(01010101),里面有 4 个 1(偶数)。偶校验时校验位为 0,奇校验时校验位为 1。
注意:校验位只能检测奇数个 bit 的错误。如果两个 bit 同时翻转,校验位是看不出来的。我曾经在一个工控项目里被这个坑过——偶发双 bit 翻转,校验位完全没反应。后来加了 CRC 才解决。
停止位(Stop Bit)
数据位(和校验位)发完后,发送端把线拉高至少一个 bit 时间。这个高电平就是停止位。停止位可以是 1 bit、1.5 bit 或 2 bit。为什么要有停止位?说白了就是给接收端一点时间“消化”刚收到的数据,准备接收下一帧。
1.3 波特率——通信的“节拍器”
波特率(Baud Rate)就是每秒传输的符号数。在 UART 里,一个符号就是一个 bit,所以波特率 = 比特率(bps)。
常见波特率有:9600、19200、38400、115200、921600 等。选哪个?我一般遵循这个原则:
| 场景 | 推荐波特率 | 说明 |
|---|---|---|
| 调试输出、低速传感器 | 9600 / 19200 | 抗干扰强,线长 10 米以上也能稳定 |
| 一般数据采集、控制 | 38400 / 57600 | 速度和稳定性的折中 |
| 高速数据传输、固件升级 | 115200 / 921600 | 线长建议 1 米以内,注意信号完整性 |
波特率偏差是个大问题。收发双方的波特率必须一致,误差一般要求 ±2% 以内。为什么是 2%?因为 UART 在数据位中间采样,如果偏差太大,采样点会逐渐偏移,最后采到错误的 bit。
我算过一笔账:115200 bps,每个 bit 约 8.68 μs。如果收发双方时钟偏差 3%,累积到第 8 个数据位时,采样点偏移了约 2 μs——已经超过半个 bit 宽度了。结果就是:数据全错,但你还查不出原因。
1.4 本章小结
这一章咱们把 UART 的底子打牢了:
- 异步串行通信:没有时钟线,靠波特率约定和帧格式同步。
- 帧格式:起始位(1 bit)→ 数据位(5~9 bit)→ 校验位(可选)→ 停止位(1/1.5/2 bit)。
- 波特率:双方必须一致,误差控制在 ±2% 以内。