4. 总线协议分析:I2C、SPI、UART、CAN 解码实战

各位工程师朋友,大家好。今天我们来聊聊总线协议分析。

说实话,做硬件调试这么多年,我见过太多人拿着示波器对着波形发呆。明明信号有,电平也对,就是不知道数据对不对。说白了,就是缺了协议解码这步。

我个人习惯,拿到一个波形,先问自己三个问题:
1. 这是什么协议?
2. 起始条件在哪?
3. 数据怎么对齐?

搞清楚了这些,解码就是水到渠成的事。下面我把四种最常用的总线协议,一个一个拆开讲。

4.1 I2C 协议解码

I2C 是嵌入式系统里最常见的协议之一。两根线:SCL(时钟)和 SDA(数据)。

解码要点:

  • 起始条件:SCL 高电平时,SDA 从高变低。这是通信开始的标志。
  • 地址帧:7 位或 10 位地址,后面跟一个读写位(0 写,1 读)。
  • 应答位:每发送完一个字节,接收方必须拉低 SDA 表示应答。
  • 停止条件:SCL 高电平时,SDA 从低变高。

实战经验: 我在项目中遇到过 I2C 总线死锁的情况。SDA 一直被拉低,怎么都释放不了。后来发现是从机在应答位之后没有释放总线。解决办法是主机主动发送 9 个时钟脉冲,让从机复位。

解码步骤:

  1. 找到起始条件,确定通信开始。
  2. 读取第一个字节的高 7 位,得到从机地址。
  3. 检查第 8 位,确定读写方向。
  4. 等待应答位(低电平有效)。
  5. 继续读取后续数据字节,每个字节后都有应答。
  6. 找到停止条件,结束解码。

小技巧: 用示波器解码 I2C 时,建议把时基调到每格 50μs 左右。太快了看不清起始条件,太慢了数据位挤在一起。

4.2 SPI 协议解码

SPI 比 I2C 快,但线也多。四根线:SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。

解码要点:

  • 片选信号:CS 拉低表示开始通信,拉高表示结束。
  • 时钟极性(CPOL):空闲时时钟是高还是低。
  • 时钟相位(CPHA):数据在时钟的上升沿还是下降沿采样。
  • 数据位宽:通常是 8 位,但也有 16 位或 32 位的。

注意: SPI 没有应答机制。发送方只管发,接收方只管收。如果从机没准备好,数据就丢了。我曾经调试一个 SPI 闪存,死活读不到数据,最后发现是从机的 CS 引脚虚焊了。

解码步骤:

  1. 找到 CS 下降沿,确定通信开始。
  2. 根据 CPOL 和 CPHA 确定采样边沿。
  3. 在采样边沿读取 MOSI 和 MISO 上的数据。
  4. 每 8 个时钟周期组成一个字节。
  5. CS 上升沿表示通信结束。

避坑指南: 我曾经在 SPI 解码时犯过一个低级错误。我以为所有 SPI 设备都是 MSB 在前,结果读出来的数据全是乱的。后来查手册才发现,那个传感器用的是 LSB 在前。所以,一定要先看数据手册,确认位顺序。

4.3 UART 协议解码

UART 是异步串行通信,没有时钟线。只有两根线:TX(发送)和 RX(接收)。

解码要点:

  • 波特率:每秒传输的位数。常见的有 9600、115200 等。
  • 数据位:通常是 8 位,也有 7 位或 9 位的。
  • 校验位:奇校验、偶校验或无校验。
  • 停止位:1 位、1.5 位或 2 位。

解码步骤:

  1. 找到起始位(高电平变低电平)。
  2. 根据波特率计算每个数据位的时间宽度。
  3. 在每位的中点采样,读取 8 个数据位。
  4. 如果有校验位,计算校验值并比对。
  5. 检查停止位(高电平)。

经验之谈: 解码 UART 时,最怕波特率不匹配。我有个习惯,先用示波器测量一个数据位的宽度,然后反推波特率。比如测到位宽是 104μs,那波特率就是 1/104μs ≈ 9600。这个方法比猜靠谱多了。

4.4 CAN 总线分析

CAN 总线在汽车和工业领域用得最多。两根线:CAN_H 和 CAN_L,差分信号传输。

解码要点:

  • 显性电平:CAN_H 比 CAN_L 高,代表逻辑 0。
  • 隐性电平:CAN_H 和 CAN_L 电压相等,代表逻辑 1。
  • 帧格式:标准帧(11 位 ID)和扩展帧(29 位 ID)。
  • 位填充:连续 5 个相同位后,插入一个相反位。

解码步骤:

  1. 找到帧起始(SOF),显性位。
  2. 读取 11 位或 29 位标识符。
  3. 读取控制位(IDE、RTR、DLC)。
  4. 读取数据场(0-8 字节)。
  5. 读取 CRC 校验场(15 位 CRC + 1 位定界符)。
  6. 读取应答场(ACK 槽 + ACK 定界符)。
  7. 找到帧结束(EOF),7 个隐性位。

实战案例: 有一次我调试一个 CAN 网络,发现某个节点总是丢帧。用示波器抓波形一看,发现那个节点的 TX 引脚上有个毛刺,导致位填充错误。后来在 TX 引脚上加了个 100pF 的电容,问题就解决了。嗯,有时候硬件上的小问题,软件怎么调都没用。

4.5 四种协议对比

特性 I2C SPI UART CAN
线数 2 4+ 2 2
通信方式 同步 同步 异步 异步
最大速率 3.4 Mbps 50+ Mbps 1 Mbps 1 Mbps
从机数量 多(地址寻址) 多(片选) 点对点 多(ID 仲裁)
应答机制 有 无 无 有
典型应用 传感器、EEPROM 闪存、显示屏 GPS、蓝牙模块 汽车、工业控制

4.6 知识体系总览

下面这张图,是我自己总结的四种协议解码的核心逻辑。你把它记在脑子里,以后看到波形就不会慌了。

总线协议解码核心逻辑 波形 输入 I2C SCL + SDA SPI SCLK + MOSI + MISO + CS UART TX + RX CAN CAN_H + CAN_L 起始/停止条件 地址 + 读写位 应答位检查 片选信号 CPOL / CPHA 位顺序 波特率 数据位 / 校验位 停止位 帧起始 / 标识符 位填充 / CRC

这张图把四种协议的核心要素都列出来了。你拿到波形后,先判断是哪种协议,然后对照着图里的要点去解码,基本不会出错。

最后说一句: 协议解码这东西,光看理论没用。我建议你找个开发板,用示波器抓几组波形,自己手动解码一遍。哪怕只解一帧数据,也比看十遍书管用。嗯,动手吧。

可可精品资料库