4. I2C寻址方式:7位地址、10位地址、地址帧归纳总结
I2C 总线上挂多个设备,怎么知道主器件在叫谁?答案就在地址帧里。说白了,每个从设备都有一个"门牌号",主设备发地址帧来敲门。这一章我们把 7 位地址、10 位地址掰开揉碎讲清楚,最后再做个归纳对比。
核心要点:地址帧是 I2C 通信的"第一声吆喝"。主设备先发出起始位,紧接着就是 7 位或 10 位地址 + 读写位。从设备认出是自己的地址,才会回一个 ACK。地址不对,后面数据一概不理。
4.1 7位地址:用得最多的寻址方式
7 位地址能挂 128 个设备,实际可用的大约 112 个。为啥不是 128?因为有些地址被保留了,比如 0x00 是通用呼叫地址,0x01~0x07 有其他用途。我刚开始做 I2C 项目时,选了个 0x00 做测试,结果总线上所有设备都响应了——嗯,踩坑了才知道那是广播地址。
7 位地址帧的格式很简单:
- 起始位(S):拉低 SDA 的同时 SCL 为高,告诉总线"我要开始通信了"。
- 7 位地址(A6~A0):从设备地址,高位在前(MSB first)。
- 读写位(R/W):0 表示主设备要写,1 表示主设备要读。
- 应答位(ACK):从设备在第 9 个 SCL 周期拉低 SDA,表示"我在,你继续"。
举个例子,一个温度传感器地址是 0x48(二进制 1001000),你要读它数据:
起始位 → 发送 0x48 << 1 | 0x01 → 即 0x91(10010001)
↑ 7位地址左移1位 ↑ 读位
等待 ACK → 开始读数据
我个人习惯把地址左移一位再拼读写位,然后统一用十六进制看。你写驱动时也建议这么干,不容易搞混。
小技巧:7 位地址在数据手册里通常写成 0x48 这种形式。实际发送时记得左移一位,最低位填读写位。很多新手在这里栽跟头——直接发了 0x48 而不是 0x90(写)或 0x91(读),结果设备没反应。
4.2 10位地址:给"大户人家"准备的
7 位地址不够用怎么办?I2C 规范在 1992 年引入了 10 位地址。说实话,我在实际项目中只遇到过两次 10 位地址的设备,一次是一个多通道 ADC,另一次是一个复杂的音频编解码芯片。大部分消费级传感器还是老老实实用 7 位地址。
10 位地址的帧结构分两步走:
- 第一字节:高 5 位固定为 11110,紧接着是地址的高 2 位(A9、A8),最后是读写位。所以第一字节的格式是
11110 A9 A8 R/W。 - 应答位:从设备回 ACK。
- 第二字节:地址的低 8 位(A7~A0),从设备再回 ACK。
你想想看,10 位地址的地址空间多大?1024 个地址。和 7 位地址兼容吗?兼容的。10 位地址的第一字节高 5 位是 11110,而 7 位地址中 11110 开头的那几个地址(0x78~0x7F)被保留用于 10 位地址扩展,所以不会冲突。
注意:10 位地址的读操作有点绕。因为第一个字节里已经包含了读写位,但地址还没发完(低 8 位在第二字节)。正确的做法是:先发 11110 + A9 + A8 + 0(写方向),等 ACK,再发低 8 位地址,等 ACK,然后发重复起始位,再发 11110 + A9 + A8 + 1(读方向)。我曾经在这里卡了大半天,逻辑分析仪一看,地址根本没发对。
4.3 地址帧结构对比与归纳
两种地址放在一起看,差异就很清楚了。下面这张图把 7 位地址帧和 10 位地址帧的每个字段都拆开了,你一眼就能看出区别。
我再整理一个表格,把两种地址的核心参数做对比,方便你快速查阅:
| 对比项 | 7位地址 | 10位地址 |
|---|---|---|
| 地址空间 | 128(可用约112) | 1024 |
| 帧长度 | 1字节 + 1个ACK | 2字节 + 2个ACK |
| 第一字节高5位 | 实际地址位 | 固定 11110(标识) |
| 兼容性 | 所有I2C设备 | 需双方支持10位寻址 |
| 读操作 | 直接发地址+R/W=1 | 需重复起始位+重新发第一字节 |
| 实际应用占比 | 95%以上 | 低于5% |
到这里,7 位和 10 位地址的核心差异你应该清楚了。我个人建议:除非你明确知道某个器件必须用 10 位地址,否则优先选 7 位地址。为什么呢?兼容性好,驱动代码简单,踩坑概率低。你拿着逻辑分析仪抓波形时,7 位地址的帧一眼就能看懂,10 位地址还得数半天位。
避坑提醒:我曾经在一个项目里同时用了 7 位地址和 10 位地址的器件,结果地址分配时没注意,7 位地址 0x78 被占用了——而 0x78 正是 10 位地址前缀 11110 所在的保留范围。总线上两个设备地址冲突,折腾了两天才排查出来。所以你分配地址时,务必查一下 I2C 保留地址表,0x00~0x07 和 0x78~0x7F 都不要随便用。
实用建议:用逻辑分析仪抓 I2C 地址帧时,重点关注第一个字节的 bit 0(即 R/W 位)和 ACK 位。如果地址发出去没收到 ACK,先检查地址是否左移了,再检查从设备地址对不对。这两个问题至少占了地址帧失败的 80%。
最后说一句,地址帧是整个 I2C 通信的"敲门砖"。地址对不上,后面发再多数据都是白费。你花 10 分钟把地址帧的结构搞透,比后面花 1 小时查波形盲点要划算得多。