2. I2C协议基础:数据帧格式、地址与读写位、应答机制

各位同学,今天我们聊聊I2C协议最核心的部分。说实话,很多做嵌入式开发的朋友,调I2C设备时遇到最多的问题,就是协议细节没吃透。你想想看,一条SDA线上挂着好几个设备,怎么保证它们不乱说话?靠的就是这套严谨的帧格式和应答机制。

2.1 数据帧的骨架:起始、地址、数据、停止

I2C通信的基本单位是“帧”。一帧数据,就像一封信,有固定的格式。我个人习惯把它拆成四个部分:

  • 起始条件(START):SCL高电平时,SDA从高变低。这是“我要开始说话了”的信号。
  • 地址帧(Address):7位或10位从机地址,加上1位读写方向位。
  • 数据帧(Data):8位数据,可以连续传多个字节。
  • 停止条件(STOP):SCL高电平时,SDA从低变高。这是“我说完了”的信号。

我在项目中遇到过一位同事,写驱动时忘了发停止条件,结果总线一直卡在忙状态,所有设备都挂掉了。嗯,这里要注意:起始和停止条件必须由主机产生,从机只能被动响应。

关键点: 每次通信必须以START开始,以STOP结束。中间可以插入多次数据帧,但地址帧只出现一次。

2.2 地址与读写位:谁在跟谁说话?

I2C总线上每个从设备都有一个唯一的地址。7位地址模式最常见,比如我们常用的温度传感器LM75,地址是0x48。但注意,这个地址是7位的,实际发送时左移1位,最低位填读写位。

位序 7 6 5 4 3 2 1 0
内容 A6 A5 A4 A3 A2 A1 A0 R/W
说明 7位从机地址 0=写,1=读

举个例子:如果设备地址是0x48(二进制 1001000),你要写数据,就发送0x90(10010000);你要读数据,就发送0x91(10010001)。

避坑指南: 我曾经在调试一个加速度传感器时,发现读回来的数据全是0xFF。查了半天,原来是地址发错了——我把7位地址直接当8位发了,没左移。记住:发送地址时一定要左移1位,再填读写位。

2.3 应答机制:你听到了吗?

I2C的应答机制,说白了就是“确认收到”。每发送完一个字节(8位),接收方必须在第9个SCL时钟周期拉低SDA,表示“我收到了”。如果接收方不拉低(SDA保持高),那就是NACK,表示“我没收到”或“我不想收”。

为什么会这样?因为I2C是开漏总线,SDA线通过上拉电阻接高电平。谁想发ACK,谁就把SDA拉低;谁都不拉,SDA就是高,那就是NACK。

  • ACK(应答):接收方在第9个时钟拉低SDA。表示“继续发”。
  • NACK(非应答):接收方在第9个时钟保持SDA高。表示“停止”或“出错”。

我记得第一次调I2C时,逻辑分析仪上看到一堆NACK,还以为是设备坏了。后来才发现,是地址发错了,设备根本不认我。NACK其实是个好信号,它告诉你“这条路走不通”。

重要: 主机在读取数据时,如果不想继续读了,必须在最后一个字节发NACK,然后发STOP。否则从机会一直等下去,总线就卡死了。

2.4 完整通信流程:一次读写操作

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

  1. 主机发START
  2. 主机发7位地址 + 写位(0)
  3. 从机发ACK
  4. 主机发1字节数据
  5. 从机发ACK
  6. 重复步骤4-5,直到数据发完
  7. 主机发STOP

读操作稍微复杂一点,因为要先写寄存器地址,再读数据。这叫“复合帧”:

  1. 主机发START
  2. 主机发7位地址 + 写位(0)
  3. 从机发ACK
  4. 主机发寄存器地址
  5. 从机发ACK
  6. 主机发重复起始条件(RESTART)
  7. 主机发7位地址 + 读位(1)
  8. 从机发ACK
  9. 从机发1字节数据,主机发ACK
  10. 重复步骤9,直到读完
  11. 主机发NACK + STOP

你想想看,如果没有重复起始条件,就得先STOP再START,中间可能被其他主机抢占总线。RESTART保证了原子性——整个操作一气呵成。

2.5 知识结构图

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

I2C协议核心知识结构图 I2C协议核心要素 I2C协议 起始/停止条件 地址 + R/W位 8位数据帧 ACK / NACK START: SCL高→SDA下降 STOP: SCL高→SDA上升 7位地址左移1位 R/W: 0=写, 1=读 MSB先发,LSB后发 可连续多字节 ACK: 第9时钟拉低SDA NACK: 第9时钟保持高 💡 调试建议 用逻辑分析仪抓波形,对照START→地址→ACK→数据→STOP的顺序检查 NACK出现时,先确认地址是否正确,再检查从机是否上电

2.6 常见问题与避坑

最后,我把自己这些年踩过的坑总结一下,你写驱动时对照着检查:

问题现象 可能原因 解决办法
一直收到NACK 地址错误、从机未上电、总线冲突 用示波器抓地址波形,核对7位地址是否左移
数据全是0xFF 从机没响应,SDA被上拉电阻拉高 检查从机供电和复位引脚
总线卡死,SCL一直低 从机拉低SCL时钟拉伸,主机没处理 在驱动中加入超时处理,超过一定时间就复位总线
读回来的数据错位 字节顺序搞反了(MSB/LSB) 确认传感器数据手册的字节序

我的习惯: 每次调新传感器,先用逻辑分析仪抓一次完整的读写波形,对照协议逐位分析。这一步做好了,后面写驱动基本不会出大问题。