4、I2C地址与读写位解码:7位地址与10位地址识别
地址解码,是I2C调试的第一步。说白了,逻辑分析仪抓到的波形里,第一个字节就是地址+读写位。但很多人栽就栽在地址的“7位”和“8位”换算上。我见过不少工程师,拿着逻辑分析仪的数据,对着数据手册愣是半天对不上号。
为什么会这样?因为I2C协议里,地址字节是8位,但真正的设备地址只有7位,最低位是读写位。你从逻辑分析仪上读到的0xA0,实际设备地址是0x50。这个换算关系,是入门第一道坎。
4.1 7位地址结构:从波形到数值
先看一个典型的I2C起始条件后的第一个字节。逻辑分析仪解码出来,通常显示为:
S Addr: 0x50 W ACK
这个0x50是怎么来的?我们拆开看:
| 位序 | 7 (MSB) | 6 | 5 | 4 | 3 | 2 | 1 | 0 (LSB) |
|---|---|---|---|---|---|---|---|---|
| 波形值 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| 含义 | 7位设备地址:0x50 (1010000) | R/W=0 (写) | ||||||
逻辑分析仪显示的0x50,其实是7位地址0x50左移1位,再加上读写位0。换算公式很简单:
总线字节 = (设备地址 << 1) | R/W
举个例子:设备地址0x50,写操作时总线字节 = (0x50 << 1) | 0 = 0xA0。读操作时 = (0x50 << 1) | 1 = 0xA1。
4.2 10位地址识别:别被波形骗了
10位地址在消费电子里用得少,但在工业传感器、电源管理芯片里很常见。我第一次遇到10位地址时,逻辑分析仪解码出来显示“Addr: 0x78”,我以为是7位地址,结果怎么都通信不上。
10位地址的识别标志,在于第一个字节的高5位。协议规定:
- 7位地址:第一个字节高7位是地址,最低位是R/W。高5位范围0x00~0x78。
- 10位地址:第一个字节高5位固定为11110,即第一个字节范围0xF0~0xF7。后跟第二个字节,补全剩余8位地址。
看个实际波形:
S 11110xx R/W ACK 8位地址低字节 ACK
比如一个10位地址为0x2B4的设备,写操作时总线序列为:
S 0xF6 (11110110) W ACK 0xB4 ACK
拆解一下:0xF6的高5位是11110,表示10位地址模式。低2位是10,加上第二个字节0xB4,组成10位地址0x2B4。R/W位是0,表示写。
4.3 读写位判断:主从角色转换的时机
读写位(R/W)决定了数据流向。但很多人只记住了“0是写,1是读”,忽略了主从角色转换的细节。
写操作时,主机发送地址+R/W=0,从机ACK后,主机继续发送数据字节。读操作时,主机发送地址+R/W=1,从机ACK后,从机开始发送数据,主机每收到一个字节后发送ACK。
关键点在于:读操作时,主机在发送完地址后,必须释放SDA线,转为输入模式。如果主机没有释放SDA,从机无法拉低SDA发送数据,就会导致通信卡死。
逻辑分析仪上判断读写位的方法:
- 看第一个字节的最低位。0=写,1=读。
- 看数据流向。写操作时,SDA上的数据变化由主机驱动;读操作时,SDA上的数据变化由从机驱动。
- 看ACK/NACK。读操作时,主机在最后一个字节发送NACK,表示读取结束。
4.4 从机地址冲突排查:波形里的“幽灵”
地址冲突,是I2C调试里最隐蔽的问题之一。两个从机地址相同,或者地址被误配置,会导致通信混乱。逻辑分析仪是排查地址冲突的最佳工具。
地址冲突的典型表现:
- ACK飘忽不定:同一个地址,有时有ACK,有时没有。这是因为两个从机都在响应,但驱动能力不同,导致总线电平不确定。
- 数据错乱:主机发送的数据,被错误的从机接收。或者主机读取的数据,来自错误的从机。
- 总线锁死:两个从机同时拉低SDA,导致SDA一直为低,无法释放。
排查步骤:
- 确认设备地址:查看每个从机的数据手册,确认其7位或10位地址。注意地址引脚(如A0、A1、A2)的配置。
- 抓取完整通信:用逻辑分析仪抓取从起始条件到停止条件的完整波形。
- 检查地址字节:看第一个字节是否与预期一致。如果多个从机地址相同,波形上会出现多个ACK。
- 检查ACK时序:正常情况,一个地址只对应一个ACK。如果出现两个ACK,或者ACK的时序异常(比如ACK脉冲宽度不一致),说明有地址冲突。
- 逐个断开从机:如果怀疑地址冲突,可以逐个断开从机,看问题是否消失。
4.5 地址解码实战:一个完整的排查案例
去年我调试一个温湿度传感器模块,用了SHT30和BMP280两个芯片。SHT30的地址是0x44,BMP280的地址是0x76。按理说不会冲突。但实际通信时,读取BMP280的数据总是出错。
用逻辑分析仪抓波形,发现主机发送地址0x76后,总线上出现了两个ACK。我一开始以为是逻辑分析仪解码错误,但放大波形看,SDA线上确实有两个低电平脉冲。
排查过程:
- 检查原理图,发现BMP280的SDO引脚被拉高了,地址应该是0x77。但代码里写的是0x76。
- 再查SHT30的数据手册,发现它的地址可以通过ADDR引脚配置。默认是0x44,但ADDR引脚悬空时,地址会变成0x76。
- 原来,SHT30的ADDR引脚没接,处于高阻态,内部上拉使其地址变为0x76。和BMP280的0x76冲突了。
解决方法:把SHT30的ADDR引脚拉低,地址恢复为0x44。问题解决。
4.6 知识结构图:地址解码核心逻辑
下面这张图,总结了7位地址和10位地址的识别流程,以及地址冲突的排查路径。建议保存下来,调试时对照着看。
这张图的核心逻辑:先判断是7位还是10位地址,再根据R/W位确定数据流向,最后检查ACK是否正常。如果ACK异常,进入地址冲突排查流程。
4.7 地址解码常见问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 逻辑分析仪显示地址与数据手册不符 | 7位/8位地址换算错误 | 用公式 总线字节 = (设备地址 << 1) | R/W 重新计算 |
| 第一个字节在0xF0~0xF7范围 | 可能是10位地址 | 检查第二个字节,组合成10位地址 |
| 同一个地址出现多个ACK | 地址冲突 | 逐个断开从机,检查地址引脚配置 |
| ACK时序异常(脉冲宽度不一致) | 多个从机同时响应 | 放大波形,看SDA低电平时间是否一致 |
| 读操作时SDA一直为高 | 主机未释放SDA,或从机未响应 | 检查主机代码,确认读操作时是否将SDA设为输入 |
| 写操作时从机返回NACK | 从机忙,或地址错误 | 检查从机状态,确认地址是否正确 |
嗯,地址解码这部分,说白了就是“看第一个字节,算地址,判方向”。但实际调试中,细节往往藏在波形里。多抓几次,多对比,慢慢就有感觉了。