3. I2C波形实战:使用逻辑分析仪抓取I2C波形,手动解析地址、读写位、数据、应答
理论讲完了,咱们来点真格的。
这一章,我会带你亲手抓一段I2C波形,然后一行一行地把它读出来。你想想看,示波器看的是电压变化,逻辑分析仪看的是高低电平——哪个更适合看协议?当然是逻辑分析仪。我个人习惯,调试I2C时逻辑分析仪是必插的,比示波器好用十倍。
3.1 准备工作:你需要什么?
别急着上手,先把家伙事儿备齐:
- 逻辑分析仪:8通道以上,采样率不低于24MHz。我常用的就是那种几十块钱的USB逻辑分析仪,够用。
- 待测设备:一块带I2C接口的开发板,比如STM32、Arduino都行。我手头正好有一块STM32F103,上面挂了个温湿度传感器SHT30。
- 杜邦线:母对母,三根——SCL、SDA、GND。
- 软件:Saleae Logic Analyzer(免费版够用),或者PulseView(开源,功能也不差)。
3.2 连接与配置
连接很简单:
- 逻辑分析仪的通道0接SCL,通道1接SDA。
- GND接开发板的GND。
- 打开软件,设置采样率为24MHz(够用,太高了文件太大)。
- 触发方式选“上升沿”,通道选SDA——这样一有数据就开始抓。
- 点击“开始”,然后让开发板发起一次I2C通信(比如读一次温度)。
抓到的波形大概长这样:
SCL: ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
SDA: ▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
↑起始条件 ↑地址+读写位 ↑应答 ↑数据 ↑应答 ↑停止条件
嗯,这只是示意图。真正的波形你得放大看。
3.3 手动解析:一步一步来
好,波形抓到了。现在咱们放大,从最左边开始看。
3.3.1 找到起始条件
SCL为高电平时,SDA从高跳变到低——这就是起始条件。在逻辑分析仪软件里,你一眼就能看到这个下降沿。我一般会在起始条件的位置加个书签,方便后面定位。
3.3.2 解析地址字节
起始条件之后,SCL开始产生时钟脉冲。每个时钟脉冲的高电平期间,SDA上的电平就是一位数据。一共8位,先传最高位(MSB)。
假设你看到的波形是这样的(SCL上升沿采样):
位序: 7 6 5 4 3 2 1 0
SDA: 1 1 0 0 1 0 0 0
换算成二进制:1100 1000 = 0xC8。但注意,I2C的7位地址是左对齐的,最低位是读写位。所以真正的设备地址是 0xC8 >> 1 = 0x64(即110 0100)。读写位是0,表示主机要写。
3.3.3 检查应答位
第9个时钟脉冲,主机释放SDA(拉高),从机如果拉低SDA,就是应答(ACK)。如果SDA保持高,就是非应答(NACK)。
在波形上,应答位就是第9个SCL高电平期间SDA的电平。低电平=ACK,高电平=NACK。我见过很多新手在这里看反了,以为高电平是应答——千万别搞错。
3.3.4 解析数据字节
应答位之后,接着传数据。格式和地址一样:8位数据 + 1位应答。比如你看到:
数据字节: 0001 0110 = 0x16
这就是从机返回的第一个数据。如果从机还有数据要发,它会继续传,直到主机发NACK+停止条件。
3.3.5 找到停止条件
SCL为高电平时,SDA从低跳变到高——停止条件。波形到这里就结束了。
3.4 完整解析示例
咱们来一个完整的例子。假设你抓到的波形解析出来是这样的:
| 阶段 | 二进制 | 十六进制 | 含义 |
|---|---|---|---|
| 起始条件 | - | - | START |
| 地址字节 | 1100 1000 | 0xC8 | 设备地址0x64,写操作 |
| 应答位 | 0 | - | ACK(从机应答) |
| 数据字节1 | 0010 1101 | 0x2D | 寄存器地址或命令 |
| 应答位 | 0 | - | ACK |
| 重复起始条件 | - | - | Sr |
| 地址字节 | 1100 1001 | 0xC9 | 设备地址0x64,读操作 |
| 应答位 | 0 | - | ACK |
| 数据字节2 | 0001 0110 | 0x16 | 温度高字节 |
| 应答位 | 1 | - | NACK(主机不再读) |
| 停止条件 | - | - | STOP |
你看,这就是一次完整的I2C通信:主机先写命令,然后重复起始,再读数据。整个过程,你用手都能算出来。
3.5 常见坑与避坑指南
- 采样率不够: 如果逻辑分析仪采样率低于4倍I2C时钟,你可能会漏掉窄脉冲。我建议至少8倍以上。
- 触发设置不对: 有时候抓不到波形,是因为触发条件没设对。试试用“下降沿”触发SDA,因为起始条件就是下降沿。
- 应答位看反: 记住,低电平是ACK,高电平是NACK。我曾经带过一个实习生,他硬是把NACK当ACK,查了半天bug。
- 地址算错: 7位地址左对齐,读写位在最低位。很多数据手册直接给7位地址,你得自己左移一位再加读写位。
3.6 知识结构图
下面这张图,把整个手动解析流程串起来了。你可以照着它一步步操作:
3.7 实战练习
光看不练假把式。我给你留个小任务:
- 找一块带I2C传感器的板子(比如SHT30、BMP280都行)。
- 用逻辑分析仪抓一次读温度的操作。
- 手动解析出设备地址、读写位、所有数据字节。
- 对照数据手册,看看你解析出来的数据对不对。
我第一次做这个练习的时候,解析出来的温度值比实际高了10度。后来发现是我把数据字节的高低字节搞反了——SHT30先传高字节,我按低字节先传算了。嗯,这种坑踩一次就记住了。