4. I2C协议基础:7位地址与10位地址、通用呼叫地址
I2C协议,说白了就是一套“谁跟谁说话、怎么说话”的规矩。你想想看,总线上挂着好几个设备,主控器怎么知道要找谁?从设备又怎么知道主控在叫自己?答案就在地址里。
我个人习惯把I2C地址比作门牌号。7位地址就像小区里的普通门牌,10位地址则是带单元号的复杂门牌。而通用呼叫地址,相当于广播喇叭喊“所有人注意”。
4.1 7位地址结构
7位地址是I2C最常用的地址格式。主控发送起始条件后,紧跟着的第一个字节就是地址字节。这个字节的高7位是地址,最低位是读写方向位。
| 位 | 7 (MSB) | 6 | 5 | 4 | 3 | 2 | 1 | 0 (LSB) |
|---|---|---|---|---|---|---|---|---|
| 含义 | 7位从机地址 | R/W | ||||||
| 说明 | A6 ~ A0 | 0=写,1=读 | ||||||
举个例子:你常用的温度传感器LM75,它的7位地址是0x48(二进制1001000)。主控要写数据时,发送的地址字节就是0x90(10010000);要读数据时,发送0x91(10010001)。
addr_7bit = 0x48; write_byte = (addr_7bit << 1) | 0;
4.2 10位地址格式
7位地址最多支持112个设备(保留地址不算)。但有些场景下设备太多,7位不够用。I2C规范在1992年引入了10位地址。
10位地址的传输分两个阶段:
- 第一个字节:高5位固定为11110,接着是10位地址的高2位,最后是R/W位。
- 第二个字节:10位地址的低8位。
| 阶段 | 字节内容 | 说明 |
|---|---|---|
| 第1字节 | 11110 A9 A8 R/W | 11110是10位地址标识,A9-A8是地址高位 |
| 第2字节 | A7 A6 A5 A4 A3 A2 A1 A0 | 地址低位,共8位 |
4.3 通用呼叫地址
通用呼叫地址是0x00(7位全0)。它的作用是让主控一次性给所有从机发消息。从机可以选择响应,也可以忽略。
通用呼叫的典型应用场景:
- 系统复位:主控发通用呼叫,让所有从机复位到初始状态。
- 广播数据:比如更新所有从机的配置参数。
- 设备发现:某些系统在初始化时,用通用呼叫来探测总线上有哪些设备。
通用呼叫地址字节是0x00(写方向)。第二个字节是命令字节,从机根据命令字节决定是否响应。
| 第二个字节 | 含义 |
|---|---|
| 0x06 | 复位所有从机 |
| 0x04 | 写入可编程地址(部分从机支持) |
| 其他值 | 由具体从机定义 |
4.4 保留地址与特殊地址
I2C规范保留了一些特殊地址,普通设备不能用。这些地址有特殊用途:
| 7位地址 | 用途 |
|---|---|
| 0x00 | 通用呼叫地址 |
| 0x01 | 起始字节(用于慢速设备) |
| 0x02 ~ 0x03 | 保留 |
| 0x04 ~ 0x07 | 高速模式主控代码 |
| 0x78 ~ 0x7F | 10位地址扩展标识 |
你设计系统时,选从机地址要避开这些保留地址。我见过有人不小心把设备地址设成0x00,结果总线上所有设备都响应,数据乱成一锅粥。
4.5 地址冲突与解决
实际项目中,多个同型号设备挂在同一条I2C总线上很常见。比如两个LM75温度传感器,默认地址都是0x48,这就冲突了。
解决办法通常有几种:
- 地址引脚:很多传感器有ADDR引脚,通过拉高或拉低来改变地址。LM75就有3个地址引脚,可以配置8个不同地址。
- I2C多路复用器:用PCA9548这类芯片,把总线分成多路,每路挂一个设备。
- 软件地址重映射:部分设备支持通过命令修改自身地址。
4.6 地址与读写操作流程
理解了地址格式,我们看看完整的读写流程。下面这张图展示了7位地址的写操作过程:
读操作流程类似,只是地址字节的R/W位为1。但要注意,读操作前通常要先写寄存器地址,所以实际流程是:START + 写地址 + 寄存器地址 + 重复起始 + 读地址 + 读数据 + STOP。
4.7 地址选择实战建议
最后,给你几个我在项目中总结的地址选择原则:
- 优先用7位地址:除非设备数量超过112个,否则别碰10位地址。7位地址兼容性好,几乎所有MCU和传感器都支持。
- 避开保留地址:选地址前,对照I2C规范检查一遍。0x00~0x07、0x78~0x7F这些别用。
- 考虑地址冲突:如果总线上有多个同型号设备,提前规划地址引脚配置。最好在原理图阶段就定好。
- 通用呼叫慎用:通用呼叫会影响所有从机。除非你确定所有设备都支持且行为可控,否则别乱发。