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(读)。
3.2 10位地址格式
7位地址不够用怎么办?I2C规范在v2.0里引入了10位地址。它兼容7位模式,但需要特殊处理。
10位地址的发送分两阶段:
- 第一个字节:高5位固定为11110,接着是10位地址的高2位,最后是R/W#位。
- 第二个字节: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 |
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。
怎么检测?
我的做法分三步:
- 扫描总线:写个程序,遍历0x08 ~ 0x77所有地址,看哪些地址有应答。一次扫描就能发现重复。
- 观察波形:用逻辑分析仪抓地址阶段。如果两个设备地址相同,它们的SDA驱动会打架——波形上能看到不完整的ACK位。
- 逐个断开:硬件上逐个断开从设备,看哪个地址消失。土办法但最可靠。
怎么解决?
解决冲突有几种思路:
- 硬件改地址:很多I2C芯片有地址选择引脚(A0/A1/A2)。通过拉高拉低,可以改变设备地址。比如AT24C02,三个引脚能设8个不同地址。
- 使用多路复用器:比如PCA9548,把一条总线分成8路。每路挂一个同地址设备,通过选择通道来访问。
- 软件区分:如果设备支持唯一ID(比如某些温度传感器有64位序列号),可以先广播查询,再单独寻址。
- 换10位地址:如果主控制器支持,把冲突设备切到10位地址模式。
3.5 地址寻址流程图
下面这张图把I2C地址寻址的完整流程画出来了。从主设备发起起始条件开始,到收到ACK或NACK结束。7位和10位的分支也标清楚了。
这张图把整个寻址过程串起来了。你调试的时候,拿着逻辑分析仪对照这个流程,一步对一步,很快就能定位问题出在哪。
3.6 实战:地址冲突排查清单
最后,我整理了一份排查清单。遇到地址相关的问题,按这个顺序查:
- 确认地址格式:数据手册给的是7位还是8位?左移了没?
- 检查保留地址:你的地址是不是落在0x00~0x07或0x78~0x7F里?
- 扫描总线:用代码遍历所有可用地址,看有没有重复应答。
- 看波形:抓地址阶段的SDA/SCL,确认ACK位是否正常。
- 检查硬件:地址选择引脚有没有虚焊?电平对不对?
- 确认10位支持:如果用10位地址,主控制器硬件是否真的支持?
地址寻址是I2C通信的第一步,也是故障高发区。把这一节吃透,后面讲时序、讲错误处理时,你心里就有底了。