1. 串口基础回顾:UART协议原理

串口,说白了就是最经典的“慢速但可靠”的通信方式。我刚开始做硬件那会儿,调试板子第一件事就是先确认串口能不能打印。你想想看,一个系统连串口都不通,那基本就是“黑盒”状态,啥也看不到。

UART(Universal Asynchronous Receiver/Transmitter)是串口通信的核心。它不需要时钟线,只靠两根数据线(TX和RX)就能完成双向通信。嗯,这里要注意——它叫“异步”,意思是收发双方各自用自己的时钟,但必须约定好相同的“节奏”。这个节奏,就是波特率。

1.1 数据帧结构:起始位、数据位、校验位、停止位

UART的数据传输是以“帧”为单位的。每一帧就像一个小包裹,里面装着你要发送的数据。我习惯把帧结构拆成四个部分来讲:

  • 起始位(Start Bit):一个固定的低电平(逻辑0)。它告诉接收端:“注意,我要开始发数据了!”
  • 数据位(Data Bits):通常是5到9位,最常见的是8位。这就是你要传输的实际数据。
  • 校验位(Parity Bit):可选。用于简单的错误检测,分奇校验和偶校验。
  • 停止位(Stop Bit):一个或多个高电平(逻辑1)。它告诉接收端:“这一帧结束了。”

重要提醒: 起始位和停止位是必须的,校验位是可选的。很多初学者会忽略停止位的长度配置,导致通信不稳定。我曾经遇到过一块板子,就是因为停止位设成了1.5位,而对方只支持1位,结果数据一直错位。

1.2 起始位详解

起始位是UART通信的“发令枪”。在空闲状态下,TX线保持高电平。当发送端要发数据时,先把TX拉低一个位时间。接收端检测到这个下降沿后,就开始采样后续的数据位。

为什么起始位必须是低电平?因为空闲状态是高电平,下降沿是一个明显的跳变,接收端很容易检测到。你想想看,如果起始位也是高电平,那接收端怎么知道数据什么时候开始?

1.3 数据位详解

数据位是真正承载信息的部分。最常见的是8位数据,也就是一个字节。但有些老设备可能只支持7位数据(比如某些ASCII终端)。

数据位的传输顺序是LSB first(最低有效位在前)。举个例子,你要发送0x55(二进制01010101),实际线上先发的是最低位1,然后是0、1、0、1、0、1、0。这个顺序别搞反了,我在项目中见过有人把数据位顺序搞反,结果通信一直乱码,查了半天才发现是软件里配置错了。

1.4 校验位详解

校验位用于简单的错误检测。它有两种模式:

  • 奇校验(Odd Parity):数据位中1的个数加上校验位,总共有奇数个1。
  • 偶校验(Even Parity):数据位中1的个数加上校验位,总共有偶数个1。

举个例子,数据位是0x41(二进制01000001),其中有2个1(偶数)。如果使用偶校验,校验位就是0,保持总数为偶数;如果使用奇校验,校验位就是1,让总数变成奇数。

我的经验: 校验位只能检测奇数个位的错误。如果两个位同时出错,校验位是检测不出来的。所以它只适合对可靠性要求不高的场景。真正要求高的场合,还是得上CRC或者更高级的校验方式。

1.5 停止位详解

停止位是帧的结束标志,必须是高电平。常见的停止位长度有1位、1.5位和2位。1.5位比较少见,我做了这么多年硬件,只在一些老式的工业设备上见过。

停止位的作用有两个:一是告诉接收端这一帧结束了;二是给接收端一点时间处理刚收到的数据。如果停止位长度不够,接收端可能来不及处理,导致下一帧的数据丢失。

避坑指南: 我曾经在一个项目中,因为停止位配置错误,导致高速通信时频繁丢帧。后来发现是接收端的处理速度跟不上,把停止位从1位改成2位后,问题就解决了。所以,如果你遇到高速通信不稳定,不妨试试增加停止位长度。

1.6 波特率的概念与计算

波特率(Baud Rate)是UART通信的“心跳”。它定义了每秒传输多少个符号(symbol)。对于UART来说,一个符号就是一个位,所以波特率就等于比特率(bps)。

常见的波特率有:9600、19200、38400、115200等。115200是我个人最常用的,因为它速度够快,而且大多数MCU和USB转串口芯片都支持。

波特率的计算公式很简单:

传输时间 = 1 / 波特率

例如:波特率115200
每个位的时间 = 1 / 115200 ≈ 8.68 μs

传输一个字节(8位数据 + 1位起始 + 1位停止)需要:
10个位 × 8.68 μs = 86.8 μs
理论最大速率 ≈ 11.5 KB/s

这里要注意,实际传输速率比理论值要低,因为还有帧间隔、协议开销等因素。我实测过,115200波特率下,实际有效数据速率大概在10 KB/s左右。

1.7 波特率误差与容限

UART是异步通信,收发双方各自用自己的时钟。如果双方的时钟有偏差,就会导致采样点偏移,最终出现误码。

一般来说,波特率误差需要控制在±2%以内。为什么是2%?因为UART在每个位的中间采样,如果误差太大,采样点会偏移到位的边缘,导致采样错误。

关键公式:

波特率误差 = (实际波特率 - 理想波特率) / 理想波特率 × 100%

例如:你配置了115200,但实际时钟产生了115500,误差就是:

(115500 - 115200) / 115200 × 100% ≈ 0.26%

这个误差在允许范围内,可以正常工作。

我建议你在设计时,尽量选择整数分频的波特率。比如用16MHz晶振,115200可以精确分频;但用12MHz晶振,115200就有误差。嗯,这个细节很多人会忽略,但实际项目中影响很大。

1.8 知识体系总览

下面这张图总结了UART协议的核心知识点,你可以把它当作一个快速参考:

UART协议知识体系 UART协议 数据帧结构 起始位 数据位 校验位 停止位 波特率 常见速率 误差容限 9600/115200 ±2%以内 校验方式 奇校验 偶校验 应用场景

1.9 实际应用中的注意事项

最后,我分享几个实际项目中的经验:

  1. 电平匹配:UART的电平标准有RS-232(±12V)、TTL(0-3.3V/5V)等。不同设备之间通信,一定要确认电平是否匹配。我见过有人直接把TTL串口接到RS-232接口上,结果烧了芯片。
  2. 地线连接:串口通信必须共地。如果不共地,信号参考点不同,会导致通信异常。嗯,这个看似简单,但很多人会忽略。
  3. 流控制:高速通信时,建议使用硬件流控制(RTS/CTS)。如果没有流控制,接收端来不及处理数据,就会丢帧。
  4. 中断处理:在MCU中,UART接收中断的优先级要设置合理。如果中断被其他高优先级任务打断太久,可能会丢失数据。

我的习惯: 调试串口时,我会先用示波器看波形。确认起始位、数据位、停止位的时序是否正确,波特率是否准确。这一步能快速定位90%的问题。别一上来就怀疑软件,先看看硬件波形再说。

好了,UART的基础知识就回顾到这里。这些内容看似简单,但它们是理解更高级接口(比如SPI、I2C、SerDes)的基础。你把这些吃透了,后面学起来会轻松很多。

可可精品资料库