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

各位同学,咱们正式开始这门课。今天先聊I2C的物理层。

很多人学I2C,上来就背时序图——SCL高电平时采样SDA,起始条件、停止条件……背得滚瓜烂熟,真到调板子的时候,波形乱跳、设备不应答,一脸懵。为什么?因为没搞懂物理层。

物理层是I2C的根基。你搞懂了开漏输出和上拉电阻,后面所有时序、仲裁、时钟拉伸,一看就通。搞不懂,调三天三夜也未必能找到问题。

1.1 总线拓扑结构

I2C总线就两根线:SCL(时钟线)和SDA(数据线)。所有设备都挂在这两根线上。

拓扑结构很简单——多主多从,共享总线。一个主设备可以带多个从设备,多个主设备也能共存。但同一时刻只能有一个主设备控制总线。

角色 说明 典型例子
主设备(Master) 产生时钟、发起通信、决定何时开始和停止 MCU、SoC、FPGA
从设备(Slave) 监听总线、响应主设备的请求 EEPROM、传感器、ADC/DAC
多主模式 多个主设备通过仲裁决定谁控制总线 双MCU系统、智能电池管理

每个从设备都有一个唯一的7位或10位地址。主设备发地址,匹配的从设备应答,然后开始数据传输。

我在一个项目里遇到过:两个传感器地址冲突,都是0x48。查了半天手册才发现其中一个可以改地址引脚。嗯,选型的时候一定要确认地址可配置。

1.2 开漏输出——I2C的核心

I2C为什么能实现多设备共享总线?关键就在开漏输出。

开漏输出,说白了就是:输出级只有一个N沟道MOSFET,漏极开路。输出低电平时,MOSFET导通,引脚拉到GND。输出高电平时,MOSFET截止,引脚悬空——靠外部上拉电阻拉到高电平。

你想想看,如果I2C用推挽输出会怎样?两个设备同时输出,一个输出高、一个输出低,直接短路,电流大得能烧引脚。开漏输出就不会——谁想拉低就拉低,谁想释放就释放,不会打架。

开漏输出的核心特性:

  • 只能主动拉低,不能主动拉高
  • 高电平靠外部上拉电阻实现
  • 多个设备可以“线与”——只要有一个拉低,总线就是低电平

这个“线与”特性,是I2C仲裁和时钟拉伸的基础。后面章节会详细讲。

1.3 上拉电阻——选不对就出问题

上拉电阻是I2C总线必不可少的。没有它,总线高电平就浮空了,数据根本传不了。

电阻值怎么选?不是随便焊个4.7kΩ就完事。选大了,上升沿太慢,高速通信出错。选小了,功耗大,驱动能力不够。

总线电容 标准模式(100kHz) 快速模式(400kHz) 高速模式(3.4MHz)
~50pF 4.7kΩ ~ 10kΩ 2.2kΩ ~ 4.7kΩ 1kΩ ~ 2.2kΩ
~100pF 2.2kΩ ~ 4.7kΩ 1kΩ ~ 2.2kΩ 不推荐
~200pF 1kΩ ~ 2.2kΩ 不推荐 不推荐

上拉电阻的计算公式:

R_min = (Vcc - Vol_max) / Iol_max
R_max = Tr_max / (0.8473 × Cbus)

其中:

  • Vcc:总线供电电压(常见3.3V或5V)
  • Vol_max:输出低电平最大值(通常0.4V)
  • Iol_max:输出低电平电流(通常3mA ~ 20mA)
  • Tr_max:上升时间最大值(标准模式1000ns,快速模式300ns)
  • Cbus:总线总电容(包括引脚电容、走线电容、过孔电容)

我的经验:一般调试阶段先用4.7kΩ,跑通后再根据实际波形调整。如果上升沿太缓,换小一点的电阻。如果功耗敏感,换大一点的。但别超过10kΩ,否则噪声容易耦合进来。

1.4 总线电容与传输距离

I2C标准规定总线电容不能超过400pF。超过这个值,上升沿会变得很缓,时序就乱了。

总线电容主要来自:

  • 每个设备的引脚电容(典型5pF ~ 10pF)
  • PCB走线电容(约1pF/cm)
  • 过孔、连接器、线缆的寄生电容

我曾经在一个项目里,用I2C连接了8个传感器,线缆长度超过1米。结果通信时好时坏。用示波器一看,上升沿都快成正弦波了。后来加了总线缓冲器(如PCA9517),把总线分段,问题才解决。

注意:I2C不适合长距离传输。板内通信没问题,板间超过30cm就要小心。超过1米,建议用RS-485或CAN。

1.5 知识结构图

下面这张图把I2C物理层的核心知识点串起来了。建议你保存下来,后面调I2C的时候对照着看。

I2C物理层知识结构 I2C物理层 总线拓扑 两根线:SCL + SDA 多主多从,共享总线 7位/10位地址寻址 开漏输出 只能拉低,不能拉高 高电平靠上拉电阻 线与特性:谁都能拉低 上拉电阻 阻值:1kΩ ~ 10kΩ 上升沿与功耗的平衡 受总线电容影响 物理层决定时序、仲裁、时钟拉伸

1.6 常见问题与避坑

最后,分享几个我踩过的坑:

  • 上拉电阻焊反了? 不会,但有人把上拉电阻焊到SCL和SDA之间,相当于短路。我见过一次,波形直接没了。
  • 总线卡死怎么办? 从设备拉低SCL不放,主设备等不到时钟释放。解决办法:主设备发9个时钟脉冲,从设备会释放总线。这叫“时钟恢复”。
  • 电平不匹配? 3.3V的MCU接5V的EEPROM,直接连会烧引脚。用电平转换芯片(如PCA9306)或者开漏加不同电压上拉。
  • 地址冲突? 选型时确认地址引脚可配置。如果已经焊上去了,用I2C多路复用器(如TCA9548)分时访问。

曾经有一次:我调试一块板子,I2C死活不通。示波器看波形,SCL和SDA都有,但就是没应答。查了半天,发现从设备的电源没焊好——供电不稳,设备根本没工作。嗯,先查电源,再查I2C,这个顺序别搞反了。