1. I2C协议基础:物理层特性与协议层帧结构

做嵌入式这些年,我调试过的I2C设备少说也有上百种了。从温度传感器到EEPROM,从触摸屏到电源管理芯片,I2C几乎无处不在。但说实话,很多人对它的理解停留在「两根线、一主多从」这个层面。一旦波形异常、设备无应答,就抓瞎了。

这一章,咱们把I2C的底裤扒干净。物理层怎么工作的?协议层怎么通信的?搞懂了这些,后面用逻辑分析仪抓波形时,你才能一眼看出问题在哪。

1.1 物理层特性:SDA/SCL开漏与上拉电阻

I2C总线只有两根线:SDA(串行数据线)和SCL(串行时钟线)。但这两根线的驱动方式,跟SPI、UART完全不同——它们是开漏输出。

开漏是什么意思?

说白了,芯片的引脚只能把电平拉低到GND,不能主动拉高到VDD。要输出高电平,必须靠外部上拉电阻把线拉到VDD。

为什么会这样设计?我刚开始做硬件时也觉得奇怪。后来想明白了——开漏结构允许多个设备共用总线,而且不会打架。你想想看,如果两个设备同时输出,一个拉高一个拉低,那就短路了。但开漏结构下,谁想拉低就拉低,想输出高电平就释放总线,让上拉电阻去拉高。这就是I2C总线能挂多个设备的物理基础。

上拉电阻的取值很关键。我踩过这个坑——

我曾经在一个项目里用了10kΩ上拉电阻,总线长度30cm,速率400kHz。结果通信时好时坏,逻辑分析仪一看,SCL上升沿慢得像蜗牛爬。换成2.2kΩ后,问题立刻消失。

上拉电阻怎么选?记住这个经验公式:

总线速率 总线电容 推荐上拉电阻 我的经验
100kHz(标准模式) <100pF 4.7kΩ ~ 10kΩ 板内通信用10kΩ没问题
400kHz(快速模式) <100pF 2.2kΩ ~ 4.7kΩ 我习惯用2.2kΩ,余量大
1MHz(快速+模式) <50pF 1kΩ ~ 2.2kΩ 注意走线要短,电容要小

选电阻时,还要考虑功耗。电阻越小,总线拉高时电流越大。比如VDD=3.3V、R=1kΩ,拉低时电流3.3mA,挂10个设备就33mA了。低功耗场景下,可以适当选大一点,但别超过10kΩ。

1.2 协议层帧结构:起始、停止、数据与应答

物理层搞清楚了,咱们来看协议层。I2C的帧结构其实很简洁,就几个要素:起始条件、从机地址、读写位、数据字节、应答位、停止条件。

我个人习惯把I2C通信比作打电话:

  • 起始条件 = 拿起话筒,拨号
  • 从机地址 = 拨电话号码
  • 读写位 = 告诉对方「我找你说话」还是「我听你说」
  • 数据字节 = 通话内容
  • 应答位 = 对方说「收到」或「没听清」
  • 停止条件 = 挂断电话

下面咱们逐个拆解。

起始条件(START)与停止条件(STOP)

这两个条件由主机产生,是I2C通信的「开关」。

  • 起始条件:SCL为高电平时,SDA从高电平跳变到低电平
  • 停止条件:SCL为高电平时,SDA从低电平跳变到高电平

注意看,这两个条件都发生在SCL高电平期间。正常数据传输时,SDA只能在SCL低电平时变化。所以起始和停止条件是一种「异常」状态,用来标记通信的开始和结束。

调试技巧:用逻辑分析仪抓波形时,先找起始条件。如果波形上SDA在SCL高电平时乱跳,那大概率是起始/停止条件被干扰了。我曾经遇到过上拉电阻虚焊,导致起始条件无法正常产生,从机根本不响应。

数据有效性:SCL高电平时采样

I2C的数据传输规则很简单:

  • SCL低电平:SDA可以变化(发送方准备数据)
  • SCL高电平:SDA必须稳定(接收方采样数据)

说白了,每个时钟脉冲传输1位数据。SCL上升沿之后、高电平期间,接收方读取SDA的电平。所以数据必须在SCL低电平时准备好,高电平时保持住。

这个规则看起来简单,但实际调试时经常出问题。我见过一个案例——

我曾经调试一块板子,从机总是返回错误数据。逻辑分析仪抓波形发现,从机在SCL上升沿之后才改变SDA电平,导致主机采到了错误位。后来查手册发现,从机对SCL上升沿的响应时间超标了。换了个批次的芯片就好了。

应答机制:ACK与NACK

I2C的应答机制是它的一大特色。每传输完一个字节(8位),接收方必须在第9个时钟周期给出应答:

  • ACK(应答):接收方在第9个时钟拉低SDA,表示「收到,继续」
  • NACK(非应答):接收方在第9个时钟释放SDA(保持高电平),表示「没收到」或「不想收」

应答位是I2C调试中最常遇到的问题。我总结了几种常见情况:

现象 可能原因 排查方法
从机地址后收到NACK 地址错误、从机不存在、从机忙 核对地址、检查上电时序
数据字节后收到NACK 从机不支持该命令、写保护 查手册、检查WP引脚
主机主动发NACK 读操作结束、主机不想继续收 正常行为,无需处理

这里有个容易忽略的点:应答位是由接收方控制的。主机发送地址后,从机拉低SDA表示应答;主机发送数据后,从机拉低SDA表示应答;从机发送数据后,主机拉低SDA表示应答。谁接收谁应答,别搞反了。

1.3 完整帧结构:一次典型的I2C写操作

把上面这些要素串起来,一次完整的I2C写操作长这样:

START | 从机地址(7位) | R/W=0 | ACK | 寄存器地址(8位) | ACK | 数据(8位) | ACK | STOP

读操作稍微复杂一点,需要先写寄存器地址,再重新发起起始条件读:

START | 从机地址(7位) | R/W=0 | ACK | 寄存器地址(8位) | ACK |
RESTART | 从机地址(7位) | R/W=1 | ACK | 数据(8位) | NACK | STOP

注意读操作最后的NACK是主机发的,告诉从机「别发了,我要结束了」。然后主机再发停止条件。

1.4 知识结构总览

下面这张图把I2C协议的核心要素串起来了。我建议你把它存下来,调试时对照着看。

I2C协议知识结构图 物理层特性 SDA / SCL 两根线 开漏输出结构 外部上拉电阻 线与逻辑:低电平优先 电阻选型:1kΩ~10kΩ 协议层帧结构 起始条件 START 从机地址 + R/W位 数据字节 (MSB优先) 应答位 ACK/NACK 停止条件 STOP 数据有效性规则 SCL低电平:SDA可变化 SCL高电平:SDA须稳定 接收方在SCL高电平采样 每时钟传输1位数据 字节传输:8位数据 + 1位应答 调试要点 1. 先看起始条件是否正常(SCL高时SDA下降沿) 2. 检查地址字节后的ACK位(第9个时钟SDA是否被拉低) 3. 确认数据在SCL高电平时稳定,没有毛刺 START 地址+R/W ACK 数据+ACK STOP

1.5 写在后面

I2C协议的基础就这些。物理层记住开漏+上拉,协议层记住起始、地址、数据、应答、停止这五个要素。搞懂了这些,你已经能看懂90%的I2C波形了。