1. I2C协议基础回顾:物理层、协议层、时序图解读

各位同学好,我是老周。做嵌入式这些年,调试过最多的总线就是I2C。说它简单吧,两根线就能挂一堆设备;说它麻烦吧,一旦出问题,示波器一挂就是半天。今天咱们先把I2C的底子打牢,后面讲多从机故障排查时才不会懵。

1.1 物理层:就两根线,但规矩不少

I2C总线物理上就两条线:SCL(时钟线)和SDA(数据线)。但你别小看这两根线,它们都是开漏输出结构。什么叫开漏?说白了,芯片只能把线拉低,不能主动拉高。拉高的工作交给上拉电阻。

核心要点:I2C总线空闲时,SCL和SDA都必须保持高电平。这是靠上拉电阻实现的。

我在项目中遇到过一位新手,把I2C的上拉电阻焊成了10kΩ,结果总线上升沿慢得像蜗牛,通信距离稍远一点就出错。嗯,这里要注意:上拉电阻的取值跟总线电容、通信速率都有关系。

参数 标准模式 (100kHz) 快速模式 (400kHz) 高速模式 (3.4MHz)
上拉电阻推荐值 4.7kΩ ~ 10kΩ 2.2kΩ ~ 4.7kΩ 1kΩ ~ 2.2kΩ
总线电容上限 400pF 400pF 100pF
最大从机数量 理论127个 理论127个 理论127个

避坑指南:我曾经在一条总线上挂了8个从机,用了1kΩ上拉电阻,结果SCL波形直接变成了三角波。后来换成2.2kΩ才恢复正常。总线电容大了,上拉电阻就得小,但太小又会增加功耗,这是个权衡。

1.2 协议层:地址、读写、应答,一个都不能少

I2C的通信协议其实挺清晰的。每次通信都由主机发起,从机响应。你想想看,总线上那么多设备,怎么知道跟谁说话?靠地址。

每个I2C从设备都有一个7位地址(也有10位地址模式,但用得少)。主机发送地址时,实际上发的是8位:7位地址 + 1位读写标志位。读写标志位为0表示写,为1表示读。

1.2.1 通信流程

  1. 起始条件:SCL高电平时,SDA从高变低
  2. 发送地址:主机发送7位地址 + 读写位
  3. 从机应答:从机拉低SDA表示应答(ACK)
  4. 数据传输:每8位数据后跟一个应答位
  5. 停止条件:SCL高电平时,SDA从低变高

个人经验:我习惯在写驱动时,把起始条件和停止条件封装成两个独立函数。这样调试时可以在关键位置加断点,看波形对不对。

1.2.2 应答机制

应答是I2C通信的"握手信号"。每发送完一个字节,接收方必须给出应答。如果没收到应答,发送方就知道出问题了。

  • ACK (应答):SDA在第9个时钟周期被拉低,表示"收到,继续"
  • NACK (非应答):SDA在第9个时钟周期保持高,表示"收完了"或"出错了"

我记得有一次调试温湿度传感器,主机发完地址后一直没收到ACK。查了半天,原来是地址搞错了——传感器的地址是0x5A,我写成了0x5B。就这一位之差,折腾了我两个小时。

1.3 时序图解读:看得懂波形,才能调得好

做I2C调试,示波器是必备工具。但很多人拿到波形图就头疼。其实I2C的时序图有规律可循,咱们拆开来看。

1.3.1 时序参数

参数 符号 标准模式 快速模式
SCL时钟频率 fSCL 100kHz 400kHz
起始条件保持时间 tHD;STA 4.0μs 0.6μs
数据建立时间 tSU;DAT 250ns 100ns
数据保持时间 tHD;DAT 0~3.45μs 0~0.9μs
停止条件建立时间 tSU;STO 4.0μs 0.6μs
总线空闲时间 tBUF 4.7μs 1.3μs

注意:STM32的I2C外设虽然会自动处理时序,但如果你用GPIO模拟I2C,这些参数就得自己把控。我曾经在快速模式下把tHD;STA设成了0.3μs,结果从机根本不认起始条件。

1.3.2 典型读写时序

写操作是最简单的。主机发完起始条件后,依次发送:从机地址(写)、寄存器地址、数据。每发一个字节等一次ACK。

读操作稍微复杂一点。要先写寄存器地址,然后重新发起始条件,再发从机地址(读),最后从机才会把数据送出来。这个"重新起始"很多人容易搞混。

// 写操作时序
START -> 从机地址+W -> ACK -> 寄存器地址 -> ACK -> 数据 -> ACK -> STOP

// 读操作时序
START -> 从机地址+W -> ACK -> 寄存器地址 -> ACK -> 
REPEATED START -> 从机地址+R -> ACK -> 读取数据 -> NACK -> STOP

调试技巧:我习惯在逻辑分析仪上设置触发条件为"START条件",这样每次通信开始都能抓到。然后对照上面的时序模板,一个字节一个字节地核对,很快就能定位问题。

1.4 I2C通信核心流程(SVG图解)

下面这张图把I2C一次完整的数据传输过程画出来了。从起始条件到停止条件,每个环节都标注了关键信号变化。你调试的时候可以对照着看波形。

I2C总线一次完整数据传输流程 I2C总线一次完整数据传输流程 总线空闲 起始条件 发送地址+读写位 从机应答 数据传输 停止条件 SCL高电平 SDA下降沿 SCL高电平 SDA上升沿 第9个SCL周期 SDA被拉低 数据字节格式(每字节8位 + 1位应答) MSB(最高位)先传输 → D7 D6 D5 D4 D3 D2 D1 D0 → ACK/NACK SCL低电平时SDA变化,SCL高电平时SDA被采样 一次完整I2C通信事务

1.5 常见问题与排查思路

做I2C调试这么多年,我总结了几类最常见的问题。你遇到故障时,可以按这个顺序排查:

  • 波形异常:先看上拉电阻对不对,再看总线电容是不是太大了
  • 无应答:检查从机地址对不对,确认从机是否上电
  • 数据错位:大概率是时钟极性或相位配置错了
  • 总线锁死:SCL或SDA被一直拉低,通常是某个从机挂了,断电重启试试

我的经验:调试I2C时,别一上来就怀疑代码。先拿示波器看波形,确认物理层没问题。我见过太多人花一整天改软件,最后发现是上拉电阻虚焊了。