一、UART通信协议基础:什么是UART、串口通信原理、波特率、数据位、停止位、校验位
大家好,我是你们的嵌入式讲师。今天咱们来聊聊UART——这个在嵌入式世界里几乎无处不在的通信协议。说实话,我做了十几年嵌入式开发,UART是我用得最多的接口,没有之一。从调试日志到传感器数据读取,从GPS模块到蓝牙模块,几乎每个项目都离不开它。
1.1 什么是UART?
UART的全称是Universal Asynchronous Receiver/Transmitter,中文叫通用异步收发器。说白了,它就是一套让两个设备之间通过两根线就能聊天的硬件电路。
我刚开始学嵌入式时,总觉得UART这个名字很唬人。后来发现,它其实就是个串行通信的翻译官——把设备内部的并行数据转成串行的一比特一比特发出去,再把收到的串行数据转回并行。嗯,就这么简单。
核心要点:UART是硬件协议,不是软件协议。它规定了电气特性、帧格式和时序,但不管数据内容是什么。你发"Hello"还是发0x55,UART一视同仁。
1.2 串口通信原理
串口通信,顾名思义就是数据一位一位地传输。你想想看,如果8位数据同时用8根线传,那就是并行通信;如果只用1根线,按顺序传8次,那就是串行通信。
UART通信需要三根线:TX(发送)、RX(接收)、GND(地线)。两个设备的TX接对方的RX,RX接对方的TX,地线共地。我在项目中遇到过不少新手把TX和TX直接连在一起,结果死活通信不上——嗯,这个坑我当年也踩过。
UART是异步通信,什么意思?就是收发双方没有独立的时钟线。那它们怎么同步呢?靠的是双方约定好的波特率,以及每个数据帧的起始位和停止位。
个人经验:我建议你在调试UART时,先用示波器看看TX脚的波形。一个完整的UART帧看起来就像一串高低电平的脉冲,起始位是低电平,数据位从LSB开始,停止位是高电平。看一眼波形,比读十页文档都管用。
1.3 波特率
波特率(Baud Rate)是UART通信中最关键的参数之一。它表示每秒传输的符号数,单位是bps(bits per second)。常见的波特率有9600、19200、38400、115200等。
为什么说它关键?因为收发双方必须使用相同的波特率,否则收到的数据全是乱码。我曾经调试一个GPS模块,折腾了半天才发现是波特率设成了9600,而模块默认是4800——那数据简直没法看。
| 波特率 (bps) | 每比特时间 (μs) | 传输1字节耗时 (ms) | 典型应用场景 |
|---|---|---|---|
| 9600 | 104.17 | 约1.04 | GPS模块、低速传感器 |
| 38400 | 26.04 | 约0.26 | 蓝牙模块、工业设备 |
| 115200 | 8.68 | 约0.09 | 调试日志、高速数据传输 |
| 921600 | 1.09 | 约0.01 | 树莓派与PC高速通信 |
这里有个小细节:波特率不等于比特率。在UART中,每个符号就是1个比特,所以两者相等。但在其他调制方式中,一个符号可能携带多个比特,那时波特率和比特率就不一样了。
1.4 数据位
数据位(Data Bits)是每个UART帧中实际传输的数据位数。常见的有5、6、7、8位,最常用的是8位。为什么?因为一个字节正好8位,方便处理ASCII字符和二进制数据。
我记得有一次做项目,需要和一台老旧的工业仪表通信。那仪表只支持7位数据位,我习惯性地设成了8位,结果读回来的数据总是少一位。排查了半天才发现是数据位不匹配——嗯,这种老设备现在不常见了,但遇到了真能让人抓狂。
避坑指南:我曾经在树莓派上用pyserial读取一个传感器模块,数据总是错位。后来发现传感器用的是7位数据位+偶校验,而我默认设成了8位无校验。记住:数据位、校验位、停止位这三者必须完全匹配,缺一不可。
1.5 停止位
停止位(Stop Bits)标志一个UART帧的结束。它可以是1位、1.5位或2位的高电平。最常用的是1位停止位。
为什么需要停止位?说白了就是给接收端一个缓冲时间,让它准备好接收下一个帧。如果停止位太短,接收端可能还没处理完上一个字节,下一个字节就来了,导致数据丢失。
我个人的习惯是:在短距离通信(比如板级通信)中用1位停止位就够了;如果通信距离较长或者环境干扰大,我会用2位停止位,虽然传输效率低一点,但可靠性更高。
1.6 校验位
校验位(Parity Bit)用于简单的错误检测。它分为三种:无校验(None)、奇校验(Odd)、偶校验(Even)。
工作原理很简单:发送端根据数据位中1的个数,自动设置校验位为0或1,使得数据位+校验位中1的总数为奇数(奇校验)或偶数(偶校验)。接收端收到后重新计算,如果发现不一致,就说明传输过程中发生了错误。
说实话,这种校验方式很基础,只能检测奇数个比特的错误。如果两个比特同时翻转,校验位就检测不出来了。但在大多数嵌入式场景中,UART通信距离短、干扰小,这种校验已经够用。
| 校验方式 | 校验位值 | 检测能力 | 适用场景 |
|---|---|---|---|
| 无校验 (None) | 无 | 无 | 调试、短距离可靠通信 |
| 奇校验 (Odd) | 使1的总数为奇数 | 检测奇数个比特错误 | 工业环境、噪声较大 |
| 偶校验 (Even) | 使1的总数为偶数 | 检测奇数个比特错误 | Modbus协议、标准通信 |
1.7 UART帧结构总览
把上面这些概念串起来,一个完整的UART帧长这样:
起始位(1位) + 数据位(5~8位) + 校验位(0或1位) + 停止位(1/1.5/2位)
举个例子,最常用的配置是8N1:8位数据位、无校验、1位停止位。加上1位起始位,总共10位传输1个字节。所以波特率9600时,每秒大约能传960个字节。
计算公式:实际数据传输速率 = 波特率 / (1 + 数据位数 + 校验位数 + 停止位数)
以9600 8N1为例:9600 / (1 + 8 + 0 + 1) = 960 字节/秒
你想想看,如果换成8E2(8位数据位、偶校验、2位停止位),那每帧就是1+8+1+2=12位,同样9600波特率下只能传800字节/秒。效率低了,但可靠性高了。这就是个取舍问题。
1.8 UART通信知识结构图
下面这张图把UART通信的核心知识点串起来了,方便你建立整体认知:
1.9 小结
这一章我们聊了UART通信协议的基础知识。从硬件接口的三根线,到帧结构的四个组成部分,再到通信参数的三个关键配置——这些东西看似零散,但其实是UART通信的基石。
我个人觉得,理解UART最好的方式就是动手。下一章我们会用树莓派的GPIO引脚,配合pyserial库,真正跑起来一个UART通信的例子。到时候你会发现,这些理论知识全都能用上。
课后小练习:打开你的树莓派终端,输入 ls /dev/tty* 看看有哪些串口设备。找到 /dev/ttyAMA0 或 /dev/ttyS0,这就是树莓派的硬件UART接口。先混个脸熟,后面我们会用它做实验。