第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 (保留) | 0x00 | 0x00 | 0x01 |
| 0x10 | 0x20 | 0x20 | 0x21 |
| 0x36 | 0x6C | 0x6C | 0x6D |
| 0x50 | 0xA0 | 0xA0 | 0xA1 |
| 0x7F (保留) | 0xFE | 0xFE | 0xFF |
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,清晰标出每个比特的归属。
6. 实战技巧
用逻辑分析仪抓I2C时,我习惯先设置一个触发条件:当SDA出现地址范围内的第一个下降沿后,开始记录。然后在协议解码设置里,把“7位地址”和“读写位”分开显示。大多数逻辑分析软件都有这个选项。
另一个实用技巧:抓取10位地址设备时,把两个地址字节都显示出来。因为有些逻辑分析仪默认只显示一个字节的地址字段,会漏掉第二个字节。我曾经在这个坑上浪费了一个下午——明明第一个字节是0xF0,软件解析成地址0x78,实际上应该是0x1C0(10位地址=二进制0 1100 0000,首字节0xF0 + 写,次字节0xC0)。
最后给个建议:把设备手册上的地址和实际抓到的第一个字节做一个对照表,贴在调试台旁边。省得每次都要临时左移右移。尤其是10位地址,检查两个字节的连续性——如果从机ACK了第一个字节但NACK了第二个字节,说明10位地址发送流程写错了,从机不认后续字节。