2. I2C 物理层详解:总线拓扑、SDA/SCL、上拉电阻与电平标准
搞懂 I2C 通信,第一道坎就是物理层。很多人一上来就啃协议帧格式、读时序、写时序,结果板子调不通,逻辑分析仪抓出来的波形全是乱码。说白了,就是物理层没打好底。
这节我就带你仔细捋一遍 I2C 的物理层。哪些线该怎么接,电阻选多大,3.3V 和 5V 怎么混接。这些都是我早期反复踩过的坑。
2.1 I2C 总线拓扑结构:主从与多主机
I2C 总线就两根线:SDA(数据线)和 SCL(时钟线)。所有设备都挂在这两条线上。结构非常简单,你用逻辑分析仪抓出来,一看就懂。
核心特点: 这是多主从总线。理论上,任何设备都能当主机发时钟。但实际项目中,几乎都是单片机和 SoC 当主机,传感器和存储器从机。
我习惯用下面这张图来记录总线的基本组成,你拿去用。
总线拓扑上有个关键点:所有设备的 SDA 和 SCL 都是漏极开路(Open-Drain)输出。这意味着什么?意味着没有任何设备能主动把总线拉高。只有主机或者从机主动拉低,把总线拉到 GND。总线高电平全靠上拉电阻提供。
这就是 I2C 的“线与”逻辑。任何设备拉低总线,整条线就变成低电平。冲突检测就是靠这个原理。我记得刚开始做 I2C 时,想当然地以为设备输出高电平时总线就是高电平,结果逻辑分析仪抓到的全是高阻态,查了很久才明白问题出在漏极开路上。
2.2 SDA 与 SCL 信号线详解
这两根线看着简单,但细节很多。我按重要程度给你拆开讲。
SCL:时钟线
- 由主机产生。标准模式 100kHz,快速模式 400kHz,高速模式 3.4MHz。
- 时钟同步和仲裁都在 SCL 上做。多主机竞争时,谁先把 SCL 拉低谁就赢得时钟控制权。
SDA:数据线
- 双向数据线。主机发送地址和写数据,从机回复应答和发送读数据。
- 数据传输发生在 SCL 高电平时。SCL 低电平时才能改变 SDA 电平。
- 起始条件:SCL 高电平时,SDA 从高到低跳变。
停止条件:SCL 高电平时,SDA 从低到高跳变。
避坑提醒:曾经我调试一块板子,单片机一直检测不到从机 ACK。花了一整天,最后发现 SDA 线上有个 1μF 的电容没去掉。电容太大,SDA 电平翻转太慢,从机根本识别不了起始条件。
SDA 和 SCL 的走线必须尽量短,负载电容加起来不能超过 400pF(标准模式)。
2.3 上拉电阻计算:很关键
这是 I2C 物理层最容易被忽视的地方。电阻选小了,总线拉低电流过大。电阻选大了,上升沿太慢,协议跑飞。
我习惯用 I2C 规范中的标准来计算。咱们一步步来。
最小上拉电阻 Rp(min)
限制因素是:设备拉低总线时的最大灌电流(Iol)。
- Vcc:供电电压
- Vol(max):输出低电平最大值(一般 0.4V)
- Iol(max):灌电流(标准模式 3mA,快速模式 20mA)
公式很简单:
Rp(min) = (Vcc - Vol(max)) / Iol(max)
例如:Vcc=3.3V,Vol=0.4V,Iol=3mA
Rp(min) = (3.3-0.4) / 0.003 ≈ 967Ω
所以无论如何不能比这个值小。否则设备没能力把总线拉到 0.4V 以下。
最大上拉电阻 Rp(max)
限制因素是:总线电容(Cb)和要求的上升时间(tr)。
- tr:SCL 上升时间(标准模式 1μs,快速模式 300ns)
- Cb:总线总电容(走线 + 设备管脚电容)
公式:
Rp(max) = tr / (0.8473 × Cb)
例如:标准模式 tr=1μs,Cb=200pF
Rp(max) = 1μs / (0.8473 × 200pF) ≈ 5.9kΩ
你实际选电阻时,就选 Rp(min) 和 Rp(max) 之间的标准阻值。我建议选 4.7kΩ 或 10kΩ,这两个值在很多 I2C 设计里都够用。
| 供电电压 (Vcc) | 标准模式 (100kHz) | 快速模式 (400kHz) |
|---|---|---|
| 5.0V | 4.7kΩ ~ 10kΩ | 2.2kΩ ~ 4.7kΩ |
| 3.3V | 3.3kΩ ~ 10kΩ | 1.5kΩ ~ 4.7kΩ |
| 1.8V | 2.2kΩ ~ 10kΩ | 1.0kΩ ~ 4.7kΩ |
实战经验:我用逻辑分析仪测过,总线电容 50pF 的情况下,用 10kΩ 上拉电阻,标准模式完全没问题。但电容到 200pF,10kΩ 就不够快了,上升沿变成了 1.7μs,超过标准模式要求。这时候我换成了 4.7kΩ。
2.4 电平标准:3.3V 与 5V 的混接
现在大部分传感器都是 3.3V,但很多传统的 EEPROM 还跑 5V。混接时你一定要注意电平是否兼容。
标准逻辑电平阈值
- TTL 电平(5V 系统):VIL=0.8V,VIH=2.0V
- CMOS 电平(3.3V 系统):VIL=0.8V,VIH=2.0V(有些 3.3V 器件 VIH 要求更高,达到 0.7×Vcc)
一般来说,3.3V 器件输出的高电平是 3.3V,能被 5V 器件识别为高电平。反过来,5V 器件输出的高电平是 5V,灌进 3.3V 器件可能会烧毁。你可以用两种方式处理:
- 电平转换芯片:如 PCA9306。可靠性最高。
- 外部分压:在 SDA/SCL 线上串联电阻分压,把 5V 降成 3.3V。但不推荐,因为会拉低驱动能力。
千万注意:不能直接把 5V 设备的输出直接接到 3.3V 设备的输入引脚上。我吃过这个亏,一个 5V 的 I2C 温度传感器直接接 3.3V 单片机,结果单片机的 I/O 引脚被击穿,内部 ESD 结构烧毁。