2. I2C协议时序:起始条件、停止条件、数据有效性、应答机制(ACK/NACK)
I2C协议说白了就是一套「谁说话、谁听话、什么时候说」的规矩。你想想看,SCL和SDA两根线,要挂多个设备,没有一套严格的时序规则,总线早就乱成一锅粥了。
我个人习惯把I2C时序拆成四个核心要素来理解:起始条件、停止条件、数据有效性、应答机制。把这四个搞明白,I2C通信的骨架你就抓住了。
2.1 起始条件(START Condition)
总线空闲时,SCL和SDA都是高电平(由上拉电阻拉高)。主设备想开始通信,必须发出一个起始信号。
时序定义:当SCL为高电平时,SDA从高电平切换到低电平。
关键点:起始条件是一个电平跳变,不是电平本身。SCL高电平期间,SDA的下降沿就是起始信号。
我在项目中遇到过一个问题:某次调试LCD驱动,示波器抓波形发现SDA在SCL低电平时就拉低了,然后SCL才变高。这根本不是起始条件,从机根本不认。折腾了半天,最后发现是代码里GPIO操作顺序写反了。
调试技巧:用示波器抓起始条件时,重点看SCL上升沿和SDA下降沿的相对位置。SDA必须先于SCL变化,且变化时SCL必须是高电平。
2.2 停止条件(STOP Condition)
通信结束,主设备要释放总线。停止条件的时序正好和起始条件相反。
时序定义:当SCL为高电平时,SDA从低电平切换到高电平。
| 条件 | SCL状态 | SDA跳变方向 | 作用 |
|---|---|---|---|
| 起始条件 | 高电平 | 高 → 低(下降沿) | 通知所有从机:准备接收 |
| 停止条件 | 高电平 | 低 → 高(上升沿) | 通知所有从机:通信结束 |
嗯,这里要注意:停止条件之后,总线恢复空闲状态(SCL和SDA都是高)。如果主设备没有发停止条件就释放总线,从机会一直等着,后续通信可能乱掉。
曾经踩过的坑:有一次我写驱动时,在异常处理分支里忘了发停止条件。结果LCD卡死,后续所有I2C操作都超时。从那以后,我每条I2C操作路径都会检查:是否确保有停止条件发出。
2.3 数据有效性(Data Validity)
数据怎么才算有效?I2C协议规定得很清楚:SCL高电平时,SDA上的数据必须稳定。数据变化只能在SCL低电平时发生。
为什么这样设计?你想想看,起始条件和停止条件都是在SCL高电平时检测SDA跳变。如果数据也在SCL高电平时变化,那从机就分不清这是数据还是起始/停止信号了。
数据采样规则:
- SCL高电平期间:主设备/从设备读取SDA上的数据位
- SCL低电平期间:发送设备可以改变SDA电平,准备下一位数据
- 数据位从最高位(MSB)开始传输,每个SCL脉冲传输1位
一句话总结:SCL高看数据,SCL低换数据。这个节奏不能乱。
我记得刚学I2C时,总觉得数据有效性这个规则有点多余。后来调试一个EEPROM驱动,发现读出来的数据总是错位。抓波形一看,原来是MCU的I2C外设在SCL上升沿采样,而我的软件模拟时序在SCL下降沿才更新数据——时序对不上,数据全乱套了。
2.4 应答机制(ACK/NACK)
I2C的应答机制,说白了就是接收方给发送方回个话:「收到了」或者「没收到」。这个机制让I2C比SPI多了错误检测能力。
应答时序:
- 发送方发送完8位数据后,释放SDA(设为输入或高阻)
- 主设备产生第9个SCL时钟脉冲
- 接收方在第9个SCL脉冲的高电平期间,将SDA拉低(ACK)或保持高(NACK)
| 应答类型 | SDA状态(第9个SCL高电平) | 含义 | 常见原因 |
|---|---|---|---|
| ACK(应答) | 低电平 | 接收成功,可以继续发送 | 正常通信 |
| NACK(非应答) | 高电平 | 接收失败或拒绝接收 | 地址不匹配、设备忙、数据错误 |
实用经验:调试LCD驱动时,如果发送设备地址后收到NACK,90%的情况是地址写错了。LCD的I2C地址通常是7位,但数据手册上给的可能是8位(左移1位后的值)。我建议你仔细核对:手册给的是0x27还是0x4E?
2.5 完整数据传输流程
把上面四个要素串起来,一次完整的I2C数据传输是这样的:
- 起始条件:主设备发出START
- 发送从机地址:7位地址 + 1位读写位(R/W)
- 等待应答:从机返回ACK表示地址匹配
- 发送/接收数据:每8位数据后跟1个应答位
- 停止条件:主设备发出STOP
这里有个细节:读操作时,最后一个字节主设备要发NACK,告诉从机「别再发了,我要停了」。然后主设备再发停止条件。这个NACK是读操作结束的标志,不是错误。
曾经踩过的坑:我第一次写LCD读寄存器时,最后一个字节发了ACK而不是NACK。结果从机继续发数据,总线被占死,停止条件发不出去。从那以后,我写读操作代码都会特意检查:最后一个字节是不是NACK。
2.6 时序知识图谱
下面这张图把I2C协议时序的四个核心要素串在一起,方便你对照理解:
2.7 时序参数速查
实际调试时,时序参数也很关键。不同I2C设备对时序要求不一样,LCD驱动芯片通常支持标准模式(100kHz)和快速模式(400kHz)。
| 参数 | 符号 | 标准模式 | 快速模式 | 说明 |
|---|---|---|---|---|
| SCL时钟频率 | fSCL | ≤100 kHz | ≤400 kHz | 主设备产生 |
| 起始条件保持时间 | tHD;STA | ≥4.0 μs | ≥0.6 μs | SCL高后SDA保持低 |
| 数据保持时间 | tHD;DAT | ≥0 μs | ≥0 μs | SCL下降沿后数据保持 |
| 数据建立时间 | tSU;DAT | ≥250 ns | ≥100 ns | SCL上升沿前数据稳定 |
| 停止条件建立时间 | tSU;STO | ≥4.0 μs | ≥0.6 μs | SCL高后SDA拉高 |
个人经验:软件模拟I2C时,我习惯把延时设得比最小值宽裕一些。比如标准模式,我会用5μs而不是4μs。虽然慢一点,但兼容性好,换不同厂家的LCD芯片不用改代码。
嗯,I2C时序就这些核心内容。起始条件、停止条件、数据有效性、应答机制——这四个概念你吃透了,I2C通信的底层逻辑就通了。后面章节我们会把这些知识用到实际的LCD驱动调试中,到时候你会感谢自己现在花时间搞懂了这些基础。