UART通信故障定位信号捕获与协议解码调试实战 - 第1节
一、UART 的前世今生
UART,全称 Universal Asynchronous Receiver/Transmitter,通用异步收发器。这东西的历史,比我们大多数工程师的工龄都长。
上世纪 60 年代,计算机和终端之间需要通信。那时候的接口五花八门,各搞各的。直到 70 年代,Motorola 和 Intel 开始推专用的 UART 芯片,比如经典的 8250、16550。我刚开始做嵌入式那会儿,还在用 16550 的 PC 串口调试,一个芯片搞定收发,省心得很。
说白了,UART 就是把并行数据转成串行,一根线发、一根线收。不需要时钟线,两边约定好速度就行。这个「不需要时钟线」的特点,让它在很多场合比 SPI、I2C 更灵活。
二、全双工异步通信原理
2.1 什么叫全双工?
全双工就是同时能发能收。UART 用两根独立的数据线:TX(发送)和 RX(接收)。发的不影响收的,收的也不影响发的。你想想看,就像两个人打电话,可以同时说话,也能同时听。
半双工呢?对讲机那种,按着键说,松手才能听。全双工显然效率更高。我在调试一个多传感器采集系统时,就吃过半双工的亏——主机轮询太慢,后来全换成 UART 全双工,数据吞吐量直接翻倍。
2.2 异步怎么理解?
异步就是没有独立的时钟线。收发双方各自用自己的时钟,靠约定的波特率和数据帧格式来同步。
那怎么保证两边节奏一致?靠的是起始位。接收端检测到起始位的下降沿,就开始按约定的波特率采样数据位。这就是所谓的「起始位同步」。
三、数据帧格式详解
UART 的数据帧,就像一列火车。每一帧由以下几个车厢组成:
| 字段 | 长度 | 说明 |
|---|---|---|
| 起始位 | 1 bit | 固定为低电平(逻辑 0),标志一帧开始 |
| 数据位 | 5~9 bit | 常用 8 bit,低位在前(LSB first) |
| 校验位 | 0 或 1 bit | 可选:无校验、奇校验、偶校验 |
| 停止位 | 1、1.5 或 2 bit | 固定为高电平(逻辑 1),标志一帧结束 |
3.1 起始位
起始位就是一根下降沿。空闲时 TX/RX 都是高电平。当 TX 拉低,接收端就知道:要开始传数据了。
我曾经遇到一个坑:某款 MCU 的 UART 在初始化后,TX 默认是低电平。结果接收端一直以为有起始位,疯狂收乱码。查了两天才发现是 GPIO 初始电平没配好。
3.2 数据位
数据位是真正的信息载体。最常用的是 8 位数据,正好一个字节。也有用 7 位的,比如早期的 ASCII 传输。9 位数据在工业现场总线里偶尔见到,比如 9 位多机通信协议。
注意:数据位是低位先发。比如你要发 0x55(二进制 01010101),线上先看到的是最低位 1,然后是 0、1、0、1、0、1、0。这个顺序别搞反了,否则解码全错。
3.3 校验位
校验位用来做简单的错误检测。有三种模式:
- 无校验(None): 不发送校验位,帧长最短。
- 奇校验(Odd): 数据位 + 校验位中 1 的个数为奇数。
- 偶校验(Even): 数据位 + 校验位中 1 的个数为偶数。
举个例子:数据位是 0x41(二进制 01000001),里面有 2 个 1。如果用偶校验,校验位就是 0,因为 2 已经是偶数。如果用奇校验,校验位就是 1,凑成 3 个 1。
3.4 停止位
停止位是高电平,持续 1、1.5 或 2 个 bit 时间。它给接收端一个缓冲,处理完当前帧,准备接收下一帧。
为什么会有 1.5 和 2 个停止位?老式设备处理速度慢,需要更多时间。现代 MCU 基本都用 1 个停止位。我只有在调试古董级设备时,才见过用 2 个停止位的。
四、波特率的概念与计算
4.1 波特率是什么?
波特率就是每秒传输的符号数。在 UART 里,一个符号就是一个 bit,所以波特率 = 比特率。单位是 bps(bits per second)。
常见的波特率有:9600、19200、38400、115200、921600。115200 是最常用的,速度适中,稳定性好。
4.2 波特率怎么算?
波特率由 UART 外设的时钟频率和分频系数决定。公式很简单:
波特率 = 时钟频率 / (16 × 分频系数)
举个例子:MCU 主频 16 MHz,想得到 115200 的波特率:
分频系数 = 16,000,000 / (16 × 115200) ≈ 8.68
取整为 9,实际波特率 = 16,000,000 / (16 × 9) ≈ 111,111 bps
误差 = (111,111 - 115,200) / 115,200 ≈ -3.55%
这个误差太大了,通信会不稳定。怎么办?换一个能整除的时钟频率,或者用带小数分频的 UART 模块。
4.3 波特率误差容忍度
接收端能容忍多大的波特率误差?一般来说:
- ±2% 以内:稳定通信
- ±2%~±3%:可能偶尔出错
- 超过 ±3%:基本不可靠
这个容忍度跟数据帧长度有关。帧越长,累积误差越大。比如 8N1(8 数据位、无校验、1 停止位)总共 10 bit,误差容忍度就比 5N1 要小。
五、知识体系总览
下面这张图,把 UART 的核心知识点串起来了。你可以把它当作本章的思维导图:
六、本章小结
UART 看起来简单,但它是嵌入式调试的命脉。我见过太多工程师,遇到串口乱码就慌了,其实无非就是几个问题:波特率对不对?帧格式配没配错?电平匹配吗?
记住这几点:
- 起始位是下降沿,停止位是高电平
- 数据位低位先发,别搞反
- 波特率误差控制在 ±2% 以内
- 校验位只能检奇数个错误
把这些基础打牢了,后面讲信号捕获和协议解码,你才能听得明白、用得顺手。