一、I2C协议基础:物理层特性、总线拓扑结构、开漏输出与上拉电阻

各位同学,咱们今天正式开始啃I2C协议。说实话,我做了十几年嵌入式,I2C和SPI这两个协议几乎天天打交道。很多新手一上来就调代码,结果波形乱七八糟,设备死活不应答——问题往往就出在物理层。

这一节,咱们先把I2C的“地基”打牢。物理层搞明白了,后面写驱动、调时序,你心里才有底。

1.1 物理层特性:两根线搞定一切

I2C总线只用两根线:SCL(串行时钟线)和SDA(串行数据线)。所有设备都挂在这两根线上,通过地址区分彼此。

信号线 功能 方向
SCL 时钟信号,由主机产生 主机→从机
SDA 数据信号,双向传输 双向

这里有个关键点:I2C是同步串行通信。时钟线SCL决定了什么时候采样数据,数据线SDA在时钟的配合下一位一位地传。我刚开始学的时候,总觉得它和SPI差不多,后来才发现——差远了。

核心指标速查

  • 标准模式:100 kbit/s
  • 快速模式:400 kbit/s
  • 高速模式:3.4 Mbit/s
  • 总线电容限制:≤400 pF
  • 最大从机数量:理论128个(7位地址)

1.2 总线拓扑结构:一主多从,多主可选

I2C的拓扑结构很简单——总线型。所有设备的SCL和SDA分别连在一起,共用两根线。

最常见的模式是单主机多从机。一个MCU做主设备,挂几个传感器、EEPROM、显示屏之类的从设备。每个从设备有唯一地址,主机通过地址选择跟谁说话。

还有一种多主机模式,多个MCU可以轮流当主机。这个在实际项目中用得少,但一旦用上,就得处理总线仲裁——说白了就是两个主机同时抢总线怎么办。我有个项目就踩过这个坑,后面会细讲。

我的经验: 绝大多数嵌入式项目用单主机模式就够了。多主机模式会增加复杂度,除非必要,不建议新手尝试。

I2C 总线拓扑结构 Rp Rp VDD (3.3V / 5V) SDA SCL 主机 (MCU) 从机1 (传感器) 从机2 (EEPROM) 从机3 (显示屏) 上拉电阻 Rp 典型值:4.7kΩ 高速时:1.5kΩ~2.2kΩ

1.3 开漏输出:为什么I2C要这么设计?

I2C的SCL和SDA引脚都是开漏输出。什么叫开漏?说白了,就是引脚只能拉低到GND,不能主动输出高电平。

你想想看,如果多个设备都能主动输出高电平,一个设备输出高,另一个输出低——那就短路了。开漏输出配合上拉电阻,解决了这个问题:

  • 拉低:设备内部MOS管导通,引脚接地
  • 释放:设备内部MOS管截止,引脚由外部上拉电阻拉到高电平

这样一来,任何设备都可以拉低总线,但谁都不能强行拉高。这就是I2C能实现多设备共用总线和总线仲裁的物理基础。

注意: 开漏输出意味着I2C引脚不能配置为推挽输出!我曾经见过有人把I2C引脚配成推挽模式,结果总线一直拉高,设备根本没法通信。排查了半天才发现是GPIO配置错了。

1.4 上拉电阻:选大了还是选小了?

上拉电阻是I2C总线必不可少的元件。它负责在设备释放总线时,把电平拉回高电平。

电阻值怎么选?这里有个权衡:

电阻值 优点 缺点 适用场景
偏小(1kΩ~2.2kΩ) 上升沿陡峭,适合高速 功耗大,灌电流大 高速模式、总线电容大
适中(4.7kΩ) 功耗与速度平衡 — 标准/快速模式,通用
偏大(10kΩ) 功耗低 上升沿平缓,限制速率 低速、短距离、低功耗

我个人习惯,100kHz标准模式用4.7kΩ,400kHz快速模式用2.2kΩ。如果总线上挂的设备多,总线电容大,电阻就得选小一点。

避坑指南: 我曾经在一个项目里,总线上挂了6个设备,线长30cm,用了10kΩ上拉电阻。结果400kHz死活跑不起来,波形上升沿像山坡一样平缓。换成2.2kΩ后,问题立刻解决。

1.5 总线电容与最大从机数量

I2C标准规定总线电容不能超过400pF。每个设备的引脚、PCB走线、连接器都会贡献电容。设备越多、线越长,电容越大。

怎么估算?一般来说:

  • 每个设备引脚电容:约5~10pF
  • PCB走线电容:约1pF/cm
  • 连接器/排线:约10~20pF

举个例子,挂10个设备,走线20cm,总电容大概在100~150pF左右,用4.7kΩ上拉跑100kHz完全没问题。但如果挂20个设备,线长50cm,电容可能就奔着300pF去了,这时候得上2.2kΩ甚至更小的电阻。

经验公式: 上拉电阻最小值 = VDD / I_OL_max,其中I_OL_max是器件允许的最大灌电流(通常3mA~20mA)。上拉电阻最大值 = t_r_max / (0.8473 × C_bus),其中t_r_max是允许的最大上升时间(标准模式1000ns,快速模式300ns)。

1.6 电平兼容:3.3V和5V混接怎么办?

实际项目中,3.3V的MCU和5V的传感器混接很常见。I2C的开漏特性让电平转换变得简单——只要上拉电阻接到3.3V,所有设备都能安全通信。

为什么?因为开漏输出只拉低到GND,不会主动输出高电平。高电平由上拉电阻决定。所以:

  • 上拉电阻接3.3V → 总线高电平为3.3V
  • 5V设备必须能识别3.3V为高电平(通常TTL电平阈值1.5V左右,没问题)
  • 3.3V设备不会被5V损坏

但要注意,有些5V设备的输入高电平阈值可能高于3.3V,这时候就需要加电平转换芯片了。我遇到过一款老旧的5V传感器,VIH_min是3.8V,3.3V死活认不到,最后加了个TXB0104才搞定。

重要: 如果总线上有5V设备,上拉电阻绝对不能接到5V!否则3.3V设备会被5V电平烧坏。上拉电阻统一接到最低工作电压的那一侧。

1.7 小结:物理层决定了你能走多远

I2C的物理层看似简单,但细节决定成败。上拉电阻选不对,总线电容超了,电平不匹配——任何一个问题都会让通信失败。我见过太多人拿着逻辑分析仪抓波形,发现上升沿慢得像蜗牛,或者设备应答信号出不来,最后发现都是物理层的问题。

记住这几条:

  • 开漏输出 + 上拉电阻 = 多设备共用总线的基石
  • 上拉电阻选4.7kΩ起步,高速或大电容时减小
  • 总线电容控制在400pF以内
  • 电平不匹配时,上拉电阻接到低电压侧