第4章 UART基础理论:异步串行通信原理、波特率、数据位、停止位、校验位详解
UART,说白了就是让两个设备之间用一根线来回传数据。听起来简单,但里面门道不少。我刚开始做嵌入式那会儿,总觉得UART就是发数据收数据,没什么好研究的。直到有一次,一个设备死活连不上,折腾了两天才发现是波特率对不上。嗯,从那以后,我再也不敢小看这些基础参数了。
4.1 异步串行通信原理
什么叫异步?就是收发双方没有独立的时钟线。你想想看,没有时钟线,接收端怎么知道什么时候该采样数据?
答案是:靠约定好的波特率,再加上起始位和停止位来同步。
UART的通信帧结构是这样的:
- 空闲状态:总线保持高电平
- 起始位:一个低电平脉冲,告诉接收端“我要开始发了”
- 数据位:5~9位,通常是8位
- 校验位:可选,奇校验或偶校验
- 停止位:1位、1.5位或2位的高电平
我在项目中遇到过一个问题:两个设备通信,偶尔会出现一个字节错位。后来发现是停止位设置不一致。一个设了1位,另一个设了2位,结果接收端把停止位当成了数据位的一部分。这种问题,示波器一看就明白。
核心要点:异步通信的“同步”是靠起始位和停止位实现的。没有这两样东西,接收端根本不知道从哪里开始读数据。
4.2 波特率详解
波特率,就是每秒传输的符号数。对于UART来说,一个符号就是一个bit。所以波特率就等于比特率。
常见的波特率有:
| 波特率 (bps) | 位时间 (μs) | 常见应用场景 |
|---|---|---|
| 9600 | 104.17 | 调试终端、老旧设备 |
| 19200 | 52.08 | 工业控制、传感器 |
| 38400 | 26.04 | GPS模块、蓝牙模块 |
| 115200 | 8.68 | 调试输出、高速通信 |
| 921600 | 1.09 | 固件升级、大数据传输 |
为什么会有这么多标准?说白了,历史原因。早期UART芯片的时钟分频器只能产生某些特定频率。现在虽然芯片能力强了,但这些“传统”波特率还是被保留了下来。
避坑指南:我曾经在CMS32上遇到过波特率误差问题。芯片主频是48MHz,要产生115200波特率,分频系数是48M/115200≈416.67。取整后实际波特率是48M/417≈115108,误差只有0.08%,没问题。但如果主频是16MHz,分频系数是16M/115200≈138.89,取整后实际波特率是16M/139≈115108,误差0.08%也还行。但有些主频会产生超过2%的误差,这时候通信就会丢包。
4.3 数据位
数据位,就是实际传输的数据长度。常见的有7位和8位。
- 7位数据位:用于ASCII字符传输,最高位不用
- 8位数据位:最常用,一个字节正好8位
- 9位数据位:某些特殊协议用,比如多机通信时的地址/数据标志
我个人习惯,只要不是跟老设备通信,一律用8位数据位。省心,也兼容性好。
4.4 校验位
校验位的作用,就是检测传输过程中有没有发生错误。UART支持三种校验方式:
| 校验方式 | 计算方法 | 特点 |
|---|---|---|
| 无校验 (None) | 不发送校验位 | 效率最高,但无错误检测 |
| 奇校验 (Odd) | 数据位中1的个数 + 校验位 = 奇数 | 能检测奇数个bit翻转 |
| 偶校验 (Even) | 数据位中1的个数 + 校验位 = 偶数 | 能检测奇数个bit翻转 |
你可能会问:校验位能检测所有错误吗?不能。如果两个bit同时翻转,奇偶校验就检测不出来了。但实际应用中,单bit翻转的概率远高于多bit翻转,所以奇偶校验还是有用的。
经验之谈:在噪声环境较强的工业现场,我建议开启校验位。虽然多了一个bit的开销,但能避免很多莫名其妙的数据错误。我曾经在一个电机驱动项目里,没开校验位,结果偶尔收到错误数据导致电机抖动。开了偶校验后,问题就解决了。
4.5 停止位
停止位,就是每个字节传输结束后的高电平保持时间。常见的有1位、1.5位和2位。
- 1位停止位:最常用,效率最高
- 1.5位停止位:某些老设备用,现在很少见
- 2位停止位:给接收端更多时间处理数据
为什么需要停止位?说白了,就是给接收端一个缓冲时间。接收端收到一个字节后,需要把数据从移位寄存器搬到数据寄存器,这个操作需要时间。如果连续发送,没有停止位,接收端可能来不及处理。
4.6 知识体系总览
下面这张图,把UART通信的核心知识点串起来了:
4.7 实际应用中的参数选择
说了这么多理论,到底怎么选参数?我总结了一个经验法则:
- 波特率:能高就高,但要考虑线长和噪声。短距离(1米以内)用115200没问题,长距离(10米以上)建议降到9600或19200
- 数据位:默认8位,除非跟ASCII设备通信才用7位
- 校验位:噪声环境开偶校验,干净环境可以不开
- 停止位:默认1位,如果接收端处理慢就开2位
记住这个公式:传输一个字节的时间 = (1 + 数据位数 + 校验位数 + 停止位数) / 波特率
例如:8位数据 + 无校验 + 1位停止 + 115200波特率 = (1+8+0+1)/115200 ≈ 86.8μs
嗯,UART的基础知识就这些。看似简单,但每个参数都有它的道理。下次调试串口通信的时候,记得先检查这些参数是不是都匹配。我敢说,80%的串口通信问题,都是这些基础参数没设对。