I2C 寻址机制:7 位地址、10 位扩展与保留地址
说到 I2C 的寻址,我刚开始做嵌入式时总觉得这东西死板。7 位地址够用吗?广播地址到底什么时候用?10 位地址又是怎么扩展的?今天咱们把这几个概念彻底理清。
7 位地址格式——最常见也最基础
标准 I2C 使用 7 位地址。主设备在起始条件后先发送 7 位地址 + 1 位读写方向位。这 8 位叫“地址字节”。
| 位序 | 功能 | 说明 |
|---|---|---|
| Bit 7~1 | 7 位设备地址 | 高位先发,范围 0x00 ~ 0x7F |
| Bit 0 (R/W) | 读写方向 | 0 = 写,1 = 读 |
举个例子。假设从机地址是 0x48(7 位二进制 1001000),主设备要写入数据,那发送的第一个字节就是 0x48 << 1 | 0 = 0x90。如果想读,就发 0x48 << 1 | 1 = 0x91。
我个人习惯:写代码时直接用 addr << 1 表示写地址,addr << 1 | 1 表示读地址。别在脑子里转二进制,容易晕。
10 位地址扩展——什么时候用?怎么用?
7 位地址只支持 128 个地址,其中还有 16 个保留地址。实际可用也就 112 个。有些大型系统需要挂载几十个同类芯片,这时就要用到 10 位地址。
10 位地址的发送分两个阶段:
- 第一个字节:高 5 位固定为 11110,接着是 10 位地址的高 2 位,最后 1 位是 R/W。格式:
11110 A9 A8 R/W - 第二个字节:剩下的 8 位地址 A7~A0。
主设备先发第一个字节(包含高两位地址),然后发第二个字节。如果 R/W=0(写操作),从设备会在每个字节后应答。
// 10 位地址 0x2B0 的写操作示例
// 10 位地址 = 00 1010 1101 0000? 等一下,我算一下。
// 0x2B0 = 二进制 10 1011 0000,高两位 A9A8 = 10,低 8 位 A7~A0 = 1011 0000
// 第一个字节: 1111 0 10 0 = 0xF4 (写)
// 第二个字节: 1011 0000 = 0xB0
// 所以发送序列: START + 0xF4 + 0xB0 + 数据字节...
广播地址与通用调用
广播地址就是 0x00(7 位全零)。任何从设备只要支持广播功能,都会响应这个地址。通常用于系统级命令,比如软件复位、地址分配等。
广播地址的 R/W 位必须是 0(写模式),因为主设备要发送命令字节。从设备只接收,不应答数据中的内容。
| 地址值 | 含义 | 典型使用 |
|---|---|---|
| 0x00 | 通用调用(广播) | 复位所有设备、地址分配 |
| 0x01 | 起始字节 | 慢速设备检测总线 |
| 0x02~0x03 | CBUS 地址 | 已废弃 |
| 0x04~0x07 | 保留 | future use |
保留地址一览
I2C 规范保留了 16 个地址(0x00 ~ 0x0F)用于特殊用途。实际软件开发里最常用的是 0x00 广播地址,其他地址基本碰不到。
| 7 位地址 | 用途 | 备注 |
|---|---|---|
| 0x00 | 通用调用 | 广播 |
| 0x01 | 起始字节 | 用于慢速 MCU |
| 0x02 | CBUS 地址 | 旧协议 |
| 0x03 | 保留 | 未来扩展 |
| 0x04 ~ 0x07 | 高速模式主码 | Hs 模式 |
| 0x08 ~ 0x0F | 保留 | 未来标准 |
你想想看,如果某个从设备地址恰好落在保留地址里,那它就不能用于标准 I2C 总线了。市面上正规芯片都会避开这些地址,但山寨货不好说。
实际项目中的地址分配策略
我做过一个 12 通道温度采集板,每个通道用一片 LM75。LM75 的 7 位地址由三个引脚决定,只能配置 8 个不同地址。怎么办?只能上 10 位地址吗?不用——我外挂了 I2C 多路复用器 TCA9548A。把 12 个传感器分成两组,每组用同一个地址,通过复用器切换通道。你看,灵活应用才是关键。
- 同一总线上地址冲突是灾难性的,系统可能随机无应答。上电先扫描一遍所有地址。
- 10 位地址比较老旧,新设计尽量用 7 位地址 + 复用器方案,代码移植性好。
- 广播地址发完后,必须等所有从机处理完(一般延时几微秒),别立刻发下一帧。