3. I2C地址机制:7位地址与10位地址、广播地址、保留地址
I2C总线上挂多个设备,怎么区分谁是谁?靠的就是地址。说白了,地址就是每个从机的“身份证号”。主机发数据前,先喊一声这个号,对应的从机应答,其他从机保持沉默。
我刚开始学I2C时,总觉得地址这块有点绕。7位、10位、广播、保留……名字听着挺唬人。其实拆开看,没那么复杂。咱们一个一个说。
3.1 7位地址:最常用的方案
标准I2C设备,绝大多数都用7位地址。地址范围从0x00到0x7F,一共128个。但注意,不是所有都能用——有些被保留了。
7位地址怎么用?主机在起始条件后,先发一个字节:高7位是地址,最低位是读写方向(0=写,1=读)。
// 7位地址格式示例
// 假设从机地址为 0x3C(7位)
// 主机要写数据:发送 0x3C << 1 | 0 = 0x78
// 主机要读数据:发送 0x3C << 1 | 1 = 0x79
我遇到过不少新手,直接把7位地址当8位发,结果从机死活不应答。嗯,这里要注意:STM32的I2C外设,有些库函数要你传7位地址,有些要传左移后的8位。看手册,别想当然。
| 地址位数 | 范围 | 可用数量 | 常见场景 |
|---|---|---|---|
| 7位 | 0x00 ~ 0x7F | 112(扣除保留地址) | 绝大多数传感器、EEPROM、ADC/DAC |
| 10位 | 0x000 ~ 0x3FF | 1024 | 需要大量从机的复杂系统 |
3.2 10位地址:什么时候用?
7位地址只有112个可用,有些大系统不够用。I2C规范就扩展了10位地址模式。说实话,我在实际项目中几乎没用过10位地址——大部分场景7位足够了。
10位地址的传输分两步:
- 第一个字节:高5位固定为11110,接着是地址的高2位,最后是读写位。
- 第二个字节:地址的低8位。
// 10位地址传输示例
// 假设从机10位地址为 0x02C4
// 第一步:发送 11110 + 地址[9:8] + R/W
// 11110 00 0 = 0xF0(写操作)
// 第二步:发送地址低8位 0xC4
3.3 广播地址:喊一嗓子,全员响应
广播地址是0x00。主机发这个地址,所有从机理论上都应该应答。有什么用?
- 系统同步:让所有从机同时执行某个操作。
- 地址分配:某些可编程地址的从机,通过广播接收新地址。
- 复位指令:让所有从机回到初始状态。
我曾经在一个多传感器采集板上用过广播复位。20个传感器挂同一条总线,一个一个复位太慢。发一次广播地址+复位命令,所有传感器同时复位,省事多了。
3.4 保留地址:这些别碰
I2C规范保留了一些特殊地址,用于特定功能。普通设备不能用这些地址,否则会冲突。
| 地址(7位) | 用途 | 说明 |
|---|---|---|
| 0x00 | 广播地址 | 通用呼叫,所有从机应答 |
| 0x01 | 起始字节 | 用于慢速设备检测总线 |
| 0x02 | CBUS地址 | 兼容旧CBUS协议 |
| 0x03 ~ 0x07 | 保留 | 未来扩展用 |
| 0x78 ~ 0x7B | 10位地址前缀 | 用于10位地址模式 |
| 0x7C ~ 0x7F | 保留 | 测试/特殊模式 |
你看,0x78到0x7B这4个地址,就是10位地址的前缀标志。如果你用7位地址,千万别选这个范围,否则会跟10位设备打架。
3.5 地址冲突:我踩过的坑
说个真实经历。有次做项目,用了两个同样型号的温湿度传感器,地址都是0x44。挂同一条I2C总线上,结果两个传感器互相干扰,数据全乱套。
解决办法有几个:
- 换地址引脚:很多传感器有ADDR引脚,拉高拉低能换地址。
- 加I2C多路复用器:比如TCA9548A,分时选通不同通道。
- 用软件模拟:每个传感器单独用GPIO模拟I2C,但占用引脚多。
我个人习惯,画原理图前先把所有I2C设备的地址列个表,确认没有冲突。省得板子打回来再飞线,那叫一个痛苦。
3.6 地址机制全景图
下面这张图,把I2C地址的整个体系串起来了。从7位到10位,从广播到保留,一目了然。
3.7 实战建议:地址怎么选?
最后,给几个实在的建议:
- 优先用7位地址:兼容性好,代码简单。
- 避开保留地址:0x00~0x07、0x78~0x7F别碰。
- 画原理图前列表:把所有I2C设备的地址写出来,确认没冲突。
- 留好ADDR引脚:如果传感器有地址选择引脚,拉到VCC或GND,别悬空。
- 读数据手册:每个设备的地址范围和支持模式,手册里写得清清楚楚。