I2C地址格式:7位地址与10位地址
你拿到一个传感器,数据手册写着“I2C地址 0x48”。但实际发的时候,发现总是没应答。
排查半天,原来人家写的是7位地址0x48,而你发的时候左移了一位变成0x90。这种坑我踩过不止一次。今天我们就彻底把地址格式搞清楚。
7位地址格式——最常用的寻址方式
I2C总线从机地址标准长度是7位。地址范围从0x00到0x7F,但实际可用的地址要剔除保留值。我记得第一次画板子,两个器件都选了0x48,结果只能在示波器上看到时钟和数据在“打架”。
7位地址的发送过程,说白了是这样的:
- 主机先发起始信号
- 接着把7位地址左移1位,最低位补读写位(0写、1读)
- 这样拼成一个字节发送
- 从机匹配地址后在第9个时钟周期拉低SDA表示应答
所以当你看到数据手册说“Device Address = 0x3C”时,实际发送的字节是:
0x3C << 1 = 0x78 (写操作)
0x3C << 1 | 0x01 = 0x79 (读操作)
关键点:7位地址只有1~127可用。地址0x00是通用呼叫地址,0x01~0x07为保留地址,0x78~0x7F用于10位地址扩展。实际可用地址约112个。
10位地址格式——突破地址瓶颈
一个总线上挂20多个器件?7位地址根本不够用。这时候就需要10位地址了。说实话,10位地址在日常项目里用得不多,但在需要大量从机的系统中它很关键。
10位地址的发送分两个阶段:
- 首字节:高5位固定为11110,接着是10位地址的高两位(bit9~bit8),最低位还是读写位
- 第二字节:发送10位地址的低8位(bit7~bit0)
举个例子,10位地址0x2C4:
高两位 = 0b10
首字节 = 11110 10 R/W = 0xF4(写)或0xF5(读)
第二字节 = 0xC4
切记:10位地址器件发送NACK后,主机不能马上重发同一地址,要先发送停止条件。我曾经在这个问题上卡了一下午,从机怎么都不应答,后来发现是NACK后没给停止信号。
7位 vs 10位——快速对比
| 特性 | 7位地址 | 10位地址 |
|---|---|---|
| 地址容量 | 128个(可用约112个) | 1024个 |
| 传输字节数 | 1个起始字节 | 2个起始字节 |
| 兼容性 | 所有从机都支持 | 需要从机硬件支持 |
| 保留地址 | 0x00~0x07、0x78~0x7F | 首字节0xF0~0xFE |
| 典型应用 | 传感器、存储器、ADC | 大型传感器阵列、多路复用器 |
地址冲突的核心根源
地址冲突说白了就是两个从机用了同一个地址,主机发寻址时两个器件都试图应答。你想想看,那时钟线还正常,数据线能被拉低到什么状态?根本不可预测。
我建议你把项目中用到的I2C地址整理成一张清单,每次选型时对照查一下。比如:
- 常见的EEPROM(如24C02)地址由A2/A1/A0引脚决定,默认0x50~0x57
- 温湿度传感器SHT30地址默认0x44(7位)
- 加速度计MPU6050地址0x68(AD0接低)或0x69(AD0接高)
你发现没有?很多器件的默认地址都是0x48~0x4F这个区间,冲突概率特别高。所以每次我画原理图前,都会先把所有I2C器件地址列出来,保证没有重复的。
小技巧:如果7位地址冲突难以避免,可以考虑使用I2C多路复用器(如TCA9548A)将总线分成多个通道,每个通道独立寻址。或者改用10位地址模式——前提是你的主从机都支持。
地址检测的实用方法
怎么在代码里快速检测地址冲突?我常用的方法:
- 发送起始条件 + 该地址的写版本(7位地址左移1位)
- 等待应答位
- 如果收到ACK,再发一次起始条件并测第二次
- 连续两次都成功→说明至少有一个该地址的从机存在
- 如果第一次ACK、第二次NACK或数据错乱→很可能有两个从机在回应
嗯,这里要注意:有冲突时数据线可能出现“一半拉低一半高”的竞争状态,逻辑分析仪上看起来像不定态。你直接用示波器看SDA线,会发现波形没有清楚的高低电平,而是卡在中间电压。这就是多个器件同时应答的典型表现。
这张图把地址检测的流程串起来了。你从确定器件地址开始,经过左移位、发送起始条件和地址,然后看是否收到ACK。如果收到ACK也不要高兴太早——还要再重复一次来排除冲突。
避坑指南
我曾经犯过一个低级错误:把7位地址直接当字节发出去,没左移。结果从机根本不应答,我还以为是硬件坏了,换了三块板子……后来看逻辑分析仪才发现字节内容不对。
另一个常见问题是10位地址模式下,有些从机在收到首字节后就会应答,然后等第二字节时才真正匹配。如果你的主机不按这个流程发第二字节,从机可能一直卡住。
所以我的习惯是:不管7位还是10位,都先用逻辑分析仪抓一次波形,确认地址字节、读写位和应答时序都正确。这也算是“一次看对,后面安心”。
总结一句话:7位地址左移1位再发,10位地址分两次发。所有地址冲突最终都能通过示波器或逻辑分析仪看到SDA线上的异常。学会看波形,比死记硬背地址列表靠谱得多。