一、I2C 硬件基础:线与特性与电平驱动
理解 I2C 的硬件原理是掌握协议的第一步,其核心是 "线与" 逻辑和开漏输出设计,这决定了 I2C 的多设备通信能力。
1.1 线与(Wire-AND)特性
I2C 总线的核心电气特性是线与逻辑:总线上所有设备的 SDA/SCL 引脚均为开漏输出,总线电平由所有设备的输出共同决定。
| chipA 输出 | chipB 输出 | 实际总线电平 |
|---|---|---|
| 1(高阻态) | 0(拉低) | 0 |
| 0(拉低) | 1(高阻态) | 0 |
| 1(高阻态) | 1(高阻态) | 1(由上拉电阻决定) |
| 0(拉低) | 0(拉低) | 0 |
核心原理:任何一个设备输出低电平,总线就会被拉低;只有所有设备都输出高阻态时,总线才会被上拉电阻拉到高电平。这一特性是 I2C 多设备通信的基础,也是 "仲裁" 和 "应答" 机制的硬件保障。
1.2 开漏输出与推挽输出的区别
I2C 设备的引脚必须配置为开漏输出模式,而常见的 GPIO 默认是推挽输出,两者的核心区别如下:
| 特性 | 开漏输出 | 推挽输出 |
|---|---|---|
| 驱动能力 | 仅能拉低总线,高电平依赖上拉电阻 | 可主动输出高 / 低电平 |
| 线与支持 | 支持,允许多设备并联 | 不支持,多设备并联会导致短路 |
| 应用场景 | I2C、SMBus 等多设备总线 | 单设备 GPIO 输出、LED 驱动等 |
在 I2C 硬件设计中,SDA 和 SCL 线上必须外接4.7k~10kΩ 的上拉电阻,以保证总线在空闲时处于高电平状态。
二、I2C 时序协议:信号定义与通信流程
I2C 的通信完全由时序信号控制,掌握起始 / 停止信号、数据传输、应答机制是解析协议的核心。
2.1 核心时序信号定义
- START(起始信号) :当 SCL 为高电平时,SDA 产生一个下降沿,表示通信开始。
- STOP(停止信号) :当 SCL 为高电平时,SDA 产生一个上升沿,表示通信结束。
- 数据传输:在 SCL 为低电平时,发送方可以改变 SDA 电平;在 SCL 为高电平时,SDA 电平必须保持稳定,接收方此时采样数据。
- 应答(ACK/NACK) :接收方在接收到 1 字节数据后,在第 9 个时钟周期内拉低 SDA 表示ACK(应答) ,保持高电平表示NACK(非应答)。
2.2 数据传输规则
- 字节序 :数据传输遵循MSB 优先原则,即每个字节的最高位最先发送。
- 时钟同步:SCL 由主机产生,但从设备可以通过拉低 SCL 实现 "时钟拉伸",以减慢通信速率,适配自身处理速度。
- 仲裁机制:当多个主机同时发送数据时,通过线与逻辑自动仲裁,首先发送低电平的主机获得总线控制权,避免数据冲突。
2.3 完整通信帧结构
一次典型的 I2C 通信分为 "主机写" 和 "主机读" 两种场景,帧结构如下:
(1)主机写数据到从设备
plaintext
START → 从机地址(7位)+ 写标志(0)→ ACK → 寄存器地址 → ACK → 数据字节 → ACK → ... → STOP
(2)主机从设备读数据
plaintext
START → 从机地址(7位)+ 写标志(0)→ ACK → 寄存器地址 → ACK → RESTART → 从机地址(7位)+ 读标志(1)→ ACK → 数据字节 → NACK → STOP
注:读操作需要先通过 "写" 操作指定寄存器地址,再发送重复起始信号(RESTART)切换为读模式。
三、I2C 驱动实现:从流程图到代码逻辑
I2C 驱动的开发核心是严格遵循时序协议,结合硬件寄存器配置实现完整的通信流程。下面结合你提供的流程图,解析 "主机写" 和 "主机读" 的驱动逻辑。
3.1 主机写驱动流程
- 初始化阶段:清除 I2C 状态寄存器的中断标志,配置为主机发送模式。
- 发送起始信号 :置位
I2CR_MTX位产生 START 信号。 - 发送从机地址 :将从机地址 + 写标志写入数据寄存器
I2DR,等待从机应答。 - 判断应答:若收到 NACK 则通信失败,直接发送 STOP 信号;若收到 ACK 则继续。
- 发送寄存器地址:写入目标寄存器地址,等待从机应答。
- 发送数据:依次发送数据字节,每发送 1 字节等待一次 ACK。
- 发送停止信号:所有数据发送完成后,产生 STOP 信号,释放总线。
3.2 主机读驱动流程
- 初始化与起始信号:与写流程一致,先发送起始信号和从机地址 + 写标志,指定寄存器地址。
- 重复起始信号:发送 RESTART 信号,切换为读模式。
- 发送从机地址 + 读标志:等待从机应答。
- 接收数据 :
- 若接收长度 > 1,主机回复 ACK,继续接收下一字节;
- 若接收最后 1 字节,主机回复 NACK,通知从机停止发送。
- 发送停止信号:接收完成后产生 STOP 信号。
3.3 关键寄存器说明
I2CR(控制寄存器):配置主机 / 从机模式、发送 / 接收模式,控制 START/STOP 信号。I2SR(状态寄存器):指示中断标志、应答状态(RXAK位表示是否收到 ACK)、仲裁结果。I2DR(数据寄存器):用于发送 / 接收数据字节。
四、开发避坑指南
- 上拉电阻选择:上拉电阻的阻值直接影响通信速率,4.7kΩ 适合 100kHz 标准模式,10kΩ 适合低速模式,阻值过大会导致信号上升沿过慢,影响稳定性。
- 时钟拉伸处理:从设备可能拉低 SCL 实现时钟拉伸,驱动中需检测 SCL 电平,等待从设备释放时钟后再继续传输。
- 应答检测:每发送 1 字节后必须检测从机的 ACK 信号,若未收到 ACK 需及时终止通信并处理错误。
- 总线冲突处理 :多主机场景下需处理仲裁失败的情况,通常通过检测
I2SR_AL位(仲裁丢失标志)并重新发起通信。
五、总结
I2C 协议的核心是 "简洁高效":仅用两根线就实现了多设备组网,通过线与逻辑和应答机制保证了通信的可靠性。开发 I2C 驱动的关键在于:
- 理解硬件特性:开漏输出 + 上拉电阻的设计是 I2C 的物理基础。
- 严格遵循时序:起始 / 停止信号、数据采样、应答机制的时序必须精准。
- 健壮的错误处理:应答失败、仲裁丢失、时钟拉伸等异常场景需妥善处理。