4. I2C 寻址方式:7位地址、10位地址、保留地址与广播地址

I2C 总线上的设备怎么互相找到对方?

靠的就是地址。每个从机都有一个唯一地址,主机发起通信时,先把地址发到总线上。谁匹配上了,谁就回应。

我刚开始学 I2C 时,总觉得地址就是个简单的编号。后来踩了几次坑才发现,这里面的门道比想象中多。7位、10位、保留地址、广播地址,各有各的规矩。

核心逻辑: 地址格式决定了总线能挂多少设备,也决定了通信的兼容性。选错地址格式,设备可能根本唤不醒。
I2C 寻址方式知识结构 I2C 寻址方式 7位地址格式 0x00 - 0x7F 最常见格式 10位地址格式 0x000 - 0x3FF 扩展寻址 保留地址 0x00 - 0x07 特殊功能 广播地址 0x00 群发指令 ? 关键要点 • 7位地址最多挂112个设备(实际可用) • 10位地址与7位地址完全兼容,但占用特殊头字节 • 保留地址用于特殊总线功能,不能分配给普通设备 • 广播地址(0x00)用于同时唤醒/复位所有从机

4.1 7位地址格式

7位地址,说白了就是一次寻址最多挂128个设备。地址范围从 0x00 到 0x7F。但实际能用的大概112个,因为头几个被保留做特殊用途。

通信时,主机发一个字节作为起始字节。高7位是地址,最低位是读写标志位(R/W)。0表示主机要写,1表示主机要读。

起始字节格式(7位地址):
  位7 - 位1: 从机地址 (A6 ~ A0)
  位0: R/W (0=写, 1=读)

示例:主机向地址 0x27 的从机写数据
  -> 发送字节: 0x4E (0100 1110)
     地址: 0100 111 = 0x27
     R/W: 0 = 写
经验之谈: 我习惯把7位地址左移一位后当成8位值来处理。比如设备地址是0x3C,写操作用0x78,读操作用0x79。这样在代码里看起来更直观。

一个典型的总线拓扑能挂多少设备?

地址位 理论设备数 实际可用(不含保留) 常见应用
7位 128 112 传感器、EEPROM、LCD驱动
10位 1024 约1000 复杂系统中多设备场景

7位地址用的最多。我在项目里接触的传感器、EEPROM、温度芯片,基本都是7位。你想想看,如果总线上只挂三五个设备,7位地址完全够用了。

4.2 10位地址格式

10位地址是干嘛用的?

扩展寻址空间。当总线上设备超过112个,或者地址冲突时,就得用10位了。

这里的实现有点绕。10位地址并不是直接发两个字节,而是用一个特殊的头字节做标志。我第一次用10位地址时,就被那个特殊格式搞晕了。

流程是这样的:

  • 第一步: 主机发第一个字节,高5位固定为 11110,接着是地址的高2位(A9~A8),最后是R/W位。
  • 第二步: 主机发第二个字节,包含地址的低8位(A7~A0)。
  • 第三步: 从机在两步后回应ACK。
10位地址通信示例(地址 = 0x1A3):
  地址高2位: 0x1A3 >> 8 = 0x01 (A9=0, A8=1)
  地址低8位: 0x1A3 & 0xFF = 0xA3

  起始字节1: 1111 0 [A9 A8] [R/W]
            = 1111 0 0 1 0
            = 0xF2 (写操作)

  起始字节2: 0xA3

  从机地址 = 0x1A3
注意: 并不是所有 MCU 的 I2C 外设都支持10位地址。选型时一定要看数据手册。我曾经遇到过一个项目,选了个不支持10位地址的MCU,结果换型号才搞定。

10位地址和7位地址可以混挂在同一条总线上。具体怎么区分?

靠的是第一个字节的高5位。如果是 11110,就是10位地址模式。兼容性做得挺好的。

4.3 保留地址

地址空间里有几个特殊值被固定保留,不能被普通设备占用。我见过有些新手直接把设备地址设成0x00,结果总线上所有从机都响应了,乱成一片。

地址(7位) 用途 说明
0x00 广播/通用呼叫地址 所有支持广播的从机必须响应
0x01 启动字节 用于低速模式下唤醒总线
0x02 保留 CBUS 兼容地址
0x03 - 0x07 保留 未来扩展 / 特殊总线格式
0x78 - 0x7F 10位地址头标志 高5位为11110

我还记得调试一个I2C触摸屏时,从机就是不响应。后来用示波器看波形,发现主机发的地址是0x00。查了数据手册才发现,那个芯片不支持广播,但恰好地址线设置了全0。这属于硬件设计的坑。

避坑指南: 设计新板子时,地址选择引脚尽量避免焊到全0或全1。万一和保留地址冲突,排查起来很痛苦。

4.4 广播地址

广播地址就是 0x00。主机发地址0x00时,所有支持广播模式的从机都必须回应。

广播能干嘛?我最常用的是:系统复位或全局写入某个配置。比如想同时重置所有传感器,发一个广播地址再跟一个复位指令,所有从机一起执行。省去挨个寻址的麻烦。

广播通信过程:

  • 主机发 START 条件
  • 主机发 0x00 + W(写标志)
  • 所有支持广播的从机在第九个SCL周期拉低SDA回应ACK
  • 主机发后续数据字节(比如复位指令)
  • 主机发 STOP 条件

但要注意,不是所有设备都支持广播。很多便宜的传感器会忽略广播地址。我曾经在项目中遇到一个温度传感器,明明数据手册标着支持广播,实际测下来根本不响应。最后只能一个个单独复位。

我的建议: 广播地址用在系统级初始化还行。但做正式产品时,不要依赖广播做关键操作。除非你能保证所有从机都严格支持并经过验证。

4.5 地址冲突与避坑

地址冲突是我在项目中遇到最多的问题。尤其是同一个型号的芯片挂在同一条总线上,每个芯片的地址引脚就那么几个,很容易撞车。

怎么办?

  • 换地址: 有些芯片通过引脚或寄存器可以改地址。优先用不同组合。
  • 加MUX: 实在冲突了,用 I2C 多路复用器(比如 PCA9548)。一个MUX能分出8路,每路独立总线。
  • 用10位地址: 如果你的MCU和从机都支持,直接切换到10位模式。

我个人的习惯是:做原型阶段先列一个地址分配表。7位地址从0x08开始用,0x00-0x07彻底避开。这样即使后续加设备,也不太会踩到保留地址的坑。

好啦,这就是I2C寻址方式的全部核心内容。掌握好这些地址知识,你在I2C调试中就能少走很多弯路。地址选对了,通信就成功了一半。