I2C协议基础回顾:物理层、协议层、时序参数详解

各位同学好,我是老周。做嵌入式这些年,I2C是我打交道最多的接口之一。别看它只有两根线,坑是真不少。今天咱们先把I2C的底子打牢,后面讲抗干扰设计时你才能知道问题出在哪。

一、物理层:就两根线,但别小看它

I2C总线就两条线:SDA(数据线)和SCL(时钟线)。都是开漏输出,配上上拉电阻。什么意思呢?说白了,芯片只能把线拉低,不能主动拉高。高电平全靠上拉电阻提供。

关键点:开漏结构决定了I2C的电气特性。多主机仲裁、时钟拉伸这些高级功能,全依赖这个设计。

我刚开始做项目时,总觉得上拉电阻随便选一个就行。结果有一次在高温箱里测试,通信频繁出错。查了半天,发现是上拉电阻选小了,灌电流太大,把IO口的驱动能力吃死了。

上拉电阻怎么选?

这里给个经验值:

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

我的习惯:一般先上4.7kΩ。如果总线设备多、距离长,再换成2.2kΩ。别一上来就用1kΩ,功耗会大不少。

二、协议层:起始、停止、应答,三板斧

I2C的协议说简单也简单,就几个基本动作。但组合起来,能玩出花。

1. 起始条件和停止条件

SCL高电平时,SDA从高变低 → 起始条件(Start)。
SCL高电平时,SDA从低变高 → 停止条件(Stop)。

这个时序很关键。我见过有人用GPIO模拟I2C时,起始条件没做对,从机根本不响应。你想想看,从机一直在等那个下降沿,你没给,它就不动。

2. 数据传输

每个时钟脉冲传1位数据。SCL低电平时SDA可以变化,SCL高电平时SDA必须稳定。这个规则保证了数据的可靠性。

3. 应答机制

每传完一个字节(8位),第9个时钟周期是应答位。接收方拉低SDA表示ACK,不拉低就是NACK。

避坑指南:我曾经在一个项目中,从机地址写对了,但就是不ACK。查了两天,发现是从机电源没稳定,上电时序有问题。记住:I2C从机必须在总线空闲时才能正确响应。

三、时序参数:别只看手册,要实测

I2C的时序参数,手册上写得清清楚楚。但实际项目中,你得留余量。

参数 符号 标准模式 快速模式
SCL时钟频率 fSCL 100 kHz 400 kHz
保持时间(起始) tHD;STA 4.0 μs 0.6 μs
建立时间(停止) tSU;STO 4.0 μs 0.6 μs
数据保持时间 tHD;DAT 0 μs 0 μs
数据建立时间 tSU;DAT 250 ns 100 ns
SCL低电平时间 tLOW 4.7 μs 1.3 μs
SCL高电平时间 tHIGH 4.0 μs 0.6 μs

嗯,这里要注意:数据保持时间tHD;DAT是0μs。这意味着SCL下降沿之后,SDA可以立刻变化。但实际中,我建议留个几百纳秒的余量,特别是总线电容大的时候。

四、知识体系总览

下面这张图,把I2C协议的核心知识点串起来了。你对照着看,心里就有谱了。

I2C协议知识体系 I2C协议知识体系 物理层 协议层 时序参数 SDA / SCL 开漏输出 上拉电阻 总线电容 起始/停止 数据帧 应答机制 多主机仲裁 f_SCL t_LOW/HIGH 建立/保持 上升/下降 物理层决定电气特性,协议层决定通信规则,时序参数决定可靠性 三者缺一不可,抗干扰设计要从这三个维度同时入手

五、一个完整的读写序列

光说不练假把式。咱们看一个实际的I2C写操作流程:

// 伪代码:向从机地址0x50写入两个字节
起始条件
发送从机地址 + 写位 (0xA0)  // 7位地址左移1位,最低位为0
等待ACK
发送寄存器地址 (0x10)
等待ACK
发送数据字节1 (0xAB)
等待ACK
发送数据字节2 (0xCD)
等待ACK
停止条件

读操作稍微复杂一点,需要先写寄存器地址,再重新发起始条件,然后读数据:

// 伪代码:从从机地址0x50读取两个字节
起始条件
发送从机地址 + 写位 (0xA0)
等待ACK
发送寄存器地址 (0x10)
等待ACK
重复起始条件  // 这里要注意,不是停止再开始
发送从机地址 + 读位 (0xA1)
等待ACK
读取数据字节1,主机发送ACK
读取数据字节2,主机发送NACK  // 最后一个字节要发NACK
停止条件

我的经验:重复起始条件(Repeated Start)是很多新手容易搞错的地方。有些人习惯先发Stop再发Start,这在多主机系统中会丢失总线控制权。记住:读操作一定要用重复起始。

六、常见问题与调试思路

做I2C调试,示波器是必备的。我总结了几种常见波形异常:

  • SDA一直低:某个设备把总线拉死了。逐个断开从机排查。
  • SCL频率不对:检查主时钟分频配置,特别是用内部RC振荡器时。
  • ACK丢失:地址对不对?从机供电正常吗?总线电容太大导致信号畸变?
  • 数据错位:大概率是时序余量不够,特别是快速模式下。

避坑指南:我曾经在一个量产项目中,发现部分板子I2C通信不稳定。查到最后,是PCB走线太长,总线电容超过了400pF。400kHz模式下,信号上升沿明显变缓,导致从机采样出错。后来加了施密特触发器整形,问题才解决。