通讯协议-IIC
I²C(Inter-Integrated Circuit,也常写作 IIC)是一种两线、同步、支持多控制器和多目标设备的串行总线。它常用于 MCU 与传感器、EEPROM、电源管理芯片、时钟芯片等低速外设之间的板级通信。
信号线与电气特性
| 信号 | 作用 |
|---|---|
| SCL | 串行时钟线 |
| SDA | 双向串行数据线 |
| GND | 通信双方的参考地 |
SCL 和 SDA 通常采用开漏/开集电极结构。设备只能主动拉低总线,高电平由上拉电阻产生。这种结构允许多个设备共享总线,并支持应答、仲裁和时钟延展。
VDD ── 上拉电阻 ── SCL ── 控制器与各目标设备
VDD ── 上拉电阻 ── SDA ── 控制器与各目标设备
GND ─────────────── GND ── 所有设备共地
上拉电阻需要结合电源电压、总线电容、目标速率和器件灌电流能力选择。电阻过大时上升沿过慢,过小时低电平电流过大。
基本时序
总线空闲时,SCL 和 SDA 均为高电平。
| 条件 | 定义 |
|---|---|
| START(起始) | SCL 为高时,SDA 从高变低 |
| STOP(停止) | SCL 为高时,SDA 从低变高 |
| 数据有效 | SCL 为高期间,SDA 保持稳定 |
| 数据改变 | 通常在 SCL 为低期间改变 SDA |
| Repeated START | 不先发送 STOP,直接再次发送 START |
每个数据字节通常先传输最高有效位(MSB),随后是第 9 个时钟周期的 ACK/NACK。
地址与读写位
常见 I²C 使用 7 位设备地址。线上发送的第一个字节由 7 位地址和 1 位读写方向位组成:
bit7 bit1 bit0
7 位设备地址 R/W
| R/W 位 | 方向 |
|---|---|
| 0 | 控制器写入目标设备 |
| 1 | 控制器读取目标设备 |
器件手册或旧代码有时会把“7 位地址左移一位并附加 R/W 位”写成两个 8 位地址。例如,7 位地址 0x50 的写地址字节是 0xA0,读地址字节是 0xA1。配置 MCU 驱动前,应确认 API 接收的是 7 位地址还是已经移位的地址字节。
I²C 也定义了 10 位地址格式,但常见外设大多使用 7 位地址。
ACK 与 NACK
发送方发送 8 位数据后释放 SDA,接收方在第 9 个时钟周期回应:
| 应答 | SDA 状态 | 含义 |
|---|---|---|
| ACK | 拉低 | 已接收该字节,可以继续 |
| NACK | 保持高 | 未接收、无法继续,或读取已结束 |
控制器读取多个字节时,通常对中间字节发送 ACK,对最后一个字节发送 NACK,然后发送 STOP。
常见传输流程
写寄存器
START → 地址+W → ACK → 寄存器地址 → ACK → 数据 → ACK → STOP
读寄存器
许多寄存器型设备先通过写操作选择寄存器,再使用重复起始切换为读取:
START → 地址+W → ACK → 寄存器地址 → ACK
Repeated START → 地址+R → ACK → 数据 → NACK → STOP
具体设备是否支持地址自增、寄存器地址长度和连续读写,必须以器件手册为准。
常见速率
| 模式 | 标称最高速率 | 说明 |
|---|---|---|
| Standard-mode | 100 kbit/s | 常用基础模式 |
| Fast-mode | 400 kbit/s | 常见高速模式 |
| Fast-mode Plus | 1 Mbit/s | 对上拉、总线电容与器件能力要求更高 |
| High-speed mode | 3.4 Mbit/s | 需要兼容设备和对应时序 |
实际可用速率受到总线电容、走线、上拉电阻、器件能力和电平转换器影响。
时钟延展与仲裁
目标设备在需要更多处理时间时,可将 SCL 保持为低电平,让控制器等待,这称为时钟延展。控制器和中间电平转换器必须支持该行为。
多控制器同时发起传输时,通过 SDA 仲裁决定谁继续占用总线。控制器发送高电平却读到低电平时,应认定仲裁丢失并停止发送。单控制器系统通常不会用到仲裁,但驱动仍可能提供对应状态标志。
优点与限制
| 优点 | 限制 |
|---|---|
| 仅需两根信号线,可连接多个设备 | 上拉结构限制速度和总线电容 |
| 原生地址与逐字节应答 | 无原生 CRC,错误检测能力有限 |
| 支持多控制器、仲裁与时钟延展 | 地址冲突需要改地址、复位控制或总线复用器 |
| 器件和 MCU 支持广泛 | 不适合长距离和强干扰环境 |
常见问题与排查
| 现象 | 常见原因 | 排查方法 |
|---|---|---|
| SCL/SDA 始终为低 | 器件未释放总线、短路、掉电器件反向供电 | 逐个断开设备,检查电源和引脚状态 |
| 地址无 ACK | 地址格式错误、设备未供电、复位未释放 | 扫描 7 位地址并核对器件地址脚 |
| 低速正常,高速失败 | 上升沿过慢、总线电容大、上拉不合适 | 示波器测量上升沿,调整上拉或降低速率 |
| 读取数据错位 | 寄存器地址长度、重复起始或字节序错误 | 对照手册检查完整事务 |
| 偶发总线锁死 | 传输中复位,目标设备等待剩余时钟 | 实现总线恢复并复位 I²C 外设 |
| 多设备无法共存 | 设备地址冲突 | 修改地址脚,分时复位或增加总线复用器 |
总线恢复
若控制器复位时目标设备正处于发送过程,目标设备可能持续拉低 SDA。常见恢复思路是:
- 暂时将 SCL/SDA 配置为开漏 GPIO。
- 在 SDA 被拉低时,向 SCL 输出若干时钟脉冲,让目标设备完成当前字节。
- 产生 STOP 条件。
- 重新初始化 I²C 外设。
所需脉冲数量和恢复行为应结合目标器件手册验证;并非所有器件都支持同样的恢复方式。
调试步骤
- 确认电压等级、公共地和上拉电阻存在。
- 空闲时测量 SCL 与 SDA,二者应为高电平。
- 用逻辑分析仪确认 START、地址、R/W 位和 ACK/NACK。
- 明确驱动 API 使用 7 位地址还是地址字节。
- 对照器件手册检查寄存器地址长度、重复起始和读写顺序。
- 高速或不稳定时,用示波器检查上升沿、低电平和振铃。
适用场景
I²C 适合板内多个低速外设共享总线。对高速连续数据可考虑 SPI;对长距离、强干扰或多节点可靠通信可考虑 CAN、RS-485 等接口。