2. I2C协议时序:起始条件、停止条件、数据有效性、字节格式、ACK/NACK机制
各位同学,今天我们来啃I2C协议最核心的骨头——时序。说白了,就是SCL和SDA这两根线在时间轴上怎么配合。我刚开始学I2C时,总觉得时序图看着像心电图,后来亲手抓了几次波形才明白,其实规律很简单。
2.1 起始条件与停止条件
先看最基础的两个动作:什么时候开始通信,什么时候结束。I2C总线上所有设备都在监听这两根线,它们靠电平跳变来识别“开始”和“结束”。
| 条件 | SCL状态 | SDA状态 | 触发时机 |
|---|---|---|---|
| 起始条件 (START) | 高电平 | 从高→低跳变 | 总线空闲时 |
| 停止条件 (STOP) | 高电平 | 从低→高跳变 | 数据传输完成后 |
注意一个关键点:SCL为高电平时,SDA不能随意变化。只有在SCL为低电平时,SDA才能改变。起始和停止条件恰恰是例外——它们利用SCL高电平时SDA的跳变来传递控制信号。嗯,这里要记住:起始条件 = SCL高 + SDA下降沿;停止条件 = SCL高 + SDA上升沿。
避坑指南:我曾经在一个项目中,主控芯片的I2C外设在发送停止条件时,SDA的上升沿不够陡峭,导致从机没识别到停止信号,总线一直处于“假忙”状态。后来加了上拉电阻的驱动能力才解决。所以硬件设计时,上拉电阻的取值很关键,别随便选个4.7kΩ就完事。
2.2 数据有效性
数据什么时候才算有效?规则只有一句话:SCL为高电平时,SDA上的电平就是有效数据。SCL为低电平时,SDA可以变化,为下一个bit做准备。
你想想看,这其实很像采样:SCL的上升沿或高电平期间,接收方去读SDA。发送方必须在SCL低电平期间把数据准备好,然后在SCL高电平期间保持稳定。
- SCL低电平:发送方改变SDA电平(准备数据)
- SCL高电平:接收方读取SDA电平(采样数据)
- 数据保持时间:SDA在SCL高电平期间必须稳定,不能抖动
个人经验:我习惯在驱动代码里,每次操作SDA前先确认SCL确实是低电平。有些从机对时序要求很严,SCL刚变低你就去拉SDA,它可能还没准备好。加个几微秒的延时,能省很多调试时间。
2.3 字节格式与传输顺序
I2C每次传输一个字节(8位),顺序是高位在前(MSB first)。为什么?因为这样接收方可以边收边判断地址是否匹配,不用等整个字节收完。
一个完整的字节传输流程是这样的:
- 发送方在SCL低电平时,依次送出D7~D0共8个bit
- 每个bit在SCL高电平时被接收方采样
- 第9个SCL时钟周期用于ACK/NACK
举个例子,你要发送地址0x50(二进制01010000):
SCL: _-_-_-_-_-_-_-_-_-_
SDA: 0 1 0 1 0 0 0 0 A
D7 D6 D5 D4 D3 D2 D1 D0 ACK
注意看,D7是最高位,先发。A是第9位,由接收方控制。
2.4 ACK/NACK机制
这是I2C协议里最巧妙的设计之一。每个字节传输完后,接收方必须给一个应答信号。怎么给?在第9个SCL时钟周期,接收方把SDA拉低表示ACK,保持高表示NACK。
| 应答类型 | SDA电平(第9个SCL高电平期间) | 含义 |
|---|---|---|
| ACK | 低电平 | 接收成功,请继续发送 |
| NACK | 高电平 | 接收失败,或不再接收 |
为什么会用到NACK?常见场景有:
- 地址不匹配:总线上没有设备响应这个地址
- 从机忙:正在处理内部操作,无法接收新数据
- 读操作结束:主机读完最后一个字节后,主动发NACK告诉从机“够了,别发了”
重要提醒:ACK信号是由接收方拉低的,不是发送方。很多初学者写驱动时,在发送字节后自己把SDA拉低当ACK,这是错的。发送方在第9个时钟周期应该释放SDA(设为输入或开漏输出高),让接收方来控制。我曾经见过一个驱动,发送方一直强推SDA,结果总线上两个设备打架,波形惨不忍睹。
2.5 完整时序流程
把上面这些串起来,一次完整的I2C通信流程就是:
- START:SCL高,SDA下降沿
- 发送从机地址(7位)+ 读写位(1位):共8位,MSB first
- 等待ACK:第9个SCL时钟,接收方拉低SDA
- 发送/接收数据字节:每字节8位,每字节后跟ACK
- STOP:SCL高,SDA上升沿
如果是读操作,最后一步是主机发NACK代替ACK,然后发STOP。
核心要点:I2C时序的精髓在于“SCL高电平时SDA不能变”这条规则。起始、停止、数据采样、ACK/NACK,全都围绕这个规则展开。你把这个规则刻在脑子里,看任何I2C时序图都不会晕。
2.6 时序知识图谱
下面这张图把本章的核心知识点串起来了,方便你对照理解:
这张图把起始条件、停止条件、数据有效性、字节格式、ACK/NACK这五个知识点串在了一起。你会发现,它们都围绕着同一个核心规则:SCL高电平时SDA不能随意变化。起始和停止是例外,数据采样是应用,ACK/NACK是扩展。理解了这个规则,I2C时序你就掌握了八成。