1. I2C 总线概述:从历史到多主多从架构
各位同学,咱们今天聊聊 I2C 总线。说实话,这玩意儿在嵌入式圈子里太常见了。你随便拆开一个电子产品,里面大概率能找到 I2C 的踪迹。我最早接触 I2C 是在做传感器采集板的时候,当时觉得这东西简单,结果一上手就踩了不少坑。嗯,咱们今天就把 I2C 的底裤扒干净。
1.1 I2C 的历史:飞利浦的“小发明”
I2C 全称是 Inter-Integrated Circuit,中文叫“集成电路间总线”。1982 年,飞利浦半导体(现在的 NXP)搞出了这个东西。初衷很简单——他们想减少芯片之间的连线数量。
你想想看,早期的电路板,每个芯片都有自己的地址线、数据线、控制线,密密麻麻的。飞利浦的工程师一拍脑袋:能不能只用两根线就把所有芯片串起来?于是 I2C 诞生了。
关键时间节点:
- 1982 年:飞利浦提出 I2C 总线概念,最初用于电视机的调谐器控制
- 1992 年:发布 I2C 规范 1.0,支持 100 kHz 标准模式
- 1998 年:规范升级到 2.0,增加 400 kHz 快速模式
- 2007 年:NXP 发布 3.0 规范,引入 1 MHz 快速模式+
- 2012 年:推出 5 MHz 超快速模式(UFm)
我记得有一次做项目,客户要求用 I2C 接 12 个传感器。我查了查规范,标准模式理论上能挂 128 个设备,但实际电容限制会让你哭。这个咱们后面细说。
3.2 物理层特性:两根线走天下
I2C 物理层就两根线:SDA(串行数据线)和 SCL(串行时钟线)。所有设备都挂在这两根线上,通过开漏输出实现“线与”逻辑。
说白了,就是任何设备都能把总线拉低,但没人能主动拉高。拉高靠的是上拉电阻。这个设计很巧妙——避免了多设备同时驱动总线时的短路问题。
| 参数 | 标准模式 | 快速模式 | 快速模式+ | 高速模式 |
|---|---|---|---|---|
| 最大时钟频率 | 100 kHz | 400 kHz | 1 MHz | 3.4 MHz |
| 最大总线电容 | 400 pF | 400 pF | 550 pF | 100 pF |
| 最小上拉电阻 | ≈1.6 kΩ | ≈1.6 kΩ | ≈1.2 kΩ | ≈0.8 kΩ |
| 最大上拉电阻 | ≈10 kΩ | ≈4.7 kΩ | ≈2.2 kΩ | ≈1.5 kΩ |
我曾经踩过的坑: 有一次我图省事,用了 10 kΩ 上拉电阻跑 400 kHz。结果示波器一看,SCL 的上升沿慢得像蜗牛爬。后来一算,总线电容 200 pF,RC 常数 2 μs,400 kHz 的周期才 2.5 μs,上升沿就占了 80% 的时间。信号根本没法看。
1.3 协议层基础:起始、停止、应答
I2C 的协议层其实不复杂。核心就几个动作:起始条件、停止条件、数据发送、应答。
咱们先看时序图:
协议流程其实就这几步:
- 起始条件:SCL 高电平时,SDA 从高切换到低。这表示“我要开始通信了”。
- 发送地址:主设备发送 7 位从机地址 + 1 位读写位(0=写,1=读)。
- 等待应答:第 9 个时钟周期,从机拉低 SDA 表示“我收到了”。
- 数据传输:每 8 位数据后跟一个应答位。数据在 SCL 低电平时改变,高电平时采样。
- 停止条件:SCL 高电平时,SDA 从低切换到高。表示“通信结束”。
小技巧: 我习惯在写驱动时,把起始和停止条件封装成独立函数。这样代码可读性高,调试也方便。比如:
void i2c_start(void) {
SDA_HIGH();
SCL_HIGH();
delay_us(5);
SDA_LOW(); // SCL高时SDA下降 → 起始
delay_us(5);
SCL_LOW(); // 准备发数据
}
1.4 多主多从架构:谁说了算?
I2C 支持多主多从架构。什么意思?就是总线上可以挂多个主设备,每个主设备都能主动发起通信。
但问题来了——如果两个主设备同时抢总线怎么办?
I2C 的解决方案是仲裁。说白了,就是谁先拉低总线谁赢。具体机制是这样的:
- 每个主设备在发送数据时,会同时监测 SDA 电平
- 如果自己发送的是高电平,但检测到 SDA 是低电平,说明有其他主设备在拉低总线
- 这个主设备就自动退出,让另一个继续
我刚开始做多主系统时,觉得仲裁很神奇。后来用示波器抓了一次波形才明白——其实就是“线与”逻辑的自然结果。谁先拉低,谁就占住总线。
| 场景 | 主设备 A 发送 | 主设备 B 发送 | SDA 实际电平 | 仲裁结果 |
|---|---|---|---|---|
| 情况 1 | 1(高) | 0(低) | 0(低) | B 获胜,A 退出 |
| 情况 2 | 0(低) | 0(低) | 0(低) | 继续仲裁下一 bit |
| 情况 3 | 1(高) | 1(高) | 1(高) | 继续仲裁下一 bit |
注意: 仲裁只发生在 SDA 上。SCL 是“线与”的——任何主设备都可以拉低 SCL 来延长时钟周期(这叫时钟拉伸)。我遇到过一些从机芯片,处理数据慢时会拉低 SCL 让主设备等一等。如果你的主设备不支持时钟拉伸,通信就会出错。
1.5 知识结构总览
咱们把这一章的核心知识点串起来,画个图:
这张图把 I2C 的核心知识点串起来了。后面咱们会逐个深入——特别是总线电容计算和上拉电阻选型,这是实战中最容易出问题的地方。
本章要点回顾:
- I2C 是飞利浦 1982 年发明的双线串行总线,初衷是减少芯片间连线
- 物理层只有 SDA 和 SCL 两根线,采用开漏输出 + 上拉电阻
- 协议层核心:起始条件、7 位地址、读写位、应答、停止条件
- 多主架构通过 SDA 仲裁解决总线冲突,时钟拉伸是从机的“慢下来”信号
- 总线电容直接影响上拉电阻选型和通信速率——这是咱们课程的核心
好了,第一章就到这里。记住这些基础概念,后面咱们要动手算电容、选电阻、写驱动了。嗯,到时候你会发现,理论懂了,实战才是真正的考验。