1. I2C协议基础:从物理层到通信时序

各位同学好,我是老周。做嵌入式这些年,调试过最多的总线就是I2C和SPI。今天咱们先聊聊I2C的基础——这部分要是没吃透,后面调试起来会非常痛苦。我见过太多工程师拿着逻辑分析仪对着波形发呆,其实就是起始条件没看明白。

1.1 I2C总线物理层:两根线打天下

I2C总线只用两根线:SCL(时钟线)和SDA(数据线)。但你别小看这两根线,它们的设计其实挺讲究的。

核心特点:

  • 开漏输出:SCL和SDA都是开漏结构,只能拉低,不能主动拉高
  • 上拉电阻:总线空闲时靠上拉电阻把电平拉到VDD
  • 线与逻辑:多个设备可以同时拉低总线,谁先释放谁后释放由硬件仲裁

说白了,I2C的物理层就是一个"谁先拉低谁说话"的机制。我刚开始做驱动时,总觉得开漏结构很麻烦,后来才明白——正是这个设计让多主机通信成为可能。

我曾经踩过的坑:上拉电阻选型不当导致通信失败。电阻太小(比如1kΩ),总线拉低时电流过大,芯片可能驱动不了;电阻太大(比如10kΩ),上升沿太慢,高速模式下时序会出问题。一般4.7kΩ是个比较稳妥的起点,具体要看总线电容和通信速率。

1.2 SCL与SDA信号:谁控制谁?

SCL是时钟线,由主机控制。SDA是数据线,主机和从机都可以控制。但有个关键点:数据只能在SCL低电平时变化,高电平时采样。

信号 控制方 作用 注意事项
SCL 主机 提供时钟同步 从机可以拉低SCL进行时钟拉伸
SDA 主机/从机 传输数据 数据变化只能在SCL低电平期间

这里有个容易忽略的点:时钟拉伸。从机如果处理不过来,可以主动拉低SCL,让主机等一等。我调试一个温湿度传感器时就遇到过,从机每次发完地址都要拉伸时钟几百微秒,一开始我还以为是硬件坏了。

1.3 I2C通信时序:一个字节怎么传?

I2C传输一个字节(8位)的时序是这样的:

  1. SCL拉低,主机在SDA上设置第一位数据
  2. SCL拉高,从机采样SDA
  3. SCL再次拉低,主机设置下一位
  4. 重复8次,传完一个字节
  5. 第9个SCL周期:主机释放SDA,从机拉低SDA作为应答(ACK)

我的调试习惯:看I2C波形时,先找SCL的上升沿。在上升沿之前一点点看SDA的电平,那就是被采样的数据位。这个习惯帮我快速定位了很多数据错位的问题。

1.4 起始条件与停止条件:通信的开关

这两个条件是I2C通信的"开关",也是最容易出问题的地方。

起始条件(START):SCL高电平时,SDA从高电平跳变到低电平。

停止条件(STOP):SCL高电平时,SDA从低电平跳变到高电平。

关键区别:

  • 起始条件:SDA下降沿,SCL保持高
  • 停止条件:SDA上升沿,SCL保持高
  • 数据位传输:SDA变化发生在SCL低电平

你想想看,如果SCL和SDA的时序搞反了,或者边沿不够陡峭,从机根本识别不到起始条件。我曾经在一个项目中,因为PCB走线太长导致SDA上升沿变缓,起始条件总是识别失败。后来在靠近从机端加了个施密特触发器才解决。

我曾经遇到的典型故障:主机发送起始条件后,从机没有响应。用示波器一看,起始条件确实发出了,但SDA的下降沿不够陡,从机没认出来。原因是上拉电阻太大加上总线电容太大,导致边沿变缓。解决办法:减小上拉电阻到2.2kΩ,或者降低通信速率。

1.5 知识结构总览

下面这张图把I2C协议基础的核心知识点串起来了,方便你对照理解。

I2C协议基础核心知识结构 I2C协议基础核心知识结构 物理层 SCL + SDA 两根线 信号特性 开漏输出 + 上拉电阻 通信时序 SCL低电平变数据 起始条件 (START) SCL高 → SDA下降沿 通信开始的标志 停止条件 (STOP) SCL高 → SDA上升沿 通信结束的标志 数据字节传输 8位数据 + 1位应答 (ACK/NACK) 高位先行 (MSB First) 通信结束:主机发送STOP 提示:起始条件和停止条件必须由主机产生,从机只能拉低SCL进行时钟拉伸

1.6 常见故障排查清单

根据我多年的调试经验,I2C物理层和时序相关的故障,90%都可以归到下面这几类:

故障现象 可能原因 排查方法
总线一直为低 某个设备拉死了总线 逐个断开从机,看总线能否恢复
起始条件不识别 SDA下降沿太缓 减小上拉电阻或降低速率
从机无应答 地址错误或从机未上电 核对地址位(7位还是10位)
数据错位 SCL抖动或干扰 加滤波电容或降低速率
时钟拉伸异常 从机处理超时 检查从机初始化时序

我的调试三板斧:

  1. 先用逻辑分析仪抓波形,看起始条件和停止条件是否完整
  2. 核对地址字节:7位地址左移1位,加上读写位
  3. 检查ACK位:第9个SCL周期SDA是否被从机拉低