1. I2C协议基础:物理层、协议层、起始条件、停止条件、数据有效性、应答机制

各位同学好,我是老周。做嵌入式这行十几年了,I2C 这协议几乎天天见。说实话,很多工程师调了几年 I2C,遇到问题还是抓瞎——要么波形看不懂,要么设备死活没应答。今天咱们就从最底层开始,把 I2C 的骨头拆开来看。

你想想看,一条总线上挂好几个设备,就靠两根线通信,怎么做到不乱?这背后就是物理层和协议层的配合。我当年第一次用逻辑分析仪抓 I2C 波形时,看到那串高低电平,脑子里全是问号。后来才明白,搞懂协议基础,调试才能有的放矢。

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

I2C 总线物理上就两条线:SCL(时钟线)和SDA(数据线)。所有设备都挂在这两条线上,采用开漏输出加外部上拉电阻的结构。

核心特点:

  • 开漏输出:设备只能将总线拉低,不能主动拉高。高电平由上拉电阻提供。
  • 线与逻辑:只要有一个设备拉低总线,总线就是低电平。这是仲裁的基础。
  • 上拉电阻:通常 4.7kΩ,高速模式可能需要 1.5kΩ 甚至更小。

我遇到过不少新手,上来就问:为什么 SDA 和 SCL 要接上拉电阻?不接行不行?答案是——不行。开漏结构决定了总线必须靠外部电阻拉到高电平。不接上拉,总线浮空,通信全乱套。

参数 标准模式 (100kHz) 快速模式 (400kHz) 高速模式 (3.4MHz)
上拉电阻典型值 4.7kΩ 1.5kΩ - 2.2kΩ 0.5kΩ - 1kΩ
总线电容上限 400pF 400pF 100pF
最大从设备数量 127(7位地址) 127 127

实战经验:我建议你调试时先用 4.7kΩ 上拉。如果总线距离长或者设备多,再换成 2.2kΩ。上拉太小会拉低信号质量,太大又会让上升沿变缓——逻辑分析仪上能看到波形变圆角。

1.2 协议层:谁说话,谁听话

I2C 是主从架构。总线上只有一个主设备(Master),其他都是从设备(Slave)。主设备负责产生时钟、发起通信、决定何时结束。从设备只能响应。

每个从设备都有一个唯一的7位地址(也有10位地址的,但用得少)。主设备发地址时,总线上所有从设备都会收到,但只有地址匹配的那个才会应答。

注意:同一个 I2C 总线上不能有两个相同地址的设备。我踩过这个坑——两个传感器地址都是 0x68,结果读数据时两个同时应答,数据全乱了。后来只能加一个 I2C 多路复用器解决。

下面这张图展示了 I2C 通信的基本结构:

I2C 总线物理拓扑结构 主设备 (Master) 从设备 1 从设备 2 SDA SCL R R VDD 关键说明: • 所有设备 SDA/SCL 引脚均为开漏输出,只能拉低,不能主动拉高 • 上拉电阻 R 将总线默认拉到 VDD 高电平 • 总线空闲时,SDA 和 SCL 均为高电平 • 任何设备拉低总线,该线即变为低电平(线与逻辑)

1.3 起始条件与停止条件

这两个条件是 I2C 通信的"开关"。没有它们,总线上的设备不知道什么时候开始、什么时候结束。

起始条件(Start Condition):SCL 为高电平时,SDA 从高电平切换到低电平。

停止条件(Stop Condition):SCL 为高电平时,SDA 从低电平切换到高电平。

记住这个口诀:

  • 起始:SCL 高 → SDA 下降沿
  • 停止:SCL 高 → SDA 上升沿

这两个条件只能由主设备产生。从设备不能发起起始或停止。

我刚开始学的时候,总把起始和停止搞混。后来逻辑分析仪抓了几次波形,一眼就看明白了——起始是 SDA 先跳,停止也是 SDA 先跳,但方向相反。

1.4 数据有效性:时钟高时采样

I2C 的数据传输有个铁律:SDA 上的数据必须在 SCL 为高电平时保持稳定。数据变化只能在 SCL 为低电平时发生。

为什么?因为接收方是在 SCL 的上升沿或高电平期间采样 SDA。如果 SDA 在此时变化,采到的数据就是错的。

SCL 状态 SDA 允许行为 说明
高电平 必须稳定 接收方在此阶段采样数据
低电平 允许变化 发送方在此阶段更新数据位

调试技巧:用逻辑分析仪看 I2C 波形时,重点看 SCL 高电平期间 SDA 有没有抖动。如果有,说明信号完整性有问题——可能是上拉电阻太小、总线电容太大,或者有噪声干扰。我曾经在一个电机驱动板上遇到过,电机一转,I2C 就出错,最后发现是电源噪声耦合到了 SDA 线上。

1.5 应答机制:确认收到

I2C 的每个字节(8位)后面都跟着一个应答位(ACK/NACK)。这是协议层的握手信号。

具体流程是这样的:

  1. 发送方发出 8 位数据后,释放 SDA(拉高)
  2. 接收方在第 9 个 SCL 时钟周期拉低 SDA(表示 ACK)或保持高电平(表示 NACK)
  3. 主设备检测 SDA 状态,判断是否继续通信

常见故障:

  • 从设备无应答(NACK):地址不对、设备未上电、总线冲突、设备忙
  • 主设备不检测应答:有些 MCU 的 I2C 外设默认不检查 ACK,导致发送错误数据而不自知

我曾经调试一个温湿度传感器,死活读不到数据。逻辑分析仪一抓,发现从设备返回了 NACK。查了半天,原来是传感器地址搞错了——数据手册写的是 7 位地址 0x76,但我左移了一位当 8 位地址发,当然对不上。

下面这个流程图展示了完整的 I2C 单字节写操作:

I2C 单字节写操作时序流程 起始条件 发送地址 + W 等待 ACK 发送寄存器地址 等待 ACK 发送数据字节 等待 ACK 停止条件 时序说明: 1. 主设备产生起始条件,所有从设备开始监听 2. 主设备发送 7 位从设备地址 + 1 位读写位(W=0) 3. 地址匹配的从设备在第 9 个 SCL 时钟拉低 SDA 应答 4. 主设备发送寄存器地址,从设备再次应答 5. 主设备发送数据字节,从设备应答 6. 主设备产生停止条件,通信结束 7. 任何一步收到 NACK,主设备应立即发送停止条件

1.6 本章小结

I2C 协议的基础就这些:两根线、主从架构、起始停止、数据有效性、应答机制。听起来简单,但实际调试中,每一个环节都可能出问题。

我个人习惯是:拿到一个新 I2C 设备,先用逻辑分析仪抓一下波形,确认起始条件、地址、应答都正常,再开始写驱动代码。这样能省去后面大量的排查时间。

核心要点回顾:

  • 物理层:开漏 + 上拉,线与逻辑
  • 起始条件:SCL 高时 SDA 下降沿
  • 停止条件:SCL 高时 SDA 上升沿
  • 数据有效性:SCL 高时 SDA 必须稳定
  • 应答机制:第 9 个时钟,拉低为 ACK,高为 NACK