3. I2C地址与寻址:7位地址与10位地址格式、广播地址、保留地址、地址冲突检测与解决

I2C的寻址机制,说白了就是总线上的“门牌号”系统。每个从设备都得有个唯一地址,主设备才能准确找到它。我见过不少工程师在这上面栽跟头——地址冲突、格式搞混、保留地址误用,折腾半天才发现是寻址的问题。

这一节,咱们把I2C地址的底裤扒干净。从7位到10位,从广播到保留,再到冲突怎么查怎么解,一次说透。

3.1 7位地址格式

标准I2C设备用7位地址。这7位跟在起始条件后面,由主设备发送。格式很简单:

起始条件 | 7位地址 | 读/写位 | 应答位 | ...数据...

7位地址能编址128个设备(0x00 ~ 0x7F)。但别高兴太早——实际上可用的没那么多。为什么?因为有一部分被保留做特殊用途了。

地址字节的构成是这样的:高7位是地址,最低位是R/W#。0表示写,1表示读。所以你在数据手册里看到的设备地址,通常是7位地址左移1位后的值。比如一个设备地址是0x27,实际发送时是0x4E(写)或0x4F(读)。

我的习惯:看数据手册时,先搞清楚它给的是7位原始地址还是8位地址字节。很多国产芯片手册写得不规范,我踩过这个坑——地址写0x50,结果发0x50死活没应答,后来才发现人家给的是8位地址字节。

3.2 10位地址格式

7位地址不够用怎么办?I2C规范在v2.0里引入了10位地址。它兼容7位模式,但需要特殊处理。

10位地址的发送分两阶段:

  1. 第一个字节:高5位固定为11110,接着是10位地址的高2位,最后是R/W#位。
  2. 第二个字节:10位地址的低8位。

举个例子,地址0x2A3(二进制10 1010 0011)的发送过程:

第一阶段:1111 0 | 10 | R/W#  → 0xF4(写)或0xF5(读)
第二阶段:1010 0011            → 0xA3

10位地址的保留标识是1111 0xx。主设备发这个头,从设备就知道后面还有8位要收。

地址类型 首字节高5位 地址范围 可用数量
7位地址 可变 0x00 ~ 0x7F 112(扣除保留)
10位地址 11110 0x000 ~ 0x3FF 1024
注意:不是所有I2C控制器都支持10位地址。我遇到过一款MCU的硬件I2C外设,数据手册说支持,实际用起来各种bug。最后只能软件模拟。选型时务必确认硬件支持情况。

3.3 广播地址与保留地址

I2C规范保留了一些特殊地址。这些地址不能分配给普通设备。

广播地址(0x00):也叫通用呼叫地址。主设备发0x00,所有从设备都应该应答。通常用于主设备通知所有从设备“我要发全局消息了”。实际项目中用得不多,但有些传感器用它做同步复位。

保留地址列表:

地址(7位) 用途 说明
0x00 广播/通用呼叫 所有从设备应答
0x01 起始字节 用于慢速设备检测起始
0x02 CBUS地址 保留给CBUS兼容设备
0x03 ~ 0x07 保留 未来扩展
0x78 ~ 0x7B 10位地址标识 11110xx前缀
0x7C ~ 0x7F 保留 测试/特殊用途

实际可用的7位地址是0x08 ~ 0x77,共112个。嗯,够用吗?在复杂系统里,多个同型号传感器挂一条总线上,地址冲突就来了。

3.4 地址冲突检测与解决

地址冲突是I2C调试里最常见的故障之一。症状很明显:主设备发地址后收不到ACK,或者收到错误的ACK。

怎么检测?

我的做法分三步:

  1. 扫描总线:写个程序,遍历0x08 ~ 0x77所有地址,看哪些地址有应答。一次扫描就能发现重复。
  2. 观察波形:用逻辑分析仪抓地址阶段。如果两个设备地址相同,它们的SDA驱动会打架——波形上能看到不完整的ACK位。
  3. 逐个断开:硬件上逐个断开从设备,看哪个地址消失。土办法但最可靠。

怎么解决?

解决冲突有几种思路:

  • 硬件改地址:很多I2C芯片有地址选择引脚(A0/A1/A2)。通过拉高拉低,可以改变设备地址。比如AT24C02,三个引脚能设8个不同地址。
  • 使用多路复用器:比如PCA9548,把一条总线分成8路。每路挂一个同地址设备,通过选择通道来访问。
  • 软件区分:如果设备支持唯一ID(比如某些温度传感器有64位序列号),可以先广播查询,再单独寻址。
  • 换10位地址:如果主控制器支持,把冲突设备切到10位地址模式。
避坑指南:我曾经在一个项目里用了8个同样的气压传感器。数据手册说地址可设,结果买回来发现A0/A1/A2引脚内部已经固定了——根本改不了。最后只能加I2C多路复用器,多花了2块钱成本,还被领导说了。所以选型时一定要看引脚是否真的可配置,别信“兼容”两个字。

3.5 地址寻址流程图

下面这张图把I2C地址寻址的完整流程画出来了。从主设备发起起始条件开始,到收到ACK或NACK结束。7位和10位的分支也标清楚了。

I2C地址寻址流程图 主设备发起始条件 判断:7位地址还是10位? 7位 10位 发送7位地址 + R/W位 发送11110 + 高2位 + R/W 等待从设备ACK 等待从设备ACK 发送低8位地址 等待从设备ACK 收到ACK还是NACK? ACK NACK 寻址成功,开始数据传输 寻址失败,检查地址冲突 注 10位地址需要两轮地址发送

这张图把整个寻址过程串起来了。你调试的时候,拿着逻辑分析仪对照这个流程,一步对一步,很快就能定位问题出在哪。

3.6 实战:地址冲突排查清单

最后,我整理了一份排查清单。遇到地址相关的问题,按这个顺序查:

  1. 确认地址格式:数据手册给的是7位还是8位?左移了没?
  2. 检查保留地址:你的地址是不是落在0x00~0x07或0x78~0x7F里?
  3. 扫描总线:用代码遍历所有可用地址,看有没有重复应答。
  4. 看波形:抓地址阶段的SDA/SCL,确认ACK位是否正常。
  5. 检查硬件:地址选择引脚有没有虚焊?电平对不对?
  6. 确认10位支持:如果用10位地址,主控制器硬件是否真的支持?
小技巧:我习惯在调试阶段给每个I2C设备焊个0欧电阻在地址选择引脚上。万一地址冲突,换个电阻就能改地址,不用重新打板。成本几分钱,省心一大截。

地址寻址是I2C通信的第一步,也是故障高发区。把这一节吃透,后面讲时序、讲错误处理时,你心里就有底了。