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写操作是这样的:
- 主设备发送起始条件
- 主设备发送7位从设备地址 + 1位读写位(0表示写)
- 从设备应答ACK
- 主设备发送寄存器地址(1字节)
- 从设备应答ACK
- 主设备发送数据(1字节或多字节)
- 每字节后从设备应答ACK
- 主设备发送停止条件
读操作稍微复杂一点,需要先写寄存器地址,再重新起始,然后读数据。这个后面章节会手把手教大家写代码。
1.4 I2C协议知识结构图
下面这张图把I2C协议的核心知识点串起来了。我建议你把它存下来,调试时对照着看。
1.5 写在后面
I2C协议看起来简单,但实际调试中坑不少。我见过最离谱的问题,是一个工程师把SCL和SDA接反了,查了两天没找到原因。所以我的建议是:先理解协议,再动手写代码。后面几章我们会用STM32的硬件I2C和软件模拟I2C分别驱动传感器,到时候这些基础知识会反复用到。
嗯,今天就到这儿。记住一句话:I2C调试,波形会说话。学会看波形,你就成功了一半。