I2C 物理层:SCL、SDA、上拉电阻

咱们搞 I2C,首先得把这物理层吃透。说白了就是两根线:SCL 和 SDA。再加上一个不能少的上拉电阻。

别小看这三样东西。我见过太多工程师,程序写得很漂亮,最后栽在这最简单的硬件上。来,咱们从头捋一遍。

SCL 和 SDA:两根线的故事

SCL 是时钟线,由主机控制。SDA 是数据线,双向的。

有意思的地方在于,这两根线都是开漏输出。什么叫开漏?就是输出只能拉低,不能主动拉高。想发高电平?靠外部电阻帮你拉上去。

小技巧:用示波器看 I2C 波形时,先看高电平是否稳定。如果上拉电阻不对,你会发现波形上升沿特别缓,像个斜坡而不是方波。

我刚开始做 I2C 时,总想把 SCL 和 SDA 当成普通 GPIO,直接推挽输出。结果呢?总线冲突,通信乱得一塌糊涂。嗯,后来才明白,开漏结构是为了避免多个设备同时驱动线路。谁想拉低就拉低,想高?大家一起放手,让电阻来干。

上拉电阻:为什么必须要有?

没有上拉电阻,你的 I2C 总线就是个哑巴。开漏输出默认是高阻态,不接电阻,线路电压就悬空了,读到的都是随机值。

电阻的取值很关键。太小了,驱动电流大,费电。太大了,上升沿变慢,跑不出高速。你想想看,100kHz 和 400kHz 模式下,对电阻的要求是不一样的。

总线模式 推荐上拉电阻范围 典型值
标准模式(100kHz) 4.7kΩ ~ 10kΩ 4.7kΩ
快速模式(400kHz) 2.2kΩ ~ 4.7kΩ 3.3kΩ
高速模式(3.4MHz) 1kΩ ~ 2.2kΩ 1.5kΩ

我个人习惯先看 VDD,再选电阻。5V 系统用 4.7kΩ 起步,3.3V 系统用 2.2kΩ 或 3.3kΩ。如果有多个设备,电阻可以适当减小。

避坑指南:我曾经在一条总线上接了 16 个从机,用的还是 10kΩ 上拉。结果总线电容太大,上升沿拖到 2μs 都不够,通信时好时坏。后来换成 2.2kΩ,问题立刻解决。

上拉电阻怎么算?给个公式

工程设计不能光靠感觉。两个边界你得心里有数:

  1. 最小值:保证输出低电平时,电流不超标。Rmin = (VDD - VOL) / IOL。VOL 一般是 0.4V,IOL 看器件手册,通常 3mA 左右。
  2. 最大值:保证上升沿时间满足时序要求。Rmax = trise / (0.8473 × Cbus)。Cbus 包括所有设备的引脚电容和走线电容。

举个例子。3.3V 系统,总电容 100pF,要求上升沿 300ns:

Rmin = (3.3 - 0.4) / 0.003 ≈ 966Ω
Rmax = 300e-9 / (0.8473 × 100e-12) ≈ 3540Ω

所以阻值在 1kΩ 到 3.5kΩ 之间。取中值 2.2kΩ 或者 3.3kΩ 都行。

总线电容:你看不见的敌人

I2C 的设计其实很脆弱。每条线的最大电容都有上限。标准模式 400pF,快速模式 400pF,高速模式 100pF。超过这个数,波形就完蛋了。

电容从哪里来?

  • 每个器件的引脚电容,通常在 5~10pF
  • PCB 走线的寄生电容,大约 1pF/cm
  • 过孔、接插件、线缆,每项都能加上几 pF

我建议你算个总数。比如接了 10 个设备,每个 10pF,就是 100pF。走线 30cm,再加 30pF。嗯,这已经 130pF 了,离 400pF 还有余量,但如果你用长线缆,分分钟超限。

经验之谈:总线上设备超过 8 个,或者通信距离超过 20cm,我都会加一个 I2C 缓冲器或中继器。别嫌麻烦,等通信出问题了再改,那才真叫麻烦。

硬件布局的几条铁律

你可能觉得布局是 PCB 工程师的事。错了,做 I2C 的都得懂。我有几条死规矩:

  1. 上拉电阻要靠近主机放,不要放在从机那边。
  2. SCL 和 SDA 两条线要尽量等长,不要绕大圈。
  3. 避免在总线中间分支,最好用菊花链拓扑。
  4. 电源旁路电容要靠近每个 I2C 器件,减少电源噪声耦合到总线上。

有一次项目赶进度,布局工程师把上拉电阻放在了总线的末端,离主机 15cm 远。结果 400kHz 跑不起来,非降速到 100kHz 才行。后面改了一版板子才解决。教训啊。

I2C 物理层结构图 VDD Rp SCL Rp SDA SCL SDA 主机 从机 1 从机 2 总线电容 Cbus ≤ 400pF 上拉电阻 = 关键参数

总结一下要点

  • SCL/SDA 是开漏输出,必须配上拉电阻,这是 I2C 的核心机制。
  • 上拉电阻取值需要平衡电流和上升时间,4.7kΩ 是通用起点。
  • 总线电容是隐形的瓶颈,超过 400pF 必须处理。
  • 硬件布局也决定了通信稳定性。上拉电阻靠近主机,走线尽量短。

把这些基础打扎实了,后面讲地址冲突检测时,你才能自信地说「我硬件没问题」。遇到 I2C 通信异常,第一步永远是检查物理层。波形对不对?上拉阻值对不对?总线电容有没有超标?别跳步骤,先解决物理层的问题,再往下查。