4. I2C地址与读写操作:7位地址与10位地址、读/写位、从机地址识别、广播地址

好,咱们进入I2C协议里最核心也最容易踩坑的部分——地址与读写操作。

你想想看,一条I2C总线上挂着好几个器件,主控怎么知道要跟谁说话?是读数据还是写数据?这就是地址和读写位要解决的问题。

4.1 7位地址:最常用的寻址方式

绝大多数I2C器件都使用7位地址。什么意思呢?就是每个从机有一个7位的编号,范围从0x00到0x7F。

但注意,0x00是广播地址,0x7F保留,实际可用的是0x01到0x7E。

我刚开始做项目时,总觉得7位地址就是7个bit,直接发7位不就行了?错!

实际上,I2C协议在发送地址时,会把7位地址左移1位,最低位用来表示读写方向。所以你在逻辑分析仪上看到的地址字节,其实是:

地址字节 = (7位地址 << 1) | R/W位

举个例子:

  • 如果从机地址是0x50(二进制1010000)
  • 要写数据,R/W=0,发送的字节就是0xA0(10100000)
  • 要读数据,R/W=1,发送的字节就是0xA1(10100001)

重点记住:逻辑分析仪上抓到的第一个字节,是左移后的结果。别直接拿0xA0当从机地址去查手册,你得右移1位才是真实地址。

4.2 10位地址:什么时候用?

7位地址最多支持112个器件(去掉保留地址)。对于大多数项目来说够用了。但有些复杂系统,比如服务器主板、工业控制板,器件一多就不够用了。

这时候就有了10位地址。

10位地址怎么传输?它用了两个字节:

  1. 第一个字节:高5位固定为11110,接着是10位地址的高2位,最后是R/W位
  2. 第二个字节:剩下的8位地址

举个例子,地址0x2A4(二进制10 1010 0100):

  • 高2位是10,所以第一个字节 = 1111 0 10 + R/W
  • 写操作时:第一个字节0xF4,第二个字节0xA4

我的经验:10位地址在实际项目中用得不多。我做了十年嵌入式,只在某款高端温度传感器上用过一次。大部分时候,7位地址足够了。但你要知道它的存在,万一遇到了别懵。

4.3 读/写位:方向决定一切

R/W位是地址字节的最低位。0表示主控要写,1表示主控要读。

这个位决定了后续数据流的方向:

R/W位 操作 数据流向
0 写操作 主控 → 从机
1 读操作 从机 → 主控

这里有个常见的坑:很多新手以为发送完地址后,数据方向就固定了。其实不是!

你可以通过发送重复起始条件(Sr)来改变方向。比如先写寄存器地址,再读数据:

主控发送: 起始条件 + 从机地址(写) + 寄存器地址 + 重复起始条件 + 从机地址(读) + 读取数据 + 停止条件

我曾经踩过的坑:有一次调试一个加速度传感器,我发送了写地址后直接读数据,结果读回来的全是0xFF。折腾了两天,最后发现需要先发重复起始条件,把方向从写切换到读。逻辑分析仪上一看,波形清清楚楚——我少发了一个Sr信号。

4.4 从机地址识别:谁在应答?

主控发送地址后,会释放SDA线,然后产生第9个时钟脉冲。这时候,地址匹配的从机会拉低SDA线,发出ACK信号。

如果没收到ACK,说明:

  • 地址写错了
  • 从机没上电
  • 从机正忙
  • 总线有问题

我个人的习惯是:调试时先用逻辑分析仪抓一下起始条件后的第一个ACK。如果没看到ACK,先检查地址对不对,再看电源和上拉电阻。

另外要注意:有些从机支持多个地址。比如某些EEPROM,通过A0/A1/A2引脚可以配置8个不同的地址。这时候你得确认硬件上的引脚电平跟代码里的地址一致。

4.5 广播地址:一呼百应

广播地址是0x00(左移后是0x00)。当主控发送0x00时,所有支持广播的从机都会响应。

广播地址一般用在:

  • 系统复位:让所有从机同时复位
  • 全局配置:比如设置所有传感器的采样率
  • 固件升级:有些器件支持广播进入升级模式

但注意,不是所有从机都支持广播地址。我见过一个项目,工程师想用广播地址同时配置10个温度传感器,结果只有3个响应了。查手册才发现,其他7个不支持广播。

避坑指南:使用广播地址前,一定要看每个从机的手册。有些器件虽然支持广播,但需要先通过某个寄存器使能。我曾经因为没使能广播功能,浪费了半天时间。

4.6 实战:用逻辑分析仪抓地址

好了,理论说完了。咱们看看实际怎么用逻辑分析仪抓地址问题。

假设你写了一段代码:

// 向地址0x50的EEPROM写数据
i2c_start();
i2c_write(0xA0);  // 0x50左移1位 + 写位
// 等待ACK...
i2c_write(0x00);  // 寄存器地址高字节
i2c_write(0x10);  // 寄存器地址低字节
i2c_write(0x55);  // 要写的数据
i2c_stop();

用逻辑分析仪抓到的波形应该是:

  • 起始条件:SCL高电平时SDA从高变低
  • 地址字节:0xA0(二进制10100000)
  • 第9个时钟:SDA被拉低(ACK)
  • 数据字节:0x00、0x10、0x55
  • 停止条件:SCL高电平时SDA从低变高

如果没看到ACK,检查:

  1. 地址对不对?0xA0右移1位是0x50,跟手册一致吗?
  2. 从机供电正常吗?用万用表量一下VCC和GND
  3. 上拉电阻焊了吗?我见过好几次忘记焊上拉电阻的
  4. SDA/SCL有没有接反?别笑,真有人接反过

嗯,地址这块就讲这么多。说白了就是:地址要左移,读写看最低位,没ACK先查硬件。记住这三点,I2C地址这块你就不会出大问题。