I2C 寻址与读写操作:7位/10位地址、读写位、数据帧结构

咱们做嵌入式开发,天天跟I2C打交道。地址搞错了,总线就哑火。今天我就把这块掰开了揉碎了讲清楚。

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

市面上95%的I2C器件都用7位地址。说白了,就是主机在总线上喊一声:“谁是0x3C?” 从机听到是自己的号,就回一声“到!”。

7位地址的范围是0x00到0x7F。但实际能用多少?嗯,这得看器件手册。比如常用的AT24C02 EEPROM,它的地址是0x50(7位)。但我记得有一次调试一个温湿度传感器,手册上写地址0x40,结果逻辑分析仪抓出来是0x80——少了左移一位!这是个经典坑。

7位地址值左移1位(8位写地址)左移1位+1(8位读地址)
0x500xA00xA1
0x3C0x780x79
0x400x800x81
我的习惯: 我一般用7位地址来沟通,写代码时才转成8位操作地址。这样跟同事对表不容易晕。

二、10位地址:扩展的玩法

7位地址最多挂128个设备,够不够?项目中我遇到过挂几十个传感器的情况,地址冲突那是家常便饭。这时候10位地址就派上用场了。

10位地址怎么发?其实它由两个阶段组成:

  • 第一个字节:11110xx + R/W,其中xx是10位地址的高2位。
  • 第二个字节:剩下的8位地址。

举个例子:10位地址0x2A6(二进制:10 1010 0110)

  1. 高2位是10,所以第一个字节是 1111 0100 + R/W(写为0)= 0xF4
  2. 低8位是 1010 0110 = 0xA6

逻辑分析仪上抓到的是:0xF4 0xA6 这样一个两字节的头。你想想看,普通7位地址只用1个字节头,10位地址需要2个,时序上自然慢一些。

三、读写位:方向的决定者

地址字节的最低位就是读写位。0表示写操作,1表示读操作。这个再简单不过了,但有件事我必须提醒:很多初学者在逻辑分析仪上看到地址0xA0,以为是0xA0号设备,其实人家是0x50(7位)+ 写位0!

注意: 我曾经在产线上排查一个批量故障,发现软件工程师把7位地址0x50写成了0xA0。结果就是主机往0xA0发数据,总线上一片安静。逻辑分析仪一抓,所有从机都没应答。原因?地址压根不对应。

四、数据帧结构:一帧一帧看透它

I2C通信就是一串帧的串联。每个完整的读写操作包含:

步骤描述SDA/SCL状态
StartSCL高时SDA从高变低始发信号
从机地址7位或10位地址主机驱动SDA
R/W位0写 1读主机驱动
ACK位从机拉低SDA表示应答从机驱动
数据字节8位数据,MSB在前主机或从机驱动
ACK位每字节后跟一个应答从机或主机驱动
StopSCL高时SDA从低变高终止信号

用逻辑分析仪看,其实就几根线在那跳来跳去。抓一个完整的写操作,你会看到 Start → 地址+R/W → ACK → 数据 → ACK → Stop 这样一个流程。

// 伪代码:逻辑分析仪解析出的写操作波形
// 起始条件:SCL高时SDA下降沿
// 地址:0x50 (7位) + 写位0 = 0xA0
// 从机应答:SDA被拉低1个时钟
// 数据:0x00 (寄存器地址) + ACK
// 数据:0xFF (写数据) + ACK
// 停止条件:SCL高时SDA上升沿

核心要点: 每个字节后必跟一个ACK/NACK。如果从机不拉低SDA(即SDA保持高),就是NACK。这是排查应答失败的关键信号。

五、知识结构总览

下面这张图帮你理清I2C寻址与读写的数据流向:

I2C数据帧结构流程图 Start条件 从机地址(7/10位) R/W位(0/1) ACK位 数据字节(8位) Stop条件 10位地址扩展字节 说明: 每个字节(地址或数据)后必须跟一个ACK/NACK位,从机应答检测是排查故障的关键。 10位地址分两个阶段发送:第一个阶段的高5位固定11110,第二个阶段是低8位。

看到没?从Start到Stop是一条完整的链路。我一般在逻辑分析仪上就是按这个顺序逐帧检查的。哪一帧没ACK,问题就出在哪。

六、避坑指南

  • 地址左移的坑: 我曾经一个项目里,新手直接把7位地址0x3C当8位用。结果主机发的0x3C对应7位地址的0x1E+写位。总线不认是必然的。
  • 10位地址格式: 别把第一个字节的高位搞错。11110是固定前缀,后面跟地址高2位。我见过有人在代码里写0xF0作为保留字节,结果地址对不上。
  • 读写位混淆: 写操作发0xA0,读操作发0xA1。很多人把0xA0当成了设备地址,忘了最后一位是方向。逻辑分析仪上一看,地址没问题,但方向不对。
  • 多字节读写: 连续读写时,每字节后都有ACK。我记得有一次项目里,从机在连续写时突然返回NACK,查了半天才发现是地址指针超出范围了。

讲到这里,I2C的地址和数据帧结构你应该清楚了。下次用逻辑分析仪抓总线,对着这个结构一帧一帧对,保证问题一秒定位。