3. I2C波形实战:使用逻辑分析仪抓取I2C波形,手动解析地址、读写位、数据、应答

理论讲完了,咱们来点真格的。

这一章,我会带你亲手抓一段I2C波形,然后一行一行地把它读出来。你想想看,示波器看的是电压变化,逻辑分析仪看的是高低电平——哪个更适合看协议?当然是逻辑分析仪。我个人习惯,调试I2C时逻辑分析仪是必插的,比示波器好用十倍。

3.1 准备工作:你需要什么?

别急着上手,先把家伙事儿备齐:

  • 逻辑分析仪:8通道以上,采样率不低于24MHz。我常用的就是那种几十块钱的USB逻辑分析仪,够用。
  • 待测设备:一块带I2C接口的开发板,比如STM32、Arduino都行。我手头正好有一块STM32F103,上面挂了个温湿度传感器SHT30。
  • 杜邦线:母对母,三根——SCL、SDA、GND。
  • 软件:Saleae Logic Analyzer(免费版够用),或者PulseView(开源,功能也不差)。
我的小习惯: 抓波形之前,先把GND接好。不接GND,波形全是毛刺,你根本没法看。我曾经有一次忘了接地,抓了半小时全是乱码,气得我差点把板子扔了。

3.2 连接与配置

连接很简单:

  1. 逻辑分析仪的通道0接SCL,通道1接SDA。
  2. GND接开发板的GND。
  3. 打开软件,设置采样率为24MHz(够用,太高了文件太大)。
  4. 触发方式选“上升沿”,通道选SDA——这样一有数据就开始抓。
  5. 点击“开始”,然后让开发板发起一次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,表示主机要写。

关键点: 地址字节 = (设备地址 << 1) | 读写位。所以看到0xC8,设备地址就是0x64,写操作。如果看到0xC9,那就是读操作。

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通信:主机先写命令,然后重复起始,再读数据。整个过程,你用手都能算出来。

注意: 重复起始条件(Sr)和停止条件长得不一样。Sr是SCL低电平时SDA从高跳低,而停止条件是SCL高电平时SDA从低跳高。别搞混了。

3.5 常见坑与避坑指南

  • 采样率不够: 如果逻辑分析仪采样率低于4倍I2C时钟,你可能会漏掉窄脉冲。我建议至少8倍以上。
  • 触发设置不对: 有时候抓不到波形,是因为触发条件没设对。试试用“下降沿”触发SDA,因为起始条件就是下降沿。
  • 应答位看反: 记住,低电平是ACK,高电平是NACK。我曾经带过一个实习生,他硬是把NACK当ACK,查了半天bug。
  • 地址算错: 7位地址左对齐,读写位在最低位。很多数据手册直接给7位地址,你得自己左移一位再加读写位。

3.6 知识结构图

下面这张图,把整个手动解析流程串起来了。你可以照着它一步步操作:

I2C波形手动解析流程 I2C波形手动解析流程 1. 抓取波形 2. 找到起始条件 3. 解析地址字节 4. 检查应答位 5. 解析数据字节 6. 找到停止条件 提示:每步都要放大波形仔细看,别跳步。特别是应答位,最容易看错。

3.7 实战练习

光看不练假把式。我给你留个小任务:

  1. 找一块带I2C传感器的板子(比如SHT30、BMP280都行)。
  2. 用逻辑分析仪抓一次读温度的操作。
  3. 手动解析出设备地址、读写位、所有数据字节。
  4. 对照数据手册,看看你解析出来的数据对不对。

我第一次做这个练习的时候,解析出来的温度值比实际高了10度。后来发现是我把数据字节的高低字节搞反了——SHT30先传高字节,我按低字节先传算了。嗯,这种坑踩一次就记住了。

我的建议: 刚开始别用自动解析功能。用手动模式硬读10次波形,之后你再看自动解析的结果,心里就有底了。这就像学开车,先开手动挡,再开自动挡,才能真的懂车。