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位地址的发送分两个阶段:

  1. 首字节:高5位固定为11110,接着是10位地址的高两位(bit9~bit8),最低位还是读写位
  2. 第二字节:发送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位地址模式——前提是你的主从机都支持。

地址检测的实用方法

怎么在代码里快速检测地址冲突?我常用的方法:

  1. 发送起始条件 + 该地址的写版本(7位地址左移1位)
  2. 等待应答位
  3. 如果收到ACK,再发一次起始条件并测第二次
  4. 连续两次都成功→说明至少有一个该地址的从机存在
  5. 如果第一次ACK、第二次NACK或数据错乱→很可能有两个从机在回应

嗯,这里要注意:有冲突时数据线可能出现“一半拉低一半高”的竞争状态,逻辑分析仪上看起来像不定态。你直接用示波器看SDA线,会发现波形没有清楚的高低电平,而是卡在中间电压。这就是多个器件同时应答的典型表现。

I2C地址格式与冲突检测流程图 确定器件地址(7位或10位) 左移1位,低位补R/W(7位) 发送起始条件 + 地址字节 收到 ACK? 是 否 可能冲突: 再发一次确认 器件不存在 或地址错误 提示:10位地址需先发11110xy + 第二字节

这张图把地址检测的流程串起来了。你从确定器件地址开始,经过左移位、发送起始条件和地址,然后看是否收到ACK。如果收到ACK也不要高兴太早——还要再重复一次来排除冲突。

避坑指南

我曾经犯过一个低级错误:把7位地址直接当字节发出去,没左移。结果从机根本不应答,我还以为是硬件坏了,换了三块板子……后来看逻辑分析仪才发现字节内容不对。

另一个常见问题是10位地址模式下,有些从机在收到首字节后就会应答,然后等第二字节时才真正匹配。如果你的主机不按这个流程发第二字节,从机可能一直卡住。

所以我的习惯是:不管7位还是10位,都先用逻辑分析仪抓一次波形,确认地址字节、读写位和应答时序都正确。这也算是“一次看对,后面安心”。

总结一句话:7位地址左移1位再发,10位地址分两次发。所有地址冲突最终都能通过示波器或逻辑分析仪看到SDA线上的异常。学会看波形,比死记硬背地址列表靠谱得多。