2. I2C 数据帧格式:7位地址模式、10位地址模式、读写位、ACK/NACK机制

I2C 总线上的数据传输以帧为单位,每一帧由起始条件、从机地址、读写控制、数据字节和应答位组成。理解数据帧格式是编写 I2C 驱动的基础,直接决定了寄存器配置中地址寄存器、控制寄存器和数据寄存器的操作方式。

2.1 帧结构基础:起始条件与停止条件

SCL 为高电平时,SDA 上的跳变定义总线的开始与结束:

  • 起始条件 (S):SCL 高电平,SDA 从高切换到低。
  • 停止条件 (P):SCL 高电平,SDA 从低切换到高。

每次传输必须以 S 开始,以 P 结束。中间可以插入重复起始条件 (Sr),用于改变传输方向而不释放总线。

2.2 7位地址模式数据帧

7 位地址模式是最常用的 I2C 寻址方式,一帧完整的数据传输包含以下字节序列:

字节序号 位域 说明
1 7 位从机地址 + R/W 高 7 位为地址,最低位为读写方向
2 ACK/NACK 从机在第 9 个 SCL 周期拉低 SDA 表示应答
3 ~ N 8 位数据 + ACK/NACK 每字节后跟一个应答位,直到停止条件
关键点:R/W = 0 表示主机写(发送数据),R/W = 1 表示主机读(接收数据)。从机地址左移 1 位后与 R/W 位拼接,构成第一个字节。
// 7位地址模式下,主机向从机 0x48 写入一个字节 0xA5
// 地址左移1位 + W = 0x90
// 发送序列:S + 0x90 + ACK + 0xA5 + ACK + P

2.3 10位地址模式数据帧

当系统中从机数量超过 127 个时,使用 10 位地址模式。该模式将地址分两个字节发送:

字节序号 位域 说明
1 11110 + 地址[9:8] + R/W 高 5 位固定为 11110,后跟地址高 2 位
2 地址[7:0] 地址低 8 位
3 ~ N 数据 + ACK/NACK 与 7 位模式相同
驱动开发提示:MCU 的 I2C 外设通常通过寄存器位(如 I2C_CR1 中的 ADDR10 位)选择 7 位或 10 位模式。10 位模式下,地址寄存器需要分两次写入。

2.4 读写位与传输方向控制

R/W 位控制总线的数据流向:

  • 主机写 (W = 0):主机发送数据,从机接收。主机产生 SCL 时钟,并在每个字节后等待从机 ACK。
  • 主机读 (R = 1):主机接收数据,从机发送。主机产生 SCL 时钟,并在每个字节后主动发送 ACK(最后一个字节发 NACK 以通知从机停止)。

组合传输(先写后读)通过重复起始条件实现:

// 典型组合传输:写寄存器地址 + 读数据
// S + 0x90(写) + ACK + REG_ADDR + ACK + Sr + 0x91(读) + ACK + DATA + NACK + P

2.5 ACK/NACK 机制

每个字节传输完成后,接收方在第 9 个 SCL 周期控制 SDA 线:

信号 SDA 状态 含义
ACK 低电平 接收成功,可以继续传输下一字节
NACK 高电平 接收失败或传输结束,主机应发送停止条件
常见驱动 Bug:主机读最后一个字节后未发送 NACK,导致从机继续发送数据,总线卡死。务必在最后一个数据字节的 ACK 周期前配置 NACK 位。

2.6 数据帧结构总览

下图展示了 7 位地址模式下一次完整写传输的帧结构:

7位地址模式写传输帧结构 S 地址 + W ACK 数据1 ACK 数据N ACK P 每个字节(地址或数据)后必须跟一个 ACK/NACK 位,由接收方在第 9 个 SCL 周期驱动。 主机在最后一个数据字节后发送 NACK 并产生停止条件,从机释放总线。 起始/停止 地址字节 ACK 数据字节 停止

2.7 10位地址模式与7位地址模式对比

对比项 7位地址模式 10位地址模式
地址范围 0x00 ~ 0x7F(128 个地址,保留 16 个) 0x000 ~ 0x3FF(1024 个地址)
首字节格式 地址[6:0] + R/W 11110 + 地址[9:8] + R/W
地址字节数 1 字节 2 字节
兼容性 所有 I2C 设备 仅支持 10 位地址的设备
寄存器配置 ADDR10 = 0 ADDR10 = 1

2.8 驱动开发中的帧处理要点

  • 起始条件检测:轮询模式下等待 SB 标志位,中断模式下在 SB 中断服务程序中处理。
  • 地址发送完成:等待 ADDR 标志位,读取 SR1+SR2 寄存器清除标志。
  • 数据发送/接收:每字节后检查 TXE/RXNE 标志,轮询或中断触发。
  • NACK 处理:收到 NACK 后立即发送停止条件,避免总线死锁。
  • 重复起始:在发送 Sr 前设置 START 位,不发送停止条件。
实战建议:在中断驱动中,将帧状态机(SEND_ADDR、SEND_DATA、RECV_DATA、WAIT_STOP)与 I2C 事件标志位绑定,每个中断事件推进状态机一步。轮询驱动则用循环等待 + 超时保护。