3. I2C设备地址:7位地址与10位地址格式、广播地址、保留地址、地址冲突与解决策略
地址,是I2C总线上每个设备的“身份证”。
我刚开始学I2C时,总觉得地址就是个编号,随便给一个就行。直到有一次,我把两个型号一样传感器挂到同一条总线上,结果数据全乱了。嗯,从那以后我才认真研究起地址这回事。
这一节,我们就来把I2C地址的底细彻底搞清楚。
3.1 7位地址格式
标准I2C设备使用7位地址。这7位地址跟在起始条件之后,由主机发送。
具体格式是这样的:
起始条件 | 7位地址(高7位) | 读写位(1位) | 应答位
举个例子,假设一个设备的7位地址是 0x48(二进制 1001000),主机要读取数据:
主机发送:0x48 << 1 | 1 = 0x91 (10010001)
设备应答:ACK
这里有个细节:7位地址左移1位,最低位填读写位。所以你在数据手册里看到的地址,通常是7位值,但实际发送时要左移。
我的习惯:在代码里直接定义7位地址,发送时用
(addr << 1) | rw 拼装。这样可读性最好,也不容易出错。
3.2 10位地址格式
7位地址最多挂128个设备,实际可用的大约112个。对于复杂系统,这不够用。
10位地址格式应运而生。它用两个字节来传输地址:
| 字节 | 位[7:0] | 说明 |
|---|---|---|
| 第1字节 | 1111 0 XX | 高5位固定11110,后2位是10位地址的最高2位 |
| 第2字节 | XXXXXXXX | 10位地址的低8位 |
10位地址的保留标识是 11110XX,其中XX是地址的最高两位。主机先发这个标识字节,再发低8位地址。
注意:不是所有I2C控制器都支持10位地址。选型时一定要确认MCU的I2C外设是否支持。我曾在STM32F103上踩过这个坑——它的I2C外设不支持10位地址模式。
3.3 广播地址与保留地址
I2C协议定义了一些特殊地址,不能分配给普通设备。
| 地址(7位) | 用途 | 说明 |
|---|---|---|
| 0x00 | 广播地址/通用呼叫 | 所有设备都应应答,用于主机向所有设备发送命令 |
| 0x01 | 起始字节 | 用于慢速设备检测总线 |
| 0x04-0x07 | HS模式主码 | 高速模式标识 |
| 0x78-0x7B | 10位地址标识 | 11110XX格式 |
| 0x7C-0x7F | 保留 | 未来扩展用 |
广播地址(0x00)比较特殊。主机发送广播地址时,所有从机都应该应答。我曾在项目中用广播地址实现“一键复位所有传感器”——主机发一个广播命令,所有设备同时复位,省去了逐个操作的麻烦。
关键点:普通设备的可用7位地址范围是
0x08 ~ 0x77(共112个)。设计系统时,要避开保留地址段。
3.4 地址冲突与解决策略
地址冲突,说白了就是两个设备用了同一个地址。这在I2C系统中很常见,尤其是使用相同型号的传感器时。
我遇到过最典型的情况:一块板子上用了两个相同的温度传感器,地址都是 0x48。结果读温度时,两个传感器的数据混在一起,根本分不清谁是谁。
解决地址冲突,有几种常用策略:
- 地址引脚配置——很多I2C芯片有ADDR引脚,通过拉高或拉低来改变地址。比如AT24C02的A0/A1/A2引脚,可以组合出8个不同地址。
- 使用多路复用器——比如PCA9548A,可以分时选通不同的I2C通道,让同一地址的设备在不同时间工作。
- 使能引脚控制——有些芯片有EN或SHDN引脚,通过GPIO控制哪个设备在线。
- 更换地址范围——如果设备支持软件配置地址(如某些数字电位器),可以在初始化时写入不同地址。
我的建议:设计阶段就规划好地址分配表。把每个设备的地址、引脚配置、复用器通道都列出来。别等到焊好板子才发现冲突,那时候改起来就麻烦了。
3.5 地址分配实战流程
下面是我个人习惯的地址分配流程,供你参考:
- 列出所有I2C设备,查数据手册确认可用地址范围
- 排除保留地址(0x00-0x07, 0x78-0x7F)
- 优先使用地址引脚配置,让相同型号设备错开地址
- 如果地址不够,引入多路复用器
- 在代码中定义地址宏,方便后期修改
// 地址分配示例
#define TEMP_SENSOR_1_ADDR 0x48 // ADDR引脚接GND
#define TEMP_SENSOR_2_ADDR 0x49 // ADDR引脚接VCC
#define EEPROM_ADDR 0x50 // A0/A1/A2全接GND
#define MUX_ADDR 0x70 // 多路复用器地址
3.6 知识结构图
下面这张图总结了I2C地址体系的核心内容:
3.7 避坑指南
最后,分享几个我踩过的坑:
- 地址左移的坑:有些库函数已经帮你左移了,你再左移一次就错了。一定要看文档确认。
- 保留地址的坑:别把设备地址设成0x00或0x78附近,否则总线会异常。
- 多设备共存的坑:同一总线上设备太多,总线电容会增大,影响信号质量。一般建议不超过8个设备。
- 地址冲突的坑:如果两个设备地址相同且都应答,总线上的数据会打架,产生总线冲突。
我曾经:在一个项目里用了两个相同地址的传感器,没加复用器,结果读数据时总线一直报错。查了两天才发现是地址冲突。从那以后,我每次画原理图前都会先做地址分配表。