1. I2C协议基础:物理层、协议层、起始条件、停止条件、数据有效性、应答机制

各位同学,咱们今天正式开讲I2C。说实话,我在嵌入式这行摸爬滚打了十几年,调试过的I2C设备少说也有上百种。从最简单的温度传感器,到复杂的九轴惯性测量单元,底层都是这套协议在跑。你把它吃透了,后面写驱动、抓波形、定位问题,心里就有底了。

1.1 物理层:两条线怎么干活?

I2C总线就两根线:SCL(时钟线)和SDA(数据线)。它是个多主从总线,意思是总线上可以挂多个主设备和多个从设备。但实际项目中,绝大多数情况是单个MCU做主设备,挂一堆传感器做从设备。

这两根线都是开漏输出结构。什么叫开漏?说白了,芯片只能把线拉低,不能主动拉高。那高电平谁来给?上拉电阻。我见过不少新手画原理图时忘了加上拉电阻,结果总线一直低电平,通信死活起不来。

上拉电阻选型经验:

  • 标准模式(100kHz):4.7kΩ 常用
  • 快速模式(400kHz):2.2kΩ 或 1.5kΩ
  • 高速模式(3.4MHz):1kΩ 以下

我曾经在一个项目里用了10kΩ上拉跑400kHz,波形上升沿慢得像蜗牛,数据全错。后来换成2.2kΩ,问题立刻解决。

1.2 协议层:数据怎么在线上跑?

I2C的通信过程,我习惯把它拆成四个基本动作:起始条件 → 发送地址/数据 → 应答 → 停止条件。咱们一个一个说。

1.2.1 起始条件(Start Condition)

SCL为高电平时,SDA从高电平切换到低电平。这就是起始信号。总线上所有设备都会检测到这个边沿,知道"要开始通信了"。

调试小技巧:用逻辑分析仪抓波形时,先找起始条件。如果波形里没有清晰的SCL高电平期间SDA下降沿,那说明主设备根本没发起通信。我经常用这个来快速判断是软件没配置好,还是硬件连接有问题。

1.2.2 停止条件(Stop Condition)

SCL为高电平时,SDA从低电平切换到高电平。从设备检测到这个信号,就知道"通信结束了",释放总线。

这里有个坑:起始条件和停止条件必须成对出现。但有一种特殊情况叫"重复起始条件"——不发送停止条件,直接再发一个起始条件。这在读传感器数据时非常常见,后面写驱动时会详细讲。

1.2.3 数据有效性

I2C规定:SDA上的数据必须在SCL低电平时变化,在SCL高电平时采样。也就是说,SCL高电平期间,SDA必须保持稳定。

为什么会这样?你想想看,如果SCL高电平时SDA还在跳变,那到底是数据还是起始/停止条件?协议设计者用这个规则把数据和命令区分开了。

SCL状态 SDA行为 含义
低电平 允许变化 准备下一位数据
高电平 必须稳定 采样当前位
高电平 + 下降沿 高→低 起始条件
高电平 + 上升沿 低→高 停止条件

1.2.4 应答机制(ACK/NACK)

每发送完一个字节(8位数据),接收方必须在第9个SCL周期拉低SDA,表示"收到了"。这就是应答位(ACK)。如果接收方不拉低(SDA保持高),那就是非应答(NACK)。

NACK在调试中非常常见,我总结了几种情况:

  • 从设备地址不对:发送地址后收到NACK,说明总线上没有这个地址的设备
  • 从设备忙:正在处理内部操作,没空应答
  • 读操作结束:主设备发送NACK告诉从设备"别再发了"

避坑指南:我曾经调试一个气压传感器,每次读数据都在第三个字节后收到NACK。查了半天手册才发现,这个传感器读操作时,主设备必须在最后一个字节发NACK,否则从设备会一直发数据。很多新手在这里栽跟头。

1.3 完整通信流程

把上面这些拼起来,一次完整的I2C写操作是这样的:

  1. 主设备发送起始条件
  2. 主设备发送7位从设备地址 + 1位读写位(0表示写)
  3. 从设备应答ACK
  4. 主设备发送寄存器地址(1字节)
  5. 从设备应答ACK
  6. 主设备发送数据(1字节或多字节)
  7. 每字节后从设备应答ACK
  8. 主设备发送停止条件

读操作稍微复杂一点,需要先写寄存器地址,再重新起始,然后读数据。这个后面章节会手把手教大家写代码。

1.4 I2C协议知识结构图

下面这张图把I2C协议的核心知识点串起来了。我建议你把它存下来,调试时对照着看。

I2C协议知识结构图 I2C协议知识结构 物理层 协议层 电气特性 SCL时钟线 SDA数据线 开漏输出结构 上拉电阻 起始条件 停止条件 数据有效性 应答机制 7位地址 + 读写位 标准模式100kHz 快速模式400kHz 高速模式3.4MHz 总线电容 ≤ 400pF 调试要点 1. 先确认SCL/SDA是否有上拉电阻 2. 用逻辑分析仪抓起始条件和停止条件 3. 地址发送后看ACK/NACK判断设备是否存在 4. 数据有效性检查:SCL高电平时SDA是否稳定

1.5 写在后面

I2C协议看起来简单,但实际调试中坑不少。我见过最离谱的问题,是一个工程师把SCL和SDA接反了,查了两天没找到原因。所以我的建议是:先理解协议,再动手写代码。后面几章我们会用STM32的硬件I2C和软件模拟I2C分别驱动传感器,到时候这些基础知识会反复用到。

嗯,今天就到这儿。记住一句话:I2C调试,波形会说话。学会看波形,你就成功了一半。