I2C从机地址与识别:7位地址、10位地址与设备寻址流程
这一章咱们聊I2C从机地址。说白了这个地址就是总线上每个设备的门牌号。主器件发起通信时,先喊一声“我要找门牌号0x50的伙计”,只有那个地址匹配的从机才会应答,其他全部闭嘴。
我刚开始做第一个I2C项目时,以为地址就是个数字写进代码就完了。后来才发现——地址格式、硬件配置、器件手册的写法,这里头坑不少。你想想看,一个传感器地址搞错了,整个总线都查无此人。
7位地址结构
标准模式下I2C使用7位地址。这7位地址放在起始条件后的第一个字节,高7位是地址,最低位是读写标志(R/W)。
关键点:7位地址空间理论上支持128个设备,但由于0x00是广播地址,实际可用的是1~127。
举个例子:一个温湿度传感器从机地址是0x44(二进制1000100),主机要读它,发送的第一个字节就是:
// 7位地址0x44,读操作
// 低字节格式: 1000100 1 = 0x89
// 高字节实际上只有这一个字节
// 写作: 0x44 << 1 | 0x01 = 0x89
如果是写操作,R/W=0,这个字节就是0x44 << 1 | 0 = 0x88。
很多新手在这里犯错。器件手册给出的地址通常是原始7位值,比如“0x68”。你需要在代码里左移一位再加读写位。我在项目里见过有人直接拿0x68去发,结果总线一直不出ACK,查了半天才反应过来。
为了避免混淆,我个人习惯定义一个宏:
#define I2C_ADDR_W(addr) ((addr) << 1 | 0x00) // 写地址
#define I2C_ADDR_R(addr) ((addr) << 1 | 0x01) // 读地址
这样每次调用时,直接传入手册上的7位值就行:I2C_ADDR_R(0x44),清晰得多。
10位地址的使用场景
7位地址只能挂127个设备,听起来不少,但在复杂系统里——比如工业背板、多传感器阵列——很快就用完了。所以I2C规范定义了10位地址扩展。
10位地址的传输用了两个字节:
| 字节 | 高7位/前5位 | 功能 |
|---|---|---|
| 第一个字节 | 11110 xx | 头标志(11110) + 地址高位(2位) + R/W |
| 第二个字节 | 0-255 | 地址低位(8位) |
第一个字节的高5位固定为11110,用来表示“这不是普通7位地址,我是10位扩展”。后面跟地址的高2位,最低位还是R/W。
记得我第一次用10位地址驱动一个64通道的ADC芯片,看起来挺唬人。 实际使用时,注意控制器要支持10位寻址模式。很多低端MCU的I2C外设只支持7位模式,10位地址需要软模拟来实现。
避坑:并非所有从机都支持10位地址。使用前必须查看芯片手册确认。另外,7位地址和10位地址不能混用在同一总线上进行复合传输,否则从机可能无法正确识别。
广播地址(通用呼叫地址)
地址0x00是一个特殊地址——广播地址。主器件发送0x00+R/W=0时,总线上的所有从机都应该应答并接收后续数据。
它的典型用途:
- 系统复位:广播一个特殊命令,让所有从机软复位
- 固件升级:同一批次设备全量更新
- 同步配置:同时修改多个传感器采样率
需要注意的是,不是每个从机都处理广播地址。某些从机即使收到0x00也不会应答。你可以用逻辑分析仪抓一下,看看总线上有没有对应ACK。
实用建议:广播地址在实际项目中不太常用。我见过有人在产线测试时用它来批量重置传感器,省了逐个发命令的时间。但如果系统中的从机不支持,那就变成噪声了。用之前务必确认。
设备寻址流程
好了,核心来了——主机到底怎么找到从机的?流程其实就那么几步:
- 起始条件:SCL高电平时,SDA从高跳低,告诉所有从机“要开始通信了”
- 发送地址字节:主机逐位发送地址(7位或10位)+ R/W位
- 等待ACK:每发送8位后,主机释放SDA,从机在第9个时钟周期拉低SDA表示“是我,我在”
- 匹配失败处理:如果SDA在第9个时钟保持高电平,说明没有从机认领这个地址,主机应发送停止条件或重新开始
- 进一步传输:地址匹配成功后,按R/W位决定后续是主机写还是主机读
实际调试时,我最常用逻辑分析仪看起始条件后的第一个字节。如果那个字节和预期一致,并且第9个时钟能看到ACK,那就说明地址识别成功了。如果看不到ACK,有几种可能:
- 从机地址写错了(最频繁的bug)
- 从机电源没上
- 上拉电阻太大导致上升沿太慢
- 总线被其他器件拉死
我曾经在一个量产项目里遇到过,某个批次传感器地址读出来总是错的。最后发现是焊接工厂用了一个不同版本的传感器,地址偏移了一位。从此以后,我在BOM里强制标注了具体地址配置引脚的电平。
下面的图概括了整个设备寻址的核心流程,从主机发起起始条件到从机ACK确认:
你看,整个流程就是从起始条件开始,发地址,等ACK。简单吧?但越是简单的东西,在实际工程里越容易出幺蛾子。
硬件地址配置引脚
大多数I2C从机芯片都有一组地址配置引脚,比如A0、A1、A2。通过拉高或拉低这些引脚,可以改变芯片的7位地址。
典型情况:一款温度传感器地址基值是0x48,A2、A1、A0分别对应地址bit2、bit1、bit0。你把这些引脚全部接GND,地址就是0x48;把A0接VDD,地址变成0x49。这样一来,一条I2C总线上可以挂8个相同的传感器。
小技巧:设计PCB时把配置引脚都加上上拉/下拉电阻的焊盘。既能默认接GND,又方便调试时飞线改地址。我早期有个设计直接把A0-A1-A2接到了MCU的GPIO,可以软件配地址——虽然灵活,但浪费了3个宝贵的IO口,后来很少这么干了。
好了,到这你已经理解了I2C从机地址的来龙去脉。下一堂我会讲I2C时序级的工作流程,包括START、STOP、数据字节传输,以及时钟同步和仲裁——这些东西是做高速数据采集绕不开的基础。