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

各位同学,咱们正式开始这门课之前,先把I2C协议的老底儿翻出来晒晒。你可能会想:“I2C协议嘛,谁不知道?” 但说实话,很多人在STM32上栽跟头,恰恰就是这些基础概念没吃透。我见过太多工程师拿着逻辑分析仪抓波形,却看不懂为什么设备不应答——说白了,就是协议理解不到位。

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

I2C总线就两条线:SCL(时钟线)和SDA(数据线)。嗯,就这么简单。但这两条线的电气特性,决定了整个协议的脾气。

  • 开漏输出:SCL和SDA都是开漏结构。这意味着什么?芯片只能把线拉低,不能主动拉高。拉高靠上拉电阻。
  • 线与逻辑:多个设备挂在同一条线上,谁都可以拉低。如果有一个设备拉低了,整条线就是低电平。这就是“线与”——低电平优先。
  • 上拉电阻:一般4.7kΩ或10kΩ。总线速度越高,电阻要越小。我做过一个项目,总线长度半米,用了2.2kΩ才稳定。
我的习惯:画PCB时,SCL和SDA的走线尽量等长,远离晶振和开关电源。曾经有一次,I2C通信偶尔出错,查了两天,最后发现是SDA线贴着DC-DC电感走的。
参数 标准模式 (100kHz) 快速模式 (400kHz) 高速模式 (3.4MHz)
上拉电阻典型值 10kΩ 4.7kΩ 1.5kΩ
总线电容上限 400pF 400pF 100pF
最大从设备数量 127(7位地址) 127 127

1.2 协议层:谁说话,谁听话?

I2C是主从结构。总线上只有一个主设备(Master),其他都是从设备(Slave)。主设备负责产生时钟、发起通信、决定什么时候结束。从设备只能被动响应。

你想想看,如果两个设备同时想当主设备,怎么办?I2C有仲裁机制。当多个主设备同时拉低SDA时,谁先释放谁就输了。这个机制保证了总线上不会乱套。

关键点:在STM32的硬件I2C外设中,仲裁是由硬件自动处理的。但如果你用软件模拟I2C,就得自己写仲裁逻辑——我建议新手别碰这个坑。

1.3 起始条件与停止条件

这两个条件是I2C通信的“开关”。没有它们,总线上的设备不知道什么时候开始、什么时候结束。

  • 起始条件(S):SCL为高电平时,SDA从高电平跳变到低电平。
  • 停止条件(P):SCL为高电平时,SDA从低电平跳变到高电平。

为什么这样设计?因为数据在SCL低电平时变化,高电平时采样。起始和停止条件利用了SCL高电平时SDA的变化——这是一种“带外信号”,不会和数据混淆。

我曾经踩过的坑:在STM32F103上,如果总线上有噪声导致SDA在SCL高电平时抖动,硬件I2C会误判为起始或停止条件。后来我在SDA和SCL上各加了一个100pF的滤波电容,问题解决。

1.4 数据有效性:什么时候读数据?

I2C的数据传输有严格的时序要求:

  1. SCL低电平时:发送设备改变SDA电平。
  2. SCL高电平时:接收设备读取SDA电平。

每个字节8位,高位在前(MSB first)。传输完8位后,发送设备释放SDA,接收设备在第9个时钟周期拉低SDA作为应答。

说白了,就是“低电平时随便改,高电平时别乱动”。这个规则保证了数据在采样时刻是稳定的。

1.5 应答机制:通信的握手

应答是I2C协议中最容易被忽视、却又最容易出问题的环节。

  • ACK(应答):接收设备在第9个时钟周期拉低SDA,表示“收到,请继续”。
  • NACK(非应答):接收设备在第9个时钟周期保持SDA高电平,表示“没收到”或“不想收了”。

什么时候会出现NACK?

  • 从设备地址不匹配
  • 从设备正忙,无法响应
  • 主设备读数据时,读完最后一个字节后发送NACK,告诉从设备“别发了”
我的调试经验:用逻辑分析仪抓I2C波形时,先看应答位。如果地址发送后没有ACK,90%的可能是地址写错了或者从设备没上电。别急着怀疑代码,先查硬件。

1.6 知识结构总览

下面这张图把I2C协议的核心要素串起来了。你可以把它当作调试时的“检查清单”。

I2C协议核心知识结构 物理层 SCL + SDA 开漏输出 上拉电阻 + 线与逻辑 协议层 主从结构 仲裁机制 时序 起始条件 S 停止条件 P 数据有效性 SCL低电平改数据 SCL高电平读数据 应答机制 ACK:拉低SDA NACK:保持高电平 调试要点 1. 先查ACK,再查数据 2. 起始/停止条件看边沿 3. 数据在SCL高电平时采样 4. 上拉电阻别太大也别太小

1.7 一个完整的字节传输示例

咱们来看一个实际的传输过程。假设主设备要向地址为0x50的从设备写一个字节0xA5:

  1. 主设备发送起始条件(S)
  2. 主设备发送7位地址 + 写位:0x50 << 1 | 0 = 0xA0
  3. 从设备在第9个时钟拉低SDA,发送ACK
  4. 主设备发送数据字节:0xA5
  5. 从设备再次发送ACK
  6. 主设备发送停止条件(P)

整个过程,SCL一共产生了18个脉冲(9个用于地址,9个用于数据)。

记住这个流程:S → 地址+读写位 → ACK → 数据 → ACK → ... → P。这是I2C通信的“标准句式”,所有操作都基于这个模板。

1.8 写在最后

I2C协议看起来简单,但细节决定成败。我见过有人把上拉电阻焊成0Ω,结果总线一直拉不上去;也见过有人把从设备地址搞反了,调了一整天。嗯,这些坑咱们后面都会讲到怎么避免。