4、I2C协议基础:标准模式、快速模式、高速模式时序参数对比

做嵌入式这些年,I2C 总线我接触得最多。从最早的单片机挂个 EEPROM,到后来给传感器阵列做数据采集,几乎每个项目都离不开它。很多新手拿到 I2C 设备,直接调库函数就跑,结果要么通信不稳定,要么速度上不去。说白了,问题往往出在对时序参数的理解上。

今天我们就来把 I2C 的三种模式——标准模式、快速模式、高速模式——的时序参数掰开揉碎讲清楚。你想想看,搞懂了这些,以后调 I2C 总线就像看交通信号灯一样简单。

4.1 三种模式的核心差异

I2C 总线从诞生到现在,主要经历了三个速度等级。我习惯把它们比作三种路况:

  • 标准模式(Standard-mode, Sm):100 kHz,像城市普通道路,稳但慢。
  • 快速模式(Fast-mode, Fm):400 kHz,像城市快速路,日常最常用。
  • 高速模式(High-speed mode, Hs-mode):3.4 MHz,像高速公路,但需要特殊硬件支持。

嗯,这里要注意:高速模式不是所有 I2C 设备都支持的。我在项目中遇到过,有人把普通传感器挂到高速总线上,结果死活不通——因为从机根本不认 Hs-mode 的时序。

4.2 时序参数逐项对比

I2C 的时序参数,核心就几个:时钟频率、上升时间、下降时间、数据建立时间、数据保持时间。下面这张表我把三种模式的关键参数列出来了,建议你收藏。

参数 符号 标准模式 (Sm) 快速模式 (Fm) 高速模式 (Hs-mode)
时钟频率 fSCL ≤ 100 kHz ≤ 400 kHz ≤ 3.4 MHz
SCL 低电平时间 tLOW ≥ 4.7 μs ≥ 1.3 μs ≥ 0.16 μs
SCL 高电平时间 tHIGH ≥ 4.0 μs ≥ 0.6 μs ≥ 0.06 μs
上升时间 tr ≤ 1000 ns ≤ 300 ns ≤ 80 ns
下降时间 tf ≤ 300 ns ≤ 300 ns ≤ 80 ns
数据建立时间 tSU;DAT ≥ 250 ns ≥ 100 ns ≥ 10 ns
数据保持时间 tHD;DAT ≥ 0 ns ≥ 0 ns ≥ 0 ns
SCL 时钟建立时间 tSU;STO ≥ 4.0 μs ≥ 0.6 μs ≥ 0.16 μs
总线电容 Cb ≤ 400 pF ≤ 400 pF ≤ 100 pF

关键点:从标准模式到快速模式,tLOW 从 4.7 μs 缩到 1.3 μs,快了 3.6 倍。而高速模式更是直接压到 0.16 μs。这意味着你的 MCU 必须能精确控制微秒甚至纳秒级别的延时。

4.3 上升时间与下降时间的陷阱

我个人觉得,上升时间(tr)和下降时间(tf)是最容易被忽略的参数。很多人只盯着时钟频率,结果总线电容一大,波形就变圆了。

为什么会这样?因为 I2C 是开漏输出,SCL 和 SDA 的上升沿是靠上拉电阻把电平拉高的。总线电容越大,RC 充电时间常数越大,上升时间就越长。

我曾经在一个项目里,把 10 个传感器挂到同一条 I2C 总线上,总线电容轻松超过 200 pF。快速模式下,上升时间直接飙到 500 ns,超过了 300 ns 的限值。结果就是:偶尔通信失败,数据错位。后来我把上拉电阻从 4.7 kΩ 换到 2.2 kΩ,问题才解决。

避坑指南:我曾经在高速模式下用过 10 kΩ 的上拉电阻,结果波形完全没法看。高速模式建议上拉电阻取 1 kΩ 到 2 kΩ 之间,同时总线电容要控制在 100 pF 以内。

4.4 数据建立时间与保持时间

数据建立时间(tSU;DAT)和数据保持时间(tHD;DAT)决定了数据在时钟边沿前后的稳定性。

  • 建立时间:数据必须在 SCL 上升沿之前稳定下来。标准模式要求 250 ns,快速模式 100 ns,高速模式只有 10 ns。
  • 保持时间:数据在 SCL 下降沿之后需要保持一段时间。三种模式都要求 ≥ 0 ns,但实际中我建议至少留 50 ns 的余量。

嗯,这里有个细节:保持时间虽然写的是 ≥ 0 ns,但如果你真的卡在 0 ns 边界上,噪声稍微一抖就可能出错。我个人的习惯是,在软件 I2C 实现中,每个数据位都加一个 NOP 延时,确保建立时间和保持时间都留有余量。

4.5 高速模式的特殊机制

高速模式(Hs-mode)和前面两种模式有个本质区别:它需要主机先发送一个特殊的「主代码」来切换总线状态。

流程是这样的:

  1. 主机先以快速模式(400 kHz)发送起始条件。
  2. 然后发送一个 8 位的主代码(0000 1xxx),其中 xxx 是主机标识。
  3. 从机收到主代码后,会切换到高速模式,并释放 SCL 和 SDA。
  4. 主机随后以 3.4 MHz 进行后续的数据传输。
  5. 传输结束后,主机发送停止条件,总线回到快速模式。

注意:高速模式下,从机必须支持 Hs-mode,否则它不会响应主代码。我曾经见过有人把普通 EEPROM 挂到高速总线上,结果从机一直 NACK,折腾了半天才发现是设备不支持。

4.6 三种模式的时序关系图

下面这张 SVG 图把三种模式的时序关系画出来了,你可以直观地看到时钟周期、高低电平时间的变化趋势。

I2C 三种模式时序对比图 I2C 三种模式时序参数对比 标准模式 f_SCL = 100 kHz t_LOW = 4.7 μs t_HIGH = 4.0 μs t_r ≤ 1000 ns 快速模式 f_SCL = 400 kHz t_LOW = 1.3 μs t_HIGH = 0.6 μs t_r ≤ 300 ns 高速模式 f_SCL = 3.4 MHz t_LOW = 0.16 μs t_HIGH = 0.06 μs t_r ≤ 80 ns 说明:从标准模式到高速模式,时钟频率提升 34 倍, 但上升时间要求从 1000 ns 压缩到 80 ns,对硬件设计提出更高要求。 SCL 波形示意(一个时钟周期) Sm: t_HIGH=4.0μs t_LOW=4.7μs Fm: t_HIGH=0.6μs t_LOW=1.3μs Hs: t_HIGH=0.06μs t_LOW=0.16μs

4.7 实际移植中的参数选择建议

讲完了理论,说说实际干活时怎么选。我个人的经验是:

  • 标准模式:适合低速传感器(如温度、湿度),总线长度可以到 1 米以上。上拉电阻用 4.7 kΩ 到 10 kΩ 都行。
  • 快速模式:日常最常用,适合大多数 I2C 设备。总线长度建议控制在 30 cm 以内,上拉电阻用 2.2 kΩ 到 4.7 kΩ。
  • 高速模式:只有在对吞吐量要求极高的场景才用,比如图像传感器、高速 ADC。总线长度必须控制在 10 cm 以内,上拉电阻用 1 kΩ 左右,而且 PCB 走线要特别注意阻抗匹配。

核心原则:能用快速模式就别上高速模式。高速模式对硬件设计的要求高出一大截,而且兼容性问题多。我见过太多人为了追求那点速度,结果花了两周调时序,得不偿失。

4.8 一个简单的时序检查代码

最后,分享一段我在调试 I2C 时序时常用的检查代码。它用 GPIO 模拟 I2C,并测量实际的 SCL 高低电平时间。

// 简易 I2C 时序检查函数(基于 GPIO 模拟)
// 返回 0 表示时序正常,返回 -1 表示时序异常

int i2c_timing_check(void) {
    uint32_t t_high, t_low;
    
    // 测量 SCL 高电平时间
    GPIO_SetBits(SCL_PORT, SCL_PIN);
    delay_us(1);  // 等待电平稳定
    t_high = get_sys_tick();  // 记录当前系统滴答
    while (GPIO_ReadInputDataBit(SCL_PORT, SCL_PIN) == 1) {
        // 等待 SCL 变低
    }
    t_high = get_sys_tick() - t_high;
    
    // 测量 SCL 低电平时间
    GPIO_ResetBits(SCL_PORT, SCL_PIN);
    delay_us(1);
    t_low = get_sys_tick();
    while (GPIO_ReadInputDataBit(SCL_PORT, SCL_PIN) == 0) {
        // 等待 SCL 变高
    }
    t_low = get_sys_tick() - t_low;
    
    // 检查是否满足快速模式要求
    if (t_high < 600 || t_low < 1300) {
        return -1;  // 时序过短,需要调整
    }
    
    return 0;
}

小技巧:如果你用的是硬件 I2C 外设,可以直接读寄存器里的时序配置值。但用软件模拟时,这个检查函数特别有用。我曾经靠它抓到一个上拉电阻虚焊的问题——当时 SCL 高电平时间只有 200 ns,明显不正常。