一、什么是 UART?
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器),俗称串口。它把一个字节(8 位数据)拆成一位一位,依次在一根线上发送出去;对面再按同样的规则一位一位接收并拼回字节。
类比:两个人用手电筒通过闪光传信息。事先约定好"每一闪的时长是 0.1 秒",然后一闪一灭地传。对方只要按同样的节奏数,就能读出每一位。这里没有共同的节拍器,只靠事先约定的速度,所以叫异步。
异步的关键:UART 没有时钟线,双方必须事先约定相同的速率(波特率),并在每一帧开始时用"起始位"重新对齐。这是它与 SPI、I²C 最大的不同。
二、接线:TX、RX、GND
UART 最少只需要三根线:
UART 两设备互连 连接前确认电平兼容
- 交叉连接:A 的 TX 接 B 的 RX,A 的 RX 接 B 的 TX。这是新手最常接错的地方。
- 共地:两边的 GND 必须连在一起,否则"0"和"1"的参考电平不同,数据乱码甚至收不到。
- 全双工:TX 和 RX 是两根独立的线,可以同时收发。
最常见的两个错误:① TX 接 TX(没有交叉);② 没有共地。两条都要先检查,比改代码更省时间。
三、一帧数据的格式
UART 发送一个字节时,并不是只发 8 位,而是打包成一个帧(Frame)。最常用的格式写作 8N1,含义如下:
| 部分 | 位数 | 作用 |
| 起始位(Start) | 1 位,电平为 0 | 告诉接收方"新的一帧开始了",并用它的下降沿对齐时间 |
| 数据位(Data) | 8 位,低位在前(LSB first) | 真正要传的数据,8 位正好一个字节 |
| 校验位(Parity) | 0 或 1 位(N = 无校验,E = 偶校验,O = 奇校验) | 简单的错误检测,可选 |
| 停止位(Stop) | 1 或 2 位,电平为 1 | 帧结束,并保证线路回到空闲的高电平 |
8N1:1 位起始 + 8 位数据 + 0 位校验 + 1 位停止 = 10 位
空闲时线路保持高电平(1)。起始位把它拉到低电平,就是新帧的开始
3.1 偶校验是怎么算的?
偶校验要求"数据中 1 的个数 + 校验位"为偶数。例如数据 0x55(0101 0101,有 4 个 1),偶校验位为 0,加上后仍是 4 个 1(偶数)。接收方收到后数一数,如果不对,就知道出错了。
注意:校验只能发现一位出错,无法纠正,而且两位同时错就发现不了。它是"粗略的保险",不是完整的纠错。
四、动手看波形
选择要发送的字节、校验方式和停止位数,观察 TX 线上的波形。注意低位在前:先发的是最低位。
五、波特率与传输速度
波特率(Baud rate)就是每秒钟能传多少位(bit/s)。它决定了"每一位占多长时间":
每一位时间 = 1 / 波特率
每秒传输的字节数 ≈ 波特率 / 每帧位数
8N1 每帧 10 位,所以 115200 波特率下,每秒约 11520 字节(有效速率)
5.1 动手算一算
每一位时间-
每字节时间-
每秒字节数-
发送完所需时间-
对调试的意义:115200 波特率下,每字节约 87 μs,打印一行 40 个字符约需 3.5 ms。如果在中断里打印大量数据,会明显拖慢程序,这时要减少打印量或使用缓冲。
六、时钟误差与"能不能对上"
两边各自的时钟都有误差(第8课讲过)。每一位的时间会有偏差,一帧里的 10 位累积起来,偏差越大,最后几位越容易采错。
双方合计误差 = 发送方误差 + 接收方误差
经验:8N1 下,合计误差最好控制在约 ±2% 以内
用内部 RC 振荡器(约 ±1%)时,两边都用它就可能接近临界值,建议至少一方使用外部晶振
七、电平:TTL 与 RS232
UART 信号本身只定义了"0 和 1",电压的具体标准有几种,接线前必须确认:
| 标准 | 逻辑 1 与 0 的电压 | 注意事项 |
| TTL / CMOS 电平(单片机) | 高 = 3.3 V 或 5 V,低 = 0 V | 单片机之间、单片机与模块之间常用 |
| RS232(老式电脑串口) | 逻辑 1 为 −3 ~ −15 V,逻辑 0 为 +3 ~ +15 V(电平反相、幅度大) | 直接接单片机会烧坏,必须经电平转换芯片(如 MAX232) |
| USB 转串口模块 | 输出为 TTL 电平(3.3 V 或 5 V,要看模块跳线) | 选 3.3 V 还是 5 V,要和单片机一致 |
电压不匹配会烧坏引脚:单片机是 3.3 V 系统,却接了 5 V 的串口模块输出,有可能损坏 IO 脚。反过来,5 V 单片机接 3.3 V 模块,可能收不到高电平。接线前一定要核对电压。
八、常见问题排查
| 现象 | 最可能的原因 | 怎么查 |
| 完全没有输出 | TX/RX 没交叉、没共地、串口没初始化 | 检查接线;看代码中是否开启了 UART 时钟和引脚复用 |
| 输出乱码 | 波特率不一致,或时钟误差大 | 两边设成相同的波特率;换用外部晶振 |
| 偶尔丢数据 | 接收缓冲区溢出,或中断响应太慢 | 提高接收优先级,使用 DMA 或环形缓冲 |
| 数据能收到,但内容错位 | 停止位、校验位设置不一致 | 确认双方都是 8N1 或都是 8E1 |
| 一接长线就不通 | 电平衰减、干扰,超出 UART 的适用距离 | 距离超过几米就考虑 RS485(下一页) |
调试小技巧:如果串口没反应,先用一根线把 TX 和 RX 短接(自发自收),看看能不能收到自己发的数据。能收到,说明单片机这一端没问题,问题在外部接线或对方设备。
十、本节小结
- UART 是异步串行通信,只需 TX、RX、GND,全双工,点对点。
- 接线要交叉(TX 接 RX)并且共地。
- 8N1 一帧 10 位:起始位(0)+ 8 位数据(低位在前)+ 停止位(1)。
- 波特率决定每一位的时间,115200 时每位约 8.7 μs。
- 双方时钟误差合计约 ±2% 以内才可靠;内部 RC 要谨慎使用。
- 注意电平标准,TTL 与 RS232 不能直接互接,3.3 V 与 5 V 也要匹配。
下一页:第9课(二):RS485,远距离的多点总线
回到总览:第9课(总):GPIO 与通信接口总览