3. I2C时序捕获实战:用逻辑分析仪抓总线波形

好,到了真正动手的环节了。前面两章我们把I2C协议的原理和逻辑分析仪的基本操作捋了一遍,这一章咱们就直接上硬菜——用逻辑分析仪去抓I2C总线上的读写波形。

说实话,很多工程师学了协议之后,一到实际抓波形就懵。为什么?因为示波器上看到的是一堆跳变的电平,你得把它翻译成Start、Address、ACK、Data、Stop这些抽象概念。我刚开始做嵌入式那会儿,对着波形数了半天,愣是没分清哪个是ACK哪个是NACK。后来被老工程师点了一句,才恍然大悟。

这一章,我就带你一步步把波形“翻译”出来。

3.1 硬件连接:别小看这一步

抓波形之前,先把物理连接搞定。逻辑分析仪的探头夹到I2C总线上,就这么简单?嗯,但有几个坑你得注意。

⚠️ 接地问题:逻辑分析仪的GND必须和被测设备的GND共地。我见过有人没接地,抓出来的波形全是毛刺,折腾了半天才发现是地线没接。

具体接线步骤:

  1. 找对通道:逻辑分析仪的通道0接SCL,通道1接SDA。我个人习惯固定这个顺序,这样波形出来一眼就能认出哪根是时钟哪根是数据。
  2. 共地:GND夹子夹到板子的GND测试点或螺丝孔上。
  3. 上拉电阻确认:I2C总线需要上拉电阻(通常4.7kΩ)。如果板子上没有,你得外接。我遇到过一块开发板,上拉电阻焊错了阻值,导致SCL上升沿特别缓,逻辑分析仪误判了好多位。
  4. 采样率设置:标准模式100kHz,采样率设1MHz以上就够了。快速模式400kHz,建议用4MHz以上。别设太低,否则边沿抓不准。

3.2 触发设置:让分析仪在正确的时间开始抓

逻辑分析仪不像示波器那样一直刷新,它是先等触发条件满足,然后才开始记录。所以触发设置是关键。

抓I2C波形,最常用的触发方式是Start条件触发。也就是SCL为高时,SDA从高跳变到低。这个边沿就是一次I2C传输的开始。

💡 我的习惯:触发条件设成“SDA下降沿且SCL为高”。有些分析仪支持I2C协议触发,可以直接选“Start Bit”。如果只能设边沿触发,那就选SDA的下降沿,但要注意别被总线上的毛刺误触发。

具体设置步骤(以Saleae Logic为例):

  1. 添加两个数字通道,分别命名为SCL和SDA。
  2. 在触发设置里,选择“I2C”协议解析器,然后选“Start”作为触发条件。
  3. 如果没有协议触发选项,就手动设:SDA通道触发条件为“下降沿”,SCL通道设为“高电平”。
  4. 设置触发位置为“中间”,这样能抓到触发点前后的波形,方便看上下文。

3.3 抓一次完整的写操作

好,连接好了,触发也设好了。现在让主设备(比如单片机)执行一次I2C写操作,往从设备(比如一个温度传感器)的某个寄存器写一个字节数据。

抓到的波形长什么样?我画个图给你看。

I2C写操作完整波形(7位地址) SCL SDA S 从机地址 (0x48) R/W=0 ACK 寄存器地址 ACK 数据字节 ACK P 时序说明 S = Start条件 P = Stop条件 ACK = 从机应答(SDA被拉低)

看到没?一次完整的写操作包含:

  • Start条件:SDA在SCL高电平时下降。
  • 从机地址:7位地址 + 1位读写位(写操作时R/W=0)。
  • ACK:第9个SCL周期,从机将SDA拉低表示应答。
  • 寄存器地址:你要写入的寄存器编号。
  • ACK:从机再次应答。
  • 数据字节:你要写入的数据。
  • ACK:从机应答。
  • Stop条件:SDA在SCL高电平时上升。
🔑 关键点:每个字节后面必须跟一个ACK位。如果从机没有拉低SDA(即SDA保持高电平),那就是NACK,表示从机没收到或者不响应。这是最常见的故障点。

3.4 抓一次完整的读操作

读操作比写操作稍微复杂一点,因为它需要两次传输:先写寄存器地址,再读数据。中间有一个Repeated Start条件。

流程是这样的:

  1. Start条件
  2. 发送从机地址 + 写位(R/W=0)
  3. 等待ACK
  4. 发送寄存器地址
  5. 等待ACK
  6. Repeated Start条件(不是Stop,而是再发一次Start)
  7. 发送从机地址 + 读位(R/W=1)
  8. 等待ACK
  9. 读取数据字节(主设备接收,从机发送)
  10. NACK(主设备不发ACK,表示读完了)
  11. Stop条件

我画个读操作的波形图:

I2C读操作完整波形 SCL SDA S 地址+W ACK RegAddr ACK Sr 地址+R ACK 数据(从发) NACK P 读操作关键 Sr = Repeated Start 最后一位是NACK(主设备不发ACK) 数据由从机驱动,主设备接收
💡 避坑指南:我曾经调试一个气压传感器,读出来的数据总是0xFF。抓波形一看,发现主设备在读完数据后发了ACK而不是NACK。从机以为还要继续发,就一直发,结果总线卡死了。记住:读操作的最后一个字节,主设备必须发NACK。

3.5 用逻辑分析仪的协议解析器自动解码

手动数波形太累了,而且容易出错。现代逻辑分析仪都带协议解析器,能自动把波形翻译成可读的协议数据。

以Saleae为例,添加I2C解析器的步骤:

  1. 抓完波形后,点击右侧的“+”号,选择“I2C”。
  2. 设置SCL和SDA对应的通道。
  3. 设置I2C速率(标准/快速/高速)。这个影响不大,解析器会自动适配。
  4. 点击“保存”。

解析器会生成一个协议列表,每一行显示一次传输的内容:

时间戳 类型 地址 方向 数据 ACK
0.000s Start 0x48 写 - -
0.000s 地址 0x48 写 - ACK
0.001s 数据 - 写 0x01 ACK
0.002s 数据 - 写 0xA5 ACK
0.003s Stop - - - -

看到没?解析器直接告诉你:地址0x48,写操作,写了两个字节0x01和0xA5,都得到了ACK。一目了然。

⚠️ 解析器不是万能的:如果波形质量差(比如毛刺多、边沿不陡),解析器可能误判。我遇到过解析器显示“地址0x48”,但实际波形上地址是0x49(因为一个毛刺把最低位变成了1)。所以,永远要对照原始波形确认。

3.6 常见波形故障定位

抓波形不是为了好看,是为了找问题。下面是我在实际项目中遇到最多的几种故障波形:

3.6.1 无ACK响应

波形上,从机地址发完后,第9个SCL周期SDA没有被拉低,而是保持高电平。原因:

  • 从机地址写错了(比如7位地址左移了一位没处理)。
  • 从机没上电或没初始化。
  • 总线上的上拉电阻失效,SDA被拉不到高电平。

3.6.2 时钟拉伸(Clock Stretching)

有些从机(比如某些EEPROM)在收到数据后,需要时间处理,会把SCL拉低不放。主设备检测到SCL被拉低,就会等待,直到从机释放SCL。如果你看到SCL长时间为低,别慌,这可能是正常的时钟拉伸。

3.6.3 总线冲突

两个主设备同时尝试控制总线,导致SDA出现不确定的电平。波形上表现为SDA在SCL的某个边沿处出现毛刺或竞争。解决办法:确保总线上只有一个主设备,或者实现总线仲裁。

3.6.4 数据位错位

有时候波形看起来是对的,但解析出来的数据不对。比如你写0xA5,但解析器显示0x4A。这通常是SCL和SDA的通道接反了,或者采样率不够导致边沿采样点偏移。

🔑 故障定位三步法:
  1. 看Start和Stop:确认传输的开始和结束是否正确。
  2. 看ACK/NACK:每个字节后有没有ACK?没有的话,问题出在从机侧。
  3. 看数据内容:用解析器对比你期望的数据和实际抓到的数据。

3.7 实战练习:抓一个温度传感器的寄存器读写

最后,我给你留一个完整的实战流程。假设你有一个I2C温度传感器(比如LM75),地址0x48,寄存器0x00是温度值寄存器。

写操作:配置传感器的工作模式,往寄存器0x01写入0x00。

读操作:读取温度值,从寄存器0x00读2个字节。

步骤:

  1. 连接逻辑分析仪到SCL和SDA。
  2. 设置触发为Start条件。
  3. 让单片机执行写操作(配置寄存器)。
  4. 抓波形,用解析器查看是否写成功。
  5. 让单片机执行读操作(读温度值)。
  6. 抓波形,确认读到的数据是否正确。

如果你抓到的波形和上面我画的图一致,那恭喜你,你已经掌握了I2C时序捕获的基本功。如果不对,别急,对照故障定位三步法,一步步排查。