3. 数据链路层协议:串口通信的“交通规则”
大家好,我是你们的嵌入式讲师。今天咱们聊聊串口通信里最核心的部分——数据链路层协议。
说白了,串口通信就像两个人打电话。你说话,我听着。但这里有个问题:你怎么知道对方什么时候开始说?什么时候说完?说的内容对不对?
嗯,这就是数据链路层要解决的事。
3.1 异步串行通信的基本框架
先看一张图,这是我用SVG画的异步串行通信时序图。你盯着看30秒,后面讲的内容就全明白了。
这张图展示的是最常用的8N1格式——8个数据位、无校验、1个停止位。你仔细看,空闲时总线是高电平。当要发送数据时,先拉低一个位时间,这就是起始位。然后依次发送8个数据位,最后拉高一个位时间作为停止位。
核心要点:异步串行通信不需要时钟线。收发双方靠约定的波特率来同步。起始位就是“我要开始说话了”的信号。
3.2 起始位:通信的“发令枪”
起始位的作用很简单——告诉接收方:“注意,数据来了!”
它就是一个位时间的低电平。为什么是低电平?因为空闲时总线是高电平。从高到低的跳变,就是一个明显的“开始”信号。
我在项目中遇到过一个问题:有个设备偶尔会丢第一个字节。查了半天,发现是起始位检测太灵敏了,把噪声也当成了起始位。后来加了去抖处理,问题就解决了。
我的建议:在固件里做起始位检测时,最好连续采样3次确认是低电平,再开始接收数据。这样可以滤掉毛刺干扰。
3.3 数据位:真正要传的内容
数据位就是你要发送的字节。通常是5到9位,最常见的是8位。为什么是8位?因为一个字节就是8位,方便和内存数据对应。
发送顺序是LSB优先,也就是最低位先发。比如你要发送0x55(二进制01010101),先发最低位1,再发0,再发1...依次类推。
你想想看,如果发送顺序搞反了,接收方收到的数据就全乱了。我见过一个新手,在自定义协议里用了MSB优先,结果和标准UART不兼容,折腾了两天才发现。
3.4 校验位:数据正确性的“保险”
校验位是可选的。常用的有奇校验和偶校验。
- 奇校验:数据位中1的个数 + 校验位 = 奇数
- 偶校验:数据位中1的个数 + 校验位 = 偶数
举个例子:数据0x55(二进制01010101),有4个1。如果用奇校验,校验位就是1(让总1的个数变成5,奇数)。如果用偶校验,校验位就是0(保持4个1,偶数)。
注意:校验位只能检测奇数个位的错误。如果两个位同时翻转,校验位是检测不出来的。所以对可靠性要求高的场景,建议用更高级的CRC校验。
我曾经在一个工业控制项目里,因为省掉了校验位,结果在强电磁干扰环境下,数据错误率高达5%。后来加上奇校验,错误率降到了0.1%以下。嗯,有些钱不能省。
3.5 停止位:通信的“句号”
停止位是1个、1.5个或2个位时间的高电平。它告诉接收方:“这一帧结束了。”
为什么需要停止位?两个原因:
- 给接收方时间处理刚收到的数据
- 为下一帧的起始位做准备(从高到低的跳变)
大多数场景用1个停止位就够了。如果通信距离远、干扰大,可以考虑用2个停止位。1.5个停止位比较少见,主要在老的终端设备上见过。
3.6 波特率:通信的“节拍器”
波特率就是每秒传输的符号数。在串口通信里,一个符号就是一个位,所以波特率等于比特率。
常用波特率有:9600、19200、38400、115200、921600等。
| 波特率 | 位时间(us) | 传输1字节时间(us) | 典型应用 |
|---|---|---|---|
| 9600 | 104.17 | 1041.7 | 调试终端、GPS模块 |
| 115200 | 8.68 | 86.8 | 常见嵌入式设备 |
| 921600 | 1.09 | 10.9 | 高速数据采集 |
位时间的计算公式很简单:
位时间(us) = 1,000,000 / 波特率
例如:波特率115200
位时间 = 1,000,000 / 115200 ≈ 8.68 us
传输一个字节(8N1格式)需要10个位时间:1个起始位 + 8个数据位 + 1个停止位。所以:
传输1字节时间 = 10 × 位时间 = 10 / 波特率(秒)
波特率115200时:10 / 115200 ≈ 86.8 us
关键点:收发双方的波特率误差必须在±2%以内。误差太大就会导致采样点偏移,出现数据错误。我建议用晶振频率能整除的波特率,比如11.0592MHz晶振配9600波特率,分频后几乎没有误差。
3.7 异步串行通信的时序细节
接收方怎么知道什么时候采样?它靠的是过采样技术。通常用16倍波特率的时钟来采样。
流程是这样的:
- 检测到起始位的下降沿
- 等待8个采样时钟(半个位时间),在位的中间采样
- 之后每16个采样时钟采样一次(一个位时间)
- 连续采样8次,得到8个数据位
- 再采样停止位,确认是高电平
为什么要采在位的中间?因为信号在跳变时不稳定,中间位置最可靠。这个技巧我在很多项目里都用过,效果很好。
避坑指南:我曾经在一个项目里,因为时钟精度不够,导致采样点逐渐偏移。最后一位的采样点已经靠近跳变沿了,偶尔会采错。后来换了精度更高的晶振,问题就解决了。所以,时钟精度真的很重要。
3.8 常见数据格式总结
串口通信的数据格式用“数据位-校验位-停止位”来表示。常见的有:
- 8N1:8数据位,无校验,1停止位。最常用。
- 8E1:8数据位,偶校验,1停止位。
- 8O1:8数据位,奇校验,1停止位。
- 7E1:7数据位,偶校验,1停止位。老设备常见。
- 8N2:8数据位,无校验,2停止位。抗干扰好。
我个人习惯,新项目一律用8N1。除非有特殊要求,比如和旧设备兼容,或者通信环境特别恶劣。
好了,数据链路层协议就讲到这里。这些概念是串口通信的基石,理解了它们,后面讲协议帧、流控制、错误处理就容易多了。
可可精品资料库