1. UART协议基础:从历史到实战
大家好,我是你们的嵌入式讲师。今天咱们聊聊UART——这个看起来老掉牙、但每个嵌入式工程师都绕不开的串行通信协议。
说实话,我入行那会儿,UART已经存在几十年了。但直到现在,我调试过的板子里,十块有八块还在用UART做调试口。为什么?因为它简单、可靠、够用。
1.1 UART的历史:一个老而弥坚的协议
UART的全称是Universal Asynchronous Receiver/Transmitter,通用异步收发器。这玩意儿最早可以追溯到1960年代,当时IBM和DEC等公司开始用串行方式连接终端和主机。
我记得第一次在教科书上看到UART的发明时间,心里想:这也太老了吧?但后来在项目中吃过亏才明白——老不代表落后,稳定才是硬道理。
UART的关键里程碑:
| 年代 | 事件 | 影响 |
|---|---|---|
| 1960s | 串行通信雏形出现 | 用于大型机与终端连接 |
| 1970s | UART芯片化(如8250) | 降低了实现成本 |
| 1980s | PC标准集成UART | RS-232成为标配 |
| 1990s至今 | MCU内置UART外设 | 嵌入式系统广泛采用 |
你想想看,一个从大型机时代走过来的协议,到现在还在用,说明它确实有两把刷子。
1.2 异步串行通信原理:没有时钟线怎么传数据?
很多新手问我:UART只有两根数据线(TX和RX),没有时钟线,两边怎么同步?
这个问题问得好。UART用的是异步通信,说白了就是双方事先约定好速度,然后各自用自己的时钟来采样。
打个比方:两个人约好每秒钟说一个字,一个人说,另一个人听。说的人按自己的节奏说,听的人按自己的节奏听。只要两个人的节奏差不多,就能听懂。
这个约定的速度就是波特率(Baud Rate)。常见的波特率有9600、115200等。
关键点:UART通信双方必须使用相同的波特率,否则数据会错位。我在项目中遇到过好几次,板子连上电脑没输出,最后发现是波特率设错了——这种低级错误,排查起来最浪费时间。
异步通信的另一个特点是帧结构。每一帧数据包含:
- 起始位:1位,低电平,告诉接收方“我要开始发了”
- 数据位:5~9位,通常是8位,就是你要传的字节
- 校验位:可选,用于简单检错
- 停止位:1位或2位,高电平,表示这一帧结束
嗯,这里要注意:空闲时TX线保持高电平。起始位拉低,就是给接收方一个明确的“开始”信号。
1.3 起始位/数据位/校验位/停止位详解
咱们一个一个拆开讲。
起始位(Start Bit)
起始位永远是低电平,持续一个位时间。接收方检测到电平从高变低,就知道数据要来了。
我曾经用逻辑分析仪抓过一个UART信号,发现起始位有毛刺——就是电平跳变不干净。结果查出来是板子电源纹波太大,导致TX引脚电平抖动。这种问题,光看代码是看不出来的。
数据位(Data Bits)
数据位是实际传输的内容。常见配置是8位数据位,因为正好对应一个字节。
数据位的顺序是低位在前(LSB first)。比如你要发0x55(二进制01010101),实际线上先发最低位1,再发0,再发1……以此类推。
小技巧:用逻辑分析仪抓UART信号时,如果看到波形是01010101这样交替的,多半是0x55或0xAA。这两个字节常被用来做线路测试。
校验位(Parity Bit)
校验位用于简单的错误检测。有三种模式:
| 模式 | 规则 | 适用场景 |
|---|---|---|
| 无校验(None) | 不发送校验位 | 大多数调试场景 |
| 奇校验(Odd) | 数据位+校验位中1的个数为奇数 | 对可靠性有要求时 |
| 偶校验(Even) | 数据位+校验位中1的个数为偶数 | 对可靠性有要求时 |
举个例子:数据位是0x41(二进制01000001),有2个1。如果用偶校验,校验位就是0,因为2已经是偶数了。如果用奇校验,校验位就是1,让总1数变成3(奇数)。
注意:校验位只能检测奇数个错误。如果两个位同时出错,校验位就发现不了。所以它只适合低噪声环境。我在一个工业项目中吃过这个亏——现场电机一启动,通信就乱码,校验位根本没用。后来换了CRC校验才解决。
停止位(Stop Bit)
停止位是高电平,持续1位或2位时间。它给接收方一个缓冲,处理完当前帧再准备接收下一帧。
为什么要有停止位?说白了就是给双方一个喘息的机会。如果连续发数据,没有停止位,接收方可能来不及处理。
我个人习惯用1位停止位,除非对方明确要求2位。1位停止位效率更高,而且大多数现代设备都能处理。
1.4 UART帧结构总览
把上面这些拼起来,就是一帧完整的UART数据:
空闲(高) | 起始位(低) | 数据位(LSB→MSB) | 校验位(可选) | 停止位(高) | 空闲(高)
用逻辑分析仪看,大概长这样:
高电平 ──────┐
│
▼
起始位 ████ (低电平)
数据位 ██░░██░░ (0和1交替)
校验位 ██ (可选)
停止位 ░░░░ (高电平)
高电平 ──────┐
嗯,这个图是手绘风格的,实际波形会更规整。但核心逻辑就是这样。
1.5 常见配置与参数对比
实际项目中,UART配置五花八门。我整理了一个常用配置表:
| 参数 | 常见值 | 说明 |
|---|---|---|
| 波特率 | 9600, 19200, 38400, 115200 | 越高越快,但抗干扰能力下降 |
| 数据位 | 8位(最常见) | 7位用于ASCII传输 |
| 校验位 | None(最常见) | 调试场景一般不校验 |
| 停止位 | 1位(最常见) | 2位用于低速或噪声环境 |
你可能会问:为什么调试场景不校验?因为调试口主要用来打印日志,偶尔丢一个字符不影响大局。而且加了校验位,帧长度变了,配置起来更麻烦。
1.6 本章知识结构图
下面这张SVG图,把UART协议的核心知识点串起来了。你可以把它当作本章的思维导图。
1.7 实战中的常见问题
讲完理论,咱们聊聊实战中容易踩的坑。
- 波特率不匹配:最常见的问题。两边设置不一致,收到的全是乱码。用逻辑分析仪一看,位宽不对,一眼就能看出来。
- 电平不匹配:MCU通常是3.3V或5V,但RS-232标准是±12V。直接连会烧芯片。需要电平转换芯片,比如MAX232。
- 信号反相:有些设备用RS-232电平,逻辑1是负电压,逻辑0是正电压。和TTL电平正好相反。我刚开始做项目时就被这个坑过——抓到的波形怎么看都不对,后来发现是电平极性反了。
- 地线没接:UART是单端信号,需要共地。如果两个设备的地电位不同,通信就会出问题。我曾经调试一个设备,TX和RX都接对了,但就是没数据。最后发现是GND没连。
调试建议:遇到UART通信问题,第一步用逻辑分析仪抓波形。看起始位有没有、数据位对不对、停止位是否完整。波形对了,问题就在软件;波形不对,问题就在硬件。