3. I2C地址与寻址:7位地址与10位地址模式、广播地址、保留地址
I2C总线上设备那么多,主控怎么找到它想对话的那个?
答案就是地址。每个从设备都有一个唯一的地址。主设备在发起通信时,先发地址,告诉总线上的所有设备:“我要找的是谁”。
地址不对,数据就传不到正确的设备上。我见过不少新手,焊好板子发现I2C不通,查了半天,最后发现是设备地址搞错了。这种问题,示波器一抓就能看到,但提前搞清楚地址机制,能省很多排查时间。
3.1 7位地址模式
这是I2C最常用的地址模式。说白了,地址就是7个bit,范围从0x00到0x7F。
主设备发送地址时,实际上会发送8个bit:高7位是地址,最低位是读写标志位(0表示写,1表示读)。
关键点:7位地址模式下,总线上最多可以挂 2^7 = 128 个设备。但实际可用地址远少于这个数,因为有一部分地址被保留了。
举个例子。你买一个I2C温度传感器,数据手册上写“设备地址为0x48”。那主设备要读它时,发送的字节就是 0x48 << 1 | 1 = 0x91。写操作则是 0x48 << 1 | 0 = 0x90。
我习惯在代码里这样定义:
#define TEMP_SENSOR_ADDR 0x48
#define TEMP_SENSOR_WRITE (TEMP_SENSOR_ADDR << 1)
#define TEMP_SENSOR_READ ((TEMP_SENSOR_ADDR << 1) | 0x01)
这样写,代码可读性高,也不容易算错。
3.2 10位地址模式
7位地址最多128个设备,去掉保留地址,实际能用的也就一百来个。对于复杂的系统,比如服务器主板、基站设备,这就不够用了。
所以I2C规范定义了10位地址模式。地址范围扩展到0x000到0x3FF,最多支持1024个设备。
10位地址的发送过程有点绕。主设备需要发两个字节:
- 第一个字节:高5位固定为11110,接着是10位地址的高2位,最后1位是读写标志。
- 第二个字节:10位地址的低8位。
举个例子,地址0x2C4(二进制10 1100 0100):
- 高2位:10
- 低8位:1100 0100
- 第一个字节:1111 0 10 R/W = 0xF4(写)或0xF5(读)
- 第二个字节:1100 0100 = 0xC4
我的经验:实际项目中,10位地址用得并不多。大部分消费级、工业级传感器和外围芯片都用7位地址。我只有在做FPGA和某些高端ADC驱动时,才遇到过10位地址的设备。如果你刚开始学I2C,先把7位地址吃透,10位地址了解原理就够了。
3.3 广播地址
广播地址是0x00。主设备发送地址0x00时,总线上的所有从设备都应该响应。
广播一般用于主设备发送“通用命令”,比如“所有设备复位”、“所有设备进入低功耗模式”。
注意:不是所有从设备都支持广播地址。有些设备会忽略0x00地址。设计系统时,不要依赖广播功能,除非你确认所有从设备都支持。
我曾经在一个项目中,想用广播地址同时复位多个传感器。结果发现其中一个传感器根本不响应广播,导致系统状态不一致。从那以后,我都是逐个设备单独发复位命令,虽然多花点时间,但可靠得多。
3.4 保留地址
I2C规范保留了一些特殊地址,用于特定功能。这些地址不能被分配给普通设备。
| 地址(7位) | 用途 | 说明 |
|---|---|---|
| 0x00 | 广播地址 | 所有从设备都应响应 |
| 0x01 | 起始字节 | 用于慢速设备检测起始条件 |
| 0x02 | CBUS地址 | 保留给CBUS兼容设备 |
| 0x03 | 保留 | 未来扩展用 |
| 0x04 - 0x07 | 高速模式主设备码 | 用于高速模式(Hs-mode) |
| 0x78 - 0x7B | 10位地址前缀 | 用于10位地址模式 |
| 0x7C - 0x7F | 保留 | 未来扩展用 |
你看,0x78到0x7B这4个地址,就是10位地址模式用的。所以即使你的设备是7位地址,也不能用这些地址,否则会和10位地址设备冲突。
避坑指南:选型时,一定要确认设备地址不在保留范围内。我见过有人选了地址0x78的传感器,结果怎么都通信不上。查了三天,最后发现是地址冲突。嗯,这种低级错误,犯一次就记住了。
3.5 地址冲突与解决
实际项目中,多个设备可能使用相同地址。比如两个型号一样的温度传感器,地址都是0x48。怎么办?
常见解决办法:
- 地址引脚:很多I2C芯片有ADDR引脚,通过拉高或拉低来改变地址。比如一个传感器,ADDR接GND时地址0x48,接VCC时地址0x49。
- I2C多路复用器:用PCA9548这类芯片,把I2C总线分成多路,每路挂一个同地址设备。
- 片选使能:有些设备有EN引脚,通过GPIO控制,同一时间只让一个设备响应。
我个人比较喜欢用地址引脚的方式,简单可靠,不增加额外芯片。但要注意,有些芯片的地址引脚是内部上拉的,外部拉低时需要强下拉,否则地址可能不稳定。
3.6 地址寻址流程图
下面这张图,把主设备发起通信时的地址寻址流程画清楚了。
流程其实不复杂。主设备发起始条件,然后发地址。从设备如果匹配,就回ACK。主设备收到ACK后,开始传数据。如果没收到ACK,主设备就发停止条件,结束通信。
嗯,这里要注意:如果总线上没有设备响应这个地址,SDA会一直保持高电平(因为上拉电阻)。主设备检测到NACK后,应该及时停止,不要一直重试,否则会浪费总线带宽。
3.7 实际调试中的地址问题
调试I2C设备时,地址问题是最常见的坑之一。我总结了几条经验:
- 先确认地址:拿到新芯片,第一件事就是看数据手册的地址章节。注意7位地址和8位地址的写法差异。有些手册写的是7位地址,有些写的是8位地址(左移后的值)。
- 用逻辑分析仪抓:不要靠猜。把SDA和SCL接到逻辑分析仪上,看主设备实际发送的地址字节。一眼就能看出地址对不对。
- 注意地址引脚电平:如果芯片有ADDR引脚,用万用表量一下实际电平。我遇到过ADDR引脚虚焊,导致地址和预期不一样的情况。
小技巧:Linux下可以用i2cdetect命令扫描总线上的设备。它会尝试所有地址,看哪些设备有响应。比如 i2cdetect -y 1 会扫描I2C总线1上的所有设备。这个命令在调试时非常有用。
地址寻址是I2C通信的基础。搞懂了7位地址、10位地址、广播地址和保留地址,你就能理解主设备是怎么找到从设备的。下次遇到I2C通信问题,先查地址,往往能快速定位问题。