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 位地址的帧结构分两步走:

  1. 第一字节:高 5 位固定为 11110,紧接着是地址的高 2 位(A9、A8),最后是读写位。所以第一字节的格式是 11110 A9 A8 R/W。
  2. 应答位:从设备回 ACK。
  3. 第二字节:地址的低 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 位地址帧的每个字段都拆开了,你一眼就能看出区别。

I2C 7位地址与10位地址帧结构对比 I2C 地址帧结构对比(7位 vs 10位) 7位地址帧 S 起始位 A6 A5 A4 A3 A2 A1 A0 7 位从设备地址 MSB → LSB R/W 0=写 1=读 读写位 ACK 应答 SCL: 1~9 SCL: 2~8 SCL: 9 SCL: 9 10位地址帧(两阶段) S 起始位 1 1 1 1 0 10位地址前缀 固定标识 A9 A8 高位 地址高2位 R/W 读写位 ACK 应答1 ← 第一字节(10位地址标识 + 高位 + 读写) → A7 A6 A5 A4 A3 A2 A1 A0 8 位低位地址 LSB ACK 应答2 ← 第二字节(低位地址) → 数据方向 关键区别 • 7位地址:1帧1字节+ACK • 10位地址:2帧2字节+2个ACK • 10位地址读操作需要 重复起始位 + 重新发送 第一字节(R/W=1)

我再整理一个表格,把两种地址的核心参数做对比,方便你快速查阅:

对比项 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 小时查波形盲点要划算得多。