4. 从设备实现时钟拉伸的硬件方法:开漏输出与 SCL 拉伸电路

时钟拉伸,说白了就是从设备把 SCL 拉低,让主设备等着。很多刚入行的朋友以为这是软件能搞定的。其实硬件才是根本。硬件不靠谱,软件怎么写都白搭。我在项目中见过太多直接靠 GPIO 模拟开漏输出结果导致信号毛刺吞掉时序的例子了。

这一节我们就掰开揉碎地讲清楚:从设备到底怎么在硬件上把 SCL 拉低,再安全地释放。

4.1 开漏输出——时钟拉伸的基石

I2C 总线物理层就是一根 SDA、一根 SCL,都接上拉电阻到 VCC。所有设备都只能拉低总线,不能主动拉高。这就是开漏(Open-Drain)输出。

  • 输出低电平:NMOS 导通,引脚内部接地,SCL 被拉低。
  • 释放总线:NMOS 关断,引脚高阻态,由上拉电阻把 SCL 拉到高电平。

“开漏”听起来玄乎,其实就是只能向下拉,不能往上推。我早期画板子时,有个新手把 SCL 接成了推挽输出,上电后直接和主设备对拉,总线锁死。嗯,教训很深刻。

4.2 SCL 拉伸电路的实际结构

从设备想要完成时钟拉伸,内部电路大概长这样(下面我画了张图帮你理解):

核心要点:拉伸的本质是NMOS开关延时关断。主设备释放SCL后,从设备继续维持低电平,直到自己准备好。

这中间任何抖毛刺、过冲、振铃都会导致主设备误判SCL为高,从而提前发起下一个操作。

SCL时钟拉伸硬件实现逻辑 主设备(Master) 内部开漏输出 SCL输出控制 RP 从设备(Slave) 内部开漏NMOS 可延时关断 拉伸过程 ① 从设备在ACK位或数据位拉低SCL ② 主设备检测到SCL低,停止时钟 ③ 从设备准备好后释放SCL(NMOS关断) ④ 上拉电阻将SCL拉高,主设备继续 关键硬件参数 • NMOS导通电阻(RDS(on))< 100Ω • 关断延迟时间 toff 可控 • SCL上拉电阻 1kΩ ~ 10kΩ • 总线电容 Cb 影响上升沿时间 硬件设计三要素 常见陷阱 ① 上拉电阻值适当 ① 输出延迟过大 ② NMOS关断速度快 ② 总线电容过高

4.3 开漏输出的具体电路实现

常见的实现方式有两种:分立 NMOS 方案和集成 I/O 单元方案。

方案 优点 缺点 典型应用
分立 NMOS + 外部上拉 成本低,可调整驱动能力 PCB 面积大,寄生电容难控 小批量、原型验证
MCU/FPGA内部开漏 I/O 集成度高,延迟可控 驱动能力有限(一般 <20mA) 量产产品、嵌入式系统
专用 I2C 缓冲器/隔离器 信号完整性好,热插拔安全 成本高,占用板空间 通信距离长、高可靠性场景

我的建议:如果你用 MCU 做从设备,先确认 I/O 是否支持开漏模式。有些便宜 MCU 只能推挽输出,这时候就必须加一个外部 NMOS 来控制 SCL。我在一次智能传感器项目里就吃了这个亏,后来不得不飞线加 2N7002。

4.4 关键硬件参数与设计原则

  1. NMOS 导通电阻 RDS(on) 尽量小,保证拉低时 SCL 电压低于 0.4V(VOL 标准)。
  2. 关断延迟 不能太长,否则主设备认为 SCL 一直被拉低而超时。我记得有一次 I2C 总线死锁,用示波器一看,从设备的 NMOS 关断要 2µs,而主设备超时只有 1.5µs。
  3. 上拉电阻 的选择:阻值太小,拉低电流过大;阻值太大,上升沿太慢,限制了时钟频率。

警惕毛刺:当场效应管关断时,沟道电荷通过体二极管泄放,可能在 SCL 上产生负尖峰。这个尖峰如果超过 -0.5V,会触发主设备的 ESD 保护钳位,导致假时钟。我建议在 SCL 与 GND 之间加一个小电容(5~20pF)来吸收尖峰。

4.5 从设备释放 SCL 的时刻控制

释放时机由从设备内部逻辑决定。常见做法是:

  • 在接收完最后一个数据位后,内部计数器清零,开始处理数据。
  • 处理完成前,SCL 保持低电平。
  • 处理完成后,将 SCL 输出寄存器写 1(实际是关断 NMOS)。
// 伪代码示意:从设备触发时钟拉伸
void i2c_slave_clock_stretch(void) {
    // 1. 拉低 SCL
    SCL_PORT &= ~(1 << SCL_PIN);  // 输出0(NMOS导通)
    SCL_DDR  |= (1 << SCL_PIN);   // 使能输出

    // 2. 处理数据(此处延时由内部状态机控制)
    process_data();

    // 3. 释放 SCL
    SCL_DDR  &= ~(1 << SCL_PIN);  // 切换到输入(高阻)
    // 或者使用开漏模式直接写1(部分MCU支持)
}

注意:写入 1 到开漏 I/O 寄存器时,有的 MCU 会自动切换到高阻态,但部分型号需要手动切换方向。千万要看数据手册!

4.6 硬件设计检查清单

检查项 要求 检查方法
开漏模式是否使能 I/O 必须配置为开漏输出 读寄存器或原理图确认
下拉能力是否足够 VOL < 0.4V @ IOL = 3mA 负载曲线测试
上拉电阻值 1kΩ ~ 10kΩ (取决于总线电容) 计算上升沿时间 tr = 0.847 × RP × Cb
关断延迟 < 1µs (最好 < 300ns) 示波器测量从写寄存器到SCL实际上升
毛刺保护 SCL上加RC滤波或小电容 在100MHz带宽下观察波形