第4章 I2C地址与读写:7位地址、10位地址、读写位归纳总结

做I2C协议分析这么多年,我见过最多的调试翻车案例,就是地址搞错了。要么是7位地址和8位地址混用,要么是读写位没算对,逻辑分析仪一抓——无应答。说白了,地址就是I2C通信的门牌号,门牌号都错了,邻居家再热闹也跟你没关系。

这一章咱们把地址和读写位彻底捋一遍。我保证,看完之后你再看到芯片手册里的device address,脑子里自动就会算出正确的7位值和写命令字节。

1. 7位地址结构

标准I2C设备,地址是7位的。主控发送的第一个字节 = (地址 << 1) | R/W。这个公式几乎挂在每个I2C工程师的显示器上。但实际操作中,很多人搞混的是“地址字节”和“有效地址”的关系。

核心公式

写操作第一个字节 = 7位地址左移1位 + 0

读操作第一个字节 = 7位地址左移1位 + 1

举个例子。某传感器的7位地址是0x36(十进制54)。写操作地址字节 = 0x6C,读操作地址字节 = 0x6D。逻辑分析仪抓到的第一个字节如果是0x6C,那就说明主控要写这个传感器。

表格里我把常见位模式整理出来了,方便查对。

7位地址左移后(不包含R/W)写字节读字节
0x00 (保留)0x000x000x01
0x100x200x200x21
0x360x6C0x6C0x6D
0x500xA00xA00xA1
0x7F (保留)0xFE0xFE0xFF

2. 10位地址机制

7位地址一共就128个,早年被用掉很多保留地址(比如0x00通用呼叫、0x01...),实际可用的不到112个。所以I2C规范推出了10位地址,一下扩展到1024个。

10位地址怎么发送?分两步。先用5位特殊保留码11110加上10位地址的高两位,组成了第一个字节;然后第二个字节发剩下的8位。读写位放在第一个字节里。

注意:10位地址的第一个字节高5位固定为11110,低2位是地址的高两位(即地址[9:8]),最后1位是R/W。所以第一个字节范围是0xF0~0xF7(写)或0xF1~0xF7(读)。如果逻辑分析仪抓到0xF0~0xF7开头的包,要意识到这是10位地址,不是普通7位。

我曾经遇到一个案子:某温湿度传感器手册写的是“10-bit address = 0x1A4”。我按7位习惯直接用了0xD2(0x1A4<<1),结果通信失败。后来才意识到,10位地址要按规范分两字节发。嗯,从那以后我看手册先看“Address type”。

特性7位地址10位地址
地址容量0x00~0x7F (128个)0x000~0x3FF (1024个)
保留地址多个 (0x00~0x07等)不可用区域 (11110开头)
传输字节数1个字节 (地址+R/W)2个字节
首个字节范围(写)0x00~0xFE (偶数)0xF0, 0xF2, 0xF4, 0xF6
常见设备大多数传感器、EEPROM多路复用器、高端音频编解码器

3. 读写位细节

R/W位就一个比特。0表示写,1表示读。在逻辑分析仪上,这个位和地址拼在一起,你看着是一整个字节。所以快速判断方法:地址字节的最低位。如果最低位是0,就是写;最低位是1,就是读。

举个例子:抓到的第一个字节0x6C,二进制0110 1100,最低位=0 → 写操作。主控要往地址0x36写数据。如果抓到0x6D,最低位=1 → 读操作。

小技巧:在逻辑分析仪里添加一个计算列,把第一个字节右移1位,就能直接得到7位地址。很多专业软件已经内置了这个功能。如果手动算,就记住:地址 = (第一个字节) >> 1,读写 = 第一个字节 & 0x01。

4. 避坑指南

  • 地址左移混淆:有些芯片手册给出的地址已经是左移后的8位值,有些给的是7位值。我习惯先看第一个字节定义。如果写操作地址是0x6C,那7位地址就是0x36。反之如果写0x36,那肯定不对。
  • 10位地址的通用呼叫:10位地址的第一个字节如果用0xF0+写,注意不要和通用呼叫0x00+写混淆。通用呼叫是0x00,而10位地址首个字节不是0x00。
  • 保留地址冲突:不要给设备分配0x00~0x07、0x78~0x7F范围内的7位地址,这些是规范保留的。我曾经遇到过有人把0x50给了一个从机,结果和另一个设备的别名冲突,两根线上都是0xA0响应,调试了三天...

5. 地址帧格式结构图

下面这张SVG图展示了7位地址传输的完整帧格式。从START到第一个ACK,清晰标出每个比特的归属。

7位地址帧格式(写操作示例) START 7位地址 A6 A5 ... A0 R/W ACK 数据... 写操作时 R/W = 0,地址字节 = 地址 << 1 读操作时 R/W = 1,地址字节 = (地址 << 1) | 1 第一个字节(8位) = 7位地址 + R/W 7位地址 (bit7~bit1) R/W (bit0) 地址部分 SDA线上一个字节内:bit7先传,bit0最后

6. 实战技巧

用逻辑分析仪抓I2C时,我习惯先设置一个触发条件:当SDA出现地址范围内的第一个下降沿后,开始记录。然后在协议解码设置里,把“7位地址”和“读写位”分开显示。大多数逻辑分析软件都有这个选项。

另一个实用技巧:抓取10位地址设备时,把两个地址字节都显示出来。因为有些逻辑分析仪默认只显示一个字节的地址字段,会漏掉第二个字节。我曾经在这个坑上浪费了一个下午——明明第一个字节是0xF0,软件解析成地址0x78,实际上应该是0x1C0(10位地址=二进制0 1100 0000,首字节0xF0 + 写,次字节0xC0)。

最后给个建议:把设备手册上的地址和实际抓到的第一个字节做一个对照表,贴在调试台旁边。省得每次都要临时左移右移。尤其是10位地址,检查两个字节的连续性——如果从机ACK了第一个字节但NACK了第二个字节,说明10位地址发送流程写错了,从机不认后续字节。