3. I2C 地址与数据传输格式:7位地址与10位地址、读写位、数据帧格式

I2C 总线上的每个从设备都有一个唯一的地址,主设备通过地址来寻址特定的从设备进行通信。理解地址格式与数据帧结构是编写 I2C 驱动的基础,也是确保传感器数据正确采集的前提。

3.1 7位地址与10位地址

I2C 协议支持两种地址长度:7位地址 和 10位地址。绝大多数传感器(如温度、湿度、加速度计等)使用 7 位地址,以节省总线带宽并简化驱动逻辑。

特性 7位地址 10位地址
地址范围 0x00 ~ 0x7F(128个地址,其中16个保留) 0x000 ~ 0x3FF(1024个地址)
总线上的地址字节数 1字节(高7位为地址,最低位为读写位) 2字节(第一个字节高5位为11110,后跟地址高2位 + 读写位;第二个字节为地址低8位)
常见应用场景 温度传感器、加速度计、EEPROM、ADC/DAC 复杂多路复用器、高端电源管理芯片、地址冲突较多的系统
驱动复杂度 低,直接使用 7 位地址即可 较高,需要处理地址扩展头
驱动开发提示: 在 Linux 内核中,I2C 从设备地址统一使用 7 位表示。对于 10 位地址设备,内核通过 I2C_TENBIT 标志位来区分。在设备树中,10 位地址需要显式声明 reg = <0x10 0x1234> 格式。

3.1.1 7位地址帧格式

主设备发送的第一个字节包含 7 位从设备地址和 1 位读写标志。地址字节的格式如下:

7位地址帧格式(主设备发送的第一个字节) A6 A5 A4 A3 A2 A1 A0 R/W 7位从设备地址(MSB → LSB) 读写位 R/W = 0:主设备写数据到从设备 R/W = 1:主设备从从设备读数据

3.1.2 10位地址帧格式

10 位地址使用两个字节进行传输。第一个字节的高 5 位固定为 11110,后跟地址的高 2 位(A9、A8)和读写位;第二个字节为地址的低 8 位(A7 ~ A0)。

10位地址帧格式(主设备发送的前两个字节) 1 1 1 1 0 A9 A8 R/W A7 A6 A5 A4 A3 A2 A1 A0 固定头 11110 地址高2位 R/W 地址低8位(A7 ~ A0)

3.2 读写位(R/W)

读写位是地址字节的最低位,用于指示数据传输方向:

  • R/W = 0(写操作):主设备向从设备发送数据。主设备在发送地址后,继续发送寄存器地址或数据字节。
  • R/W = 1(读操作):主设备从从设备读取数据。主设备发送地址后,从设备开始发送数据字节到主设备。
驱动开发关键点: 在 Linux I2C 驱动中,读写位由内核 I2C 核心自动处理。驱动开发者只需在 i2c_msg 结构体中设置 flags 字段:0 表示写,I2C_M_RD 表示读。无需手动拼接地址字节。

3.3 数据帧格式

I2C 数据传输以帧为单位,每帧包含一个起始条件、地址字节、若干数据字节和一个停止条件。每个字节后跟随一个应答位(ACK/NACK)。

3.3.1 完整写操作数据帧

I2C 写操作数据帧格式(主设备 → 从设备) S 地址 + W ACK Reg Addr ACK Data 1 ACK Data N ACK P 起始 从设备地址 应答 寄存器地址 数据字节 停止 写操作流程:主设备先发送起始条件 → 从设备地址 + 写位 → 等待 ACK → 发送寄存器地址 → 等待 ACK → 发送一个或多个数据字节 → 等待 ACK → 发送停止条件 每个数据字节后从设备必须回复 ACK,否则主设备会终止传输

3.3.2 完整读操作数据帧

I2C 读操作数据帧格式(主设备 ← 从设备) S 地址 + W ACK Reg Addr ACK Sr 地址 + R ACK Data 1 ACK 起始 地址+写 寄存器地址 重复起始 地址+读 数据字节 读操作流程(两步法): 步骤1:主设备发送起始条件 → 从设备地址 + 写位 → 发送寄存器地址 → 等待 ACK 步骤2:主设备发送重复起始条件(Sr)→ 从设备地址 + 读位 → 等待 ACK → 从设备发送数据字节 → 主设备回复 ACK(继续读)或 NACK(停止)→ 主设备发送停止条件 最后一个数据字节主设备回复 NACK 表示读结束

3.4 应答位(ACK/NACK)机制

每个字节传输完成后,接收方必须在第 9 个 SCL 时钟周期内拉低 SDA 线(ACK)或保持高电平(NACK)。

应答类型 SDA 电平 含义 典型场景
ACK(应答) 低电平 接收方已成功接收字节,可以继续传输 地址匹配成功、数据写入成功、读数据时主设备希望继续读取
NACK(非应答) 高电平 接收方未准备好或传输结束 地址未匹配、从设备忙、读操作最后一个字节后主设备通知停止
驱动调试常见问题: 如果 I2C 通信卡在地址发送阶段,且从设备回复 NACK,通常原因包括:
• 设备地址错误(检查数据手册和原理图)
• 从设备未上电或处于复位状态
• 总线被其他设备拉死(SDA/SCL 电平异常)
• 地址 7 位/10 位模式不匹配

3.5 典型传感器 I2C 地址示例

以下列出常见传感器的 7 位 I2C 地址(通常数据手册会给出 8 位地址,需要右移 1 位得到 7 位地址):

传感器型号 类型 7位地址(十六进制) 地址引脚配置
BME280 温湿度/气压 0x76 或 0x77 SDO 引脚电平决定
MPU6050 6轴IMU 0x68 或 0x69 AD0 引脚电平决定
LSM6DS3 6轴IMU 0x6A 或 0x6B SA0 引脚电平决定
TC74 温度传感器 0x48 ~ 0x4F A0~A2 引脚组合决定
AT24C02 EEPROM 0x50 ~ 0x57 A0~A2 引脚组合决定
地址转换技巧: 数据手册通常给出 8 位地址(如 0xD0 表示写、0xD1 表示读)。在 Linux 驱动中,i2c_client 的 addr 字段使用 7 位地址。转换方法:7位地址 = 8位地址 >> 1。例如 0xD0 >> 1 = 0x68。

3.6 数据帧格式总结

I2C 数据帧的核心要素可以归纳为以下流程:

  1. 起始条件(S):SCL 高电平时,SDA 从高到低跳变。
  2. 地址字节:7 位或 10 位地址 + 读写位。
  3. 应答位(ACK):从设备在第 9 个时钟拉低 SDA。
  4. 数据字节:8 位数据,MSB 先传,每个字节后跟应答位。
  5. 重复起始条件(Sr):用于读操作时切换方向,不释放总线。
  6. 停止条件(P):SCL 高电平时,SDA 从低到高跳变。

掌握地址格式和数据帧结构后,下一步就可以在 Linux 驱动中实现 I2C 读写操作,并结合中断处理完成传感器数据的实时采集。