1. I2C协议基础回顾:物理层、协议层、时序图解读

各位同学,咱们正式开始之前,我先说句实在话。I2C这个协议,看着简单,但真要在项目里把它调稳了,尤其是挂上三四个从机的时候,坑是真不少。我最早用STM32做I2C的时候,也以为不就是两根线嘛,结果被从机地址冲突、时钟延展、总线锁死这些问题折腾了好几个通宵。

所以第一章,咱们先把地基打牢。物理层长什么样?协议层怎么握手?时序图到底怎么看?这些东西搞不清楚,后面调试故障定位就是瞎蒙。

1.1 物理层:就两根线,但别小看它们

I2C总线物理上只需要两根线:SCL(串行时钟线)和SDA(串行数据线)。所有设备都挂在这两根线上,主从机共用。

关键特征:

  • SCL和SDA都是开漏输出结构,必须外接上拉电阻
  • 总线空闲时,两根线都被上拉电阻拉到高电平
  • 任何设备都可以拉低总线——这就是“线与”特性
  • 同一总线上最多可挂127个从机(7位地址模式)

我习惯把上拉电阻选在4.7kΩ左右,标准模式100kHz下基本够用。如果总线电容大或者线长,可以换2.2kΩ。但别太小,否则功耗会上去。

我曾经踩过的坑:有一次调试一块板子,SDA波形一直不对,示波器一看,上升沿慢得像爬坡。查了半天,发现上拉电阻焊了10kΩ,总线电容又大,信号根本建立不起来。换成3.3kΩ后,波形立马干净了。

物理层还有一个重要概念——多主机仲裁。多个主机同时尝试控制总线时,谁先拉低SDA谁就赢。这个机制靠的是开漏结构的“线与”特性,说白了就是谁先动手谁说了算。

1.2 协议层:起始、停止、数据、应答

协议层其实就四个基本动作,你把它记熟了,后面看时序图就跟看乐谱一样。

动作 SCL状态 SDA状态 说明
起始条件(S) 高电平 下降沿(高→低) SCL高时SDA跳变,表示传输开始
停止条件(P) 高电平 上升沿(低→高) SCL高时SDA跳变,表示传输结束
数据位传输 低电平时改变SDA 高电平时采样SDA SCL高时SDA必须稳定
应答位(ACK/NACK) 第9个时钟脉冲 从机拉低为ACK 从机不拉低表示NACK

数据格式很固定:起始条件 → 7位从机地址 + 读/写位 → 应答位 → 数据字节 + 应答位 → ... → 停止条件。每个字节8位,高位在前(MSB first)。

个人经验:调试的时候,我最先看的就是应答位。如果从机没拉低ACK,八成是地址写错了,或者从机根本没上电。别急着怀疑时序,先查电源和地址。

1.3 时序图解读:别被波形吓到

很多同学看到I2C时序图就头大,其实拆开看就四个参数:建立时间、保持时间、上升时间、下降时间。标准模式100kHz下,这些时间都比较宽松,但快速模式400kHz就得小心了。

我画了一张时序结构图,帮你把整个流程串起来:

I2C总线时序结构图 I2C 总线时序结构图 SCL SDA 起始 S 7位从机地址 + R/W ACK 8位数据 ACK 停止 P 时序要点说明: • SCL高电平时,SDA必须保持稳定(数据采样窗口) • SCL低电平时,SDA可以变化(数据切换窗口) • 起始和停止条件:SCL高电平时SDA发生跳变 • 每个字节后必须跟一个应答位(第9个SCL脉冲)

你看,整个传输过程就是:起始 → 地址+R/W → 应答 → 数据 → 应答 → ... → 停止。每个字节9个时钟(8位数据+1位应答),节奏非常固定。

1.4 时钟延展:从机的“慢点,我跟不上”

时钟延展(Clock Stretching)是I2C协议里一个容易被忽略的特性。从机如果处理不过来,可以拉低SCL,告诉主机“你慢点,我还没准备好”。主机检测到SCL被拉低,就会等待,直到从机释放SCL。

实际影响:

  • STM32硬件I2C外设默认支持时钟延展
  • 但有些从机(比如某些传感器)延展时间过长,会导致超时
  • 我建议在I2C驱动里加一个超时处理,别死等

我记得有一次用STM32F103读一个温湿度传感器,读回来的数据偶尔会错。示波器一看,从机在应答位之后延展了SCL将近2ms,而我的I2C超时设得太短,主机直接放弃了传输。把超时放宽到5ms后,问题就解决了。

1.5 常见时序参数速查

不同模式下,时序参数差别很大。我整理了一张速查表,调试时对照着看:

参数 标准模式(100kHz) 快速模式(400kHz) 说明
SCL时钟频率 ≤100 kHz ≤400 kHz 实际频率由主机决定
SCL低电平时间 ≥4.7 μs ≥1.3 μs 保证数据建立时间
SCL高电平时间 ≥4.0 μs ≥0.6 μs 保证数据保持时间
SDA建立时间 ≥250 ns ≥100 ns SCL上升沿前SDA需稳定
SDA保持时间 ≥0 ns ≥0 ns SCL下降沿后SDA保持
上升时间 ≤1000 ns ≤300 ns 受上拉电阻和总线电容影响

调试小技巧:用示波器看波形时,重点看SCL低电平时间和SDA建立时间。如果这两个参数不满足,数据采样就会出错。我习惯在代码里把I2C时序配置得比手册要求宽松20%,留点余量。

1.6 多从机通信的物理基础

为什么I2C能挂多个从机?因为每个从机都有唯一的地址。主机发送地址时,所有从机都会收到,但只有地址匹配的那个才会应答。其他从机保持沉默,继续监听总线。

这里有个容易忽略的点:从机地址冲突。如果两个从机用了同一个地址,它们会同时应答,导致总线数据混乱。我遇到过一块板子上两个传感器默认地址都是0x48,结果读数据时两个一起响应,数据完全对不上。

避坑指南:选型时一定要确认每个从机的I2C地址是否可配置。如果不可配置,就得用I2C多路复用器(比如TCA9548A)来分时访问。我曾经为了省一个I2C多路复用器的钱,硬着头皮改PCB,结果得不偿失。