I2C 协议研究

# I2C 协议研究

> 嵌入式芯片工程师之家 – 基础研究系列

## 1. 概述

I2C(Inter-Integrated Circuit)是由 Philips 公司(现 NXP)于 1982 年开发的一种串行通信总线协议。它最初设计用于连接微控制器和外围设备,现已成为嵌入式系统中最常用的通信协议之一。

### 1.1 主要特点

– **两线制**:仅需 SDA(数据线)和 SCL(时钟线)两根信号线
– **多主多从**:支持多个主设备和多个从设备在同一总线上
– **同步通信**:由主设备提供时钟信号
– **地址寻址**:每个从设备有唯一的地址(7 位或 10 位)
– **开漏输出**:需要外部上拉电阻
– **标准速率**:
– 标准模式(Standard-mode):100 kbps
– 快速模式(Fast-mode):400 kbps
– 快速模式+(Fast-mode Plus):1 Mbps
– 高速模式(High-speed mode):3.4 Mbps

## 2. 物理层

### 2.1 总线结构

“`
VCC
|
┌┴┐
│ │ Rpull-up (典型 4.7kΩ)
└┬┘
├────────── SDA

┌────┴────┐
│ Master │
│ Slave │
└─────────┘
“`

### 2.2 电气特性

| 参数 | 标准模式 | 快速模式 | 快速模式+ |
|——|———-|———-|———–|
| 电源电压 | 2.5V – 5.5V | 2.5V – 5.5V | 1.65V – 3.6V |
| 上拉电阻 | 1kΩ – 10kΩ | 1kΩ – 4.7kΩ | 500Ω – 1kΩ |
| 上升时间 | ≤ 1000ns | ≤ 300ns | ≤ 120ns |
| 下降时间 | ≤ 300ns | ≤ 300ns | ≤ 120ns |

### 2.3 开漏输出原理

I2C 总线采用开漏(Open-Drain)或开集(Open-Collector)输出结构:

– **低电平**:MOSFET 导通,将总线拉低到 GND
– **高电平**:MOSFET 截止,由上拉电阻将总线拉高到 VCC
– **优点**:
– 支持多设备共享总线(线与逻辑)
– 支持不同电压等级的设备(通过上拉到不同电压)
– 简化总线仲裁

## 3. 协议时序

### 3.1 基本信号定义

“`
SDA: ────┐ ┌───────┐ ┌────
│ │ │ │
└───┘ └───┘
↑ ↑ ↑ ↑
S P Data S P
tart top tart top

SCL: ─────┐ ┌─────┐ ┌─────
│ │ │ │
└─┘ └─┘
“`

### 3.2 起始条件(START)

– SCL 为高电平时,SDA 从高电平跳变到低电平
– 标志一次传输的开始
– 只有主设备可以产生起始条件

### 3.3 停止条件(STOP)

– SCL 为高电平时,SDA 从低电平跳变到高电平
– 标志一次传输的结束
– 释放总线

### 3.4 重复起始条件(Repeated START)

– 在不产生 STOP 的情况下再次产生 START
– 用于连续访问同一从设备或切换读写方向
– 保持对总线的控制

### 3.5 数据有效性

“`
┌─────────────┐
SDA: │ 数据位 │
│ 稳定有效 │
└─────────────┘
↑ ↑
SCL 上升 SCL 下降
采样点 变化允许
“`

– 数据在 SCL 高电平期间必须保持稳定
– 数据变化只能在 SCL 低电平期间进行
– 在 SCL 上升沿采样数据

## 4. 数据帧格式

### 4.1 字节格式

“`
MSB LSB
┌───┬───┬───┬───┬───┬───┬───┬───┬───┐
│D7 │D6 │D5 │D4 │D3 │D2 │D1 │D0 │ACK│
└───┴───┴───┴───┴───┴───┴───┴───┴───┘
│←─────── 8 位数据 ───────→│← ACK →│
“`

– 每个字节 8 位,MSB 先发
– 每个字节后跟随 1 位应答(ACK/NACK)

### 4.2 应答机制

| 类型 | 产生者 | SDA 电平 | 含义 |
|——|——–|———-|——|
| ACK | 接收方 | 低电平 | 成功接收 |
| NACK | 接收方 | 高电平 | 未成功接收/结束 |

– 发送方在第 9 个时钟周期释放 SDA
– 接收方拉低 SDA 表示 ACK
– 接收方保持 SDA 高电平表示 NACK

### 4.3 完整传输序列

“`
START → [地址 + R/W] → ACK → [数据] → ACK → … → STOP
“`

## 5. 寻址方式

### 5.1 7 位地址

“`
┌───┬───┬───┬───┬───┬───┬───┬───┐
│A6 │A5 │A4 │A3 │A2 │A1 │A0 │R/W│
└───┴───┴───┴───┴───┴───┴───┴───┘
│←──── 7 位地址 ────→│← 方向 →│
“`

– 地址范围:0x00 – 0x7F(0x00-0x07 和 0x78-0x7F 保留)
– 可用地址:112 个(0x08-0x77)
– R/W 位:0=写,1=读

### 5.2 10 位地址

“`
第一次传输:
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 1 │ 1 │ 1 │ 0 │A9 │A8 │R/W│
└───┴───┴───┴───┴───┴───┴───┴───┘
固定前缀 │← 高 2 位 →│

第二次传输:
┌───┬───┬───┬───┬───┬───┬───┬───┐
│A7 │A6 │A5 │A4 │A3 │A2 │A1 │A0 │
└───┴───┴───┴───┴───┴───┴───┴───┘
│←─────── 低 8 位 ───────→│
“`

– 地址范围:0x000 – 0x3FF
– 需要两次传输完成寻址
– 兼容性较差,使用较少

### 5.3 保留地址

| 地址 | 用途 |
|——|——|
| 0x00 | 通用呼叫地址 |
| 0x01-0x03 | 保留(10 位地址) |
| 0x78-0x7B | 保留(10 位地址) |
| 0x7C-0x7F | 保留 |

## 6. 传输模式

### 6.1 主设备写从设备

“`
START → [地址 + 0] → ACK → [寄存器地址] → ACK → [数据] → ACK → STOP
“`

### 6.2 主设备读从设备(单字节)

“`
START → [地址 + 0] → ACK → [寄存器地址] → ACK →
RESTART → [地址 + 1] → ACK → [数据] → NACK → STOP
“`

### 6.3 主设备读从设备(多字节)

“`
START → [地址 + 0] → ACK → [寄存器地址] → ACK →
RESTART → [地址 + 1] → ACK → [数据 1] → ACK → [数据 2] → ACK → … → [数据 N] → NACK → STOP
“`

### 6.4 组合传输

“`
START → [地址 + 0] → ACK → [命令] → ACK →
RESTART → [地址 + 1] → ACK → [数据] → NACK → STOP
“`

## 7. 时钟延展(Clock Stretching)

从设备可以通过拉低 SCL 来延缓通信:

“`
SCL: ────┐ ┌───────┐ ┌────
│ │ │ │
└───┘ └───┘

从设备拉低
(处理数据中)
“`

– 从设备需要更多时间处理数据时使用
– 主设备必须等待 SCL 释放
– 某些主设备不支持时钟延展

## 8. 总线仲裁

### 8.1 仲裁原理

当多个主设备同时尝试控制总线时:

1. 每个主设备在发送数据时同时监测 SDA
2. 如果发送高电平但检测到低电平,说明有其他主设备在发送
3. 该主设备立即停止发送,释放总线
4. 发送低电平的主设备赢得仲裁

### 8.2 仲裁时序

“`
Master A: 发送 1 → 检测到 0 → 失去仲裁 → 释放总线
Master B: 发送 0 → 检测到 0 → 继续发送 → 赢得仲裁
“`

– 仲裁只发生在地址和数据传输阶段
– 仲裁失败的主设备可以在总线空闲时重试

## 9. 常见问题与调试

### 9.1 硬件问题

| 问题 | 可能原因 | 解决方案 |
|——|———-|———-|
| 无 ACK | 从设备未连接/地址错误 | 检查接线和地址 |
| 通信不稳定 | 上拉电阻过大/过小 | 调整上拉电阻值 |
| 波形畸变 | 总线电容过大 | 减少总线长度/设备数量 |
| 电平不匹配 | 电压等级不一致 | 使用电平转换器 |

### 9.2 软件问题

| 问题 | 可能原因 | 解决方案 |
|——|———-|———-|
| 超时 | 从设备无响应 | 添加超时处理 |
| 数据错误 | 时序不匹配 | 调整 I2C 时钟频率 |
| 死锁 | 总线被占用 | 实现总线恢复机制 |

### 9.3 调试技巧

1. **使用逻辑分析仪**:捕获完整时序
2. **检查上拉电阻**:确保阻值合适
3. **验证地址**:确认从设备地址正确
4. **测量波形**:检查上升/下降时间
5. **简化测试**:先单设备通信,再增加设备

## 10. 代码示例(STM32 HAL)

### 10.1 初始化

“`c
// I2C 初始化配置
I2C_HandleTypeDef hi2c1;

hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00702681; // 根据时钟配置
hi2c1.Init.OwnAddress1 = 0x00;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

HAL_I2C_Init(&hi2c1);
“`

### 10.2 写入寄存器

“`c
uint8_t dev_addr = 0x50; // 设备地址
uint8_t reg_addr = 0x00; // 寄存器地址
uint8_t data = 0xAA; // 写入数据

HAL_I2C_Mem_Write(&hi2c1, dev_addr, reg_addr,
I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
“`

### 10.3 读取寄存器

“`c
uint8_t dev_addr = 0x50;
uint8_t reg_addr = 0x00;
uint8_t data;

HAL_I2C_Mem_Read(&hi2c1, dev_addr, reg_addr,
I2C_MEMADD_SIZE_8BIT, &data, 1, 100);
“`

## 11. 参考资料

– [NXP I2C-Bus Specification and User Manual](https://www.nxp.com/docs/en/user-guide/UM10204.pdf)
– [Texas Instruments I2C Application Report](https://www.ti.com/lit/an/slva704/slva704.pdf)
– [STMicroelectronics I2C Application Note](https://www.st.com/resource/en/application_note/an2644.pdf)

*文档版本:1.0*
*创建日期:2026-04-07*
*作者:狗剩 🌱*

通讯更新

请输入您的电子邮件地址进行订阅

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注