1. 课程导入

各位同学,今天咱们开始聊I2C。说实话,我最早接触I2C是在做一款车载传感器驱动的时候,那时候刚入行,对着示波器看SDA和SCL的波形,愣是盯了一下午才搞明白起始条件和停止条件长什么样。嗯,从那以后我就养成了一个习惯——不管多简单的协议,先把物理层吃透。

1.1 I2C总线起源:飞利浦的小心思

I2C全称是Inter-Integrated Circuit,也就是“集成电路间总线”。80年代初,飞利浦(现在的NXP)搞出来的。当时他们想解决一个很实际的问题:板子上芯片越来越多,每个芯片都拉一堆并行地址线和数据线,PCB都快成蜘蛛网了。

于是他们想:能不能就用两根线,把所有外设串起来?

这就是I2C的核心理念——两线制。一根时钟线SCL,一根数据线SDA。所有设备挂在这两根线上,通过地址区分谁跟谁说话。

关键点:I2C是同步、半双工、多主从的串行通信总线。同步靠SCL,半双工意味着同一时刻只能一个方向传数据,多主从意思是总线上可以有多个主机(Master)和多个从机(Slave)。

1.2 物理层特性:SDA和SCL到底怎么工作的?

先看一张I2C总线的物理连接图,我习惯把它画成下面这样:

I2C总线物理连接结构图 I2C总线物理连接结构 Rp Rp VDD VDD SDA SCL 主机 (Master) 从机1 (Slave) 从机2 (Slave) 说明: • SDA和SCL都是开漏(Open-Drain)输出,必须外接上拉电阻到VDD。 • 总线空闲时,SDA和SCL都被上拉电阻拉到高电平。 • 任何设备都可以拉低SDA或SCL,但不能主动拉高——这就是“线与”特性。 • 上拉电阻Rp的取值直接影响通信速率和功耗,后面会细讲。

这张图我建议你多看两眼。I2C总线上所有设备的SDA引脚连在一起,SCL引脚也连在一起。每个设备都有一个唯一的7位或10位地址。主机通过地址来选择跟谁通信。

1.3 电气特性:开漏输出与线与逻辑

I2C最特别的地方在于它的输出结构——开漏(Open-Drain)。说白了,每个设备的SDA和SCL引脚内部就是一个MOS管的漏极,它只能把线拉低到GND,不能主动拉高。

那高电平谁来提供?上拉电阻。

这就引出了一个重要概念——线与(Wired-AND)。任何设备只要拉低总线,总线就是低电平。只有所有设备都不拉低,总线才是高电平。你想想看,这天然就支持了多主机仲裁——谁先拉低SDA,谁就赢得了总线控制权。

我的经验:调试I2C时,如果发现SCL一直低或者SDA一直低,别急着怀疑代码。先拿万用表量一下上拉电阻两端电压。我曾经遇到过一颗电阻虚焊,SDA波形永远只有半幅,折腾了两天才找到原因。

1.4 上拉电阻选择:算对了省心,算错了头疼

上拉电阻的取值不是随便选的。选大了,上升沿太慢,高速通信时波形畸变;选小了,功耗大,而且设备可能拉不动。我一般按下面这个思路来算:

参数 符号 典型值 说明
电源电压 VDD 1.8V / 3.3V / 5V 取决于系统供电
输出低电平电压 VOL 0.4V (max) 设备拉低时的残留电压
输出低电平电流 IOL 3mA (标准模式) 设备能承受的灌电流
总线电容 Cb 10pF ~ 400pF 取决于线长和设备数量
上升时间 tr 1000ns (标准模式) 由RC时间常数决定

上拉电阻的最小值由灌电流限制决定:

Rp(min) = (VDD - VOL(max)) / IOL(max)
        = (3.3V - 0.4V) / 3mA
        ≈ 967Ω

上拉电阻的最大值由上升时间要求决定:

Rp(max) = tr / (0.8473 × Cb)
        = 1000ns / (0.8473 × 200pF)
        ≈ 5.9kΩ

避坑指南:我曾经在一个项目里用了10kΩ的上拉电阻,标准模式100kHz跑得好好的。后来客户要求升级到400kHz快速模式,结果波形上升沿明显变缓,通信偶尔出错。一算,10kΩ配200pF总线电容,上升时间接近1.7μs,远超快速模式300ns的要求。换成4.7kΩ后问题解决。

实际工程中,我常用的经验值:

  • 标准模式(100kHz):4.7kΩ ~ 10kΩ
  • 快速模式(400kHz):1.5kΩ ~ 4.7kΩ
  • 高速模式(3.4MHz):1kΩ ~ 2.2kΩ

当然,具体取值还要看总线电容。如果板子上挂了七八个I2C设备,总线电容轻松超过200pF,这时候就得选小一点的上拉电阻。

1.5 电平兼容性:不同电压域怎么玩?

现在很多系统是混合电压的——主控是3.3V,传感器可能是1.8V或者5V。I2C能不能直接连?

答案是不一定。I2C规范要求所有设备的VOL和VIH/VIL要匹配。如果电压差太大,直接连可能烧坏IO口,或者逻辑电平判不对。

我常用的几种方案:

  1. 使用I2C电平转换芯片:比如PCA9306、TXS0102,最省心。
  2. 分立MOSFET方案:用N沟道MOSFET搭双向电平转换电路,成本低但要注意方向控制。
  3. 上拉电阻接不同电压:如果两边IO口都支持5V耐受,可以只把上拉电阻接到较高电压侧。

记住:I2C总线上的所有设备,其SDA和SCL引脚必须能承受总线上的最高电压。如果主控是3.3V但传感器是5V,主控IO口必须标注“5V-tolerant”,否则老老实实加电平转换。

1.6 本章小结

I2C总线的物理层,说白了就是两根开漏线加上拉电阻。理解了这个基础,后面讲时序、讲仲裁、讲速率配置才不会懵。我个人觉得,物理层是I2C最容易被忽视但最容易出问题的地方——上拉电阻选错、电平不匹配、总线电容过大,这些坑我几乎都踩过一遍。