UART协议基础:帧格式、波特率与数据完整性

UART,说白了就是串口。我入行那会儿,调试板子第一件事就是先把串口打通。它简单、可靠,直到今天,几乎所有MCU和传感器都还留着它。这一章,咱们把UART的帧格式、波特率、起始位、数据位、校验位、停止位这些基础概念彻底讲透。

UART帧格式:一次传输的完整结构

UART是异步通信,没有时钟线。收发双方靠什么同步?靠约定的帧格式。一帧数据,就像一列火车,有车头、车厢、车尾。

字段 位数 作用
起始位 1位 拉低电平,告诉接收方“准备接收”
数据位 5~9位(常用8位) 实际传输的数据
校验位 0或1位 可选,用于检错
停止位 1、1.5或2位 拉高电平,表示帧结束

我习惯把UART帧画成下面这张图,一目了然:

UART 一帧数据格式(8N1 典型配置) 空闲 高电平 起始 低电平 D0 D1 D2 D3 D4 D5 D6 D7 校验 停止 高电平 LSB(最低有效位)先发送 → 说明: • 8N1 表示:8位数据 + 无校验 + 1位停止位,最常用配置 • 数据位从 D0(LSB)开始发送,D7(MSB)最后发送 • 空闲时 TX 线保持高电平,起始位拉低,停止位拉高

起始位与停止位:帧同步的关键

起始位是UART通信的“发令枪”。发送方把TX线从高电平拉低,保持一个位时间。接收方检测到这个下降沿,就知道“数据要来了”。

停止位则是“刹车”。发送方把TX线拉高,保持1位、1.5位或2位时间。接收方看到停止位,就知道这一帧结束了。

我的经验: 停止位用2位,能容忍更大的时钟偏差。我在一个长距离通信项目里,线缆有十几米,波特率9600,用2位停止位后误码率明显下降。你想想看,多花一个位时间,换来稳定性,值不值?

数据位:真正要传的东西

数据位可以是5、6、7、8位,甚至9位。最常见的是8位,刚好一个字节。为什么?因为ASCII码是7位,加上校验位或扩展字符,8位最灵活。

发送顺序是LSB(最低有效位)先发,MSB(最高有效位)后发。这一点和I2C、SPI不一样,别搞混了。

关键点: 收发双方的数据位长度必须一致。你设8位,对方设7位,收到的数据全是乱的。我见过有人调试半天,最后发现是数据位不匹配——这种坑,踩过一次就记住了。

校验位:简单的错误检测

校验位是可选的。有奇校验、偶校验、无校验三种模式。

校验模式 规则 示例(数据 0x55 = 01010101)
无校验(N) 不发送校验位 帧长度 = 1 + 8 + 1 = 10位
奇校验(O) 数据位中1的个数 + 校验位 = 奇数 0x55有4个1,校验位=1,总1数=5(奇数)
偶校验(E) 数据位中1的个数 + 校验位 = 偶数 0x55有4个1,校验位=0,总1数=4(偶数)

校验位只能检测奇数个位错误。如果两个位同时翻转,校验位就发现不了。不过对于大多数嵌入式场景,够用了。

注意: 我曾经在一个工业控制项目里,环境电磁干扰很强,奇校验根本不够用。后来加了CRC校验(应用层实现),才彻底解决问题。UART的硬件校验位只是基础防护,别指望它万无一失。

波特率:通信的“节拍器”

波特率就是每秒传输的符号数。对UART来说,一个符号就是一个位。所以波特率 = 位速率。

常用波特率有:9600、19200、38400、115200、921600。115200是很多MCU的默认值,速度适中,稳定性好。

收发双方的波特率必须一致,误差一般要求在±2%以内。误差大了,采样点会偏移,导致数据错位。

计算公式: 传输一个字节(8N1)需要 1(起始)+ 8(数据)+ 1(停止)= 10位。波特率115200时,每秒可传 115200 / 10 = 11520 字节 ≈ 11.25 KB/s。

波特率误差:看不见的杀手

为什么波特率误差会出问题?我画个时序图你就明白了。

波特率误差导致采样偏移 发送方 采样点 接收方(无误差) 采样点对齐 ✓ 接收方(+3%误差) 采样点逐渐偏移 → 最后一位可能采错 误差累积到最后一个位时,采样点可能落在位边界上,导致数据错误

你看,误差会累积。起始位检测时对齐,但每过一个位,采样点就偏移一点。到最后一个数据位或停止位时,可能就采到边界上了。

避坑指南: 我曾经用内部RC振荡器做UART通信,标称16MHz,实际只有15.6MHz,误差2.5%。9600波特率勉强能用,但115200就完全乱码。后来换了外部晶振,问题解决。所以,高速UART一定要用晶振,别省那几毛钱。

UART配置的常见组合

实际项目中,UART配置通常用三个字母表示:数据位-校验位-停止位。比如8N1、8E1、7O2。

配置 数据位 校验位 停止位 帧长度 适用场景
8N1 8 无 1 10位 最通用,效率最高
8E1 8 偶校验 1 11位 Modbus RTU 默认
8O1 8 奇校验 1 11位 部分工业协议
7E1 7 偶校验 1 10位 老式ASCII终端
8N2 8 无 2 11位 长线、高干扰环境
我的建议: 新项目默认用8N1。如果环境有干扰,先上8N2,再考虑加校验。别一上来就奇校验偶校验,调试起来麻烦,收益却不大。

UART的硬件流控

除了基本帧格式,UART还有硬件流控:RTS(请求发送)和CTS(允许发送)。

简单说:发送前先问对方“能收吗?”,对方说“能”再发。这样能防止接收缓冲区溢出。

不过,很多嵌入式场景不用流控。只要双方处理速度匹配,或者用软件协议控制,就够了。

个人经验: 我做过一个项目,MCU通过UART给Wi-Fi模块发数据,Wi-Fi模块处理慢,缓冲区经常满。加了RTS/CTS流控后,问题解决。但要注意,流控线会占用两个GPIO,PCB布局时提前规划好。

小结

UART协议基础,说白了就是约定好“怎么开始、怎么结束、中间传什么、传多快”。起始位和停止位保证帧同步,数据位承载信息,校验位提供基础检错,波特率决定速度。这些参数必须收发一致,否则通信失败。