4. 数据传输与应答:字节传输格式、ACK/NACK机制、从机时钟拉伸
I2C 的数据传输,说白了就是主从设备之间的一问一答。主机发数据,从机得给个回应——「收到了」或者「没收到」。这个回应就是 ACK/NACK。另外还有个让很多新手头疼的「时钟拉伸」,其实是从机在说「慢点,我还没准备好」。
我个人习惯把这几个概念放在一起讲,因为它们在实际波形里是同时出现的。你抓一条 I2C 波形,字节、应答、时钟拉伸全混在一起。分开学容易,合起来看就懵了。今天咱们就把它们彻底理清楚。
4.1 字节传输格式:9个时钟的规矩
I2C 的字节传输,有一个铁律:每传输一个字节,必须跟一个应答位。所以一个完整的字节传输,其实是 9 个 SCL 时钟周期。
- 前 8 个时钟:传输数据位,MSB 先发(最高位在前)
- 第 9 个时钟:应答位,由接收方控制 SDA
你想想看,如果主机发了 8 位数据后直接拉 STOP 条件,从机根本来不及告诉你数据对不对。这个第 9 个时钟,就是专门留给从机表态的。
关键点:I2C 总线上传输的每个字节,长度必须是 8 位。没有 7 位、9 位这种变体。地址也是 7 位或 10 位,但地址本身也是按 8 位字节传输的(地址左移 1 位,最低位补 R/W)。
我在项目中遇到过一位同事,调试时发现从机总是不响应。抓波形看了半天,发现他发的地址只有 7 位,少了一位。嗯,I2C 协议不认这个,必须凑满 8 位。
4.2 ACK/NACK 机制:从机的「收到」与「拒绝」
ACK 和 NACK 的物理实现很简单:在第 9 个时钟周期,发送方释放 SDA(拉高),接收方拉低 SDA 表示 ACK,保持高电平表示 NACK。
| 信号 | SDA 状态(第9时钟) | 含义 | 常见场景 |
|---|---|---|---|
| ACK | 低电平 | 「收到,继续发」 | 正常数据传输、地址匹配 |
| NACK | 高电平 | 「没收到/拒绝/结束」 | 地址不匹配、读操作结束、从机忙 |
这里有个容易搞混的地方:谁拉低 SDA 表示 ACK? 答案是接收方。主机发送数据时,从机拉低 ACK;主机读取数据时,主机拉低 ACK。说白了,谁收数据谁负责应答。
避坑指南:我曾经在一个项目里,主机读从机数据时忘了在第 9 个时钟拉低 SDA 做 ACK。结果从机以为主机不要数据了,直接停止发送。波形上看,主机读到的全是 0xFF。后来查了三天才发现是主机 ACK 没拉。记住:读操作时,主机必须在每个字节后给 ACK,直到最后一个字节给 NACK 表示读完了。
4.3 从机时钟拉伸(Clock Stretching)
时钟拉伸是 I2C 协议里一个很特别的设计。它允许从机在需要时「拖住」时钟线,让主机等一等。
具体做法是:从机拉低 SCL 线,主机检测到 SCL 被拉低后,必须停止时钟,直到从机释放 SCL。
为什么会这样?我举个例子。你有个 I2C 温度传感器,它内部测量温度需要 100ms。主机发完「启动测量」命令后立刻要读结果,传感器还没算完呢。这时候传感器就可以拉低 SCL,告诉主机:「别急,我还在算,算完了我放你走。」
个人经验:我调试过一个气压传感器,它的数据手册里明确写了「最大时钟拉伸时间 500μs」。但实际测试时,某些批次芯片拉伸时间到了 1.2ms。主机 I2C 控制器的超时设置是 1ms,结果频繁超时。最后我把主机超时改到 2ms 才稳定。所以选型时一定要留余量,别卡着上限用。
4.4 完整传输流程:从 START 到 STOP
把上面这些串起来,一个完整的 I2C 写操作流程是这样的:
- 主机发送 START 条件
- 主机发送 7 位地址 + R/W(写 = 0),共 8 位
- 从机在第 9 个时钟拉低 SDA 应答(ACK)
- 主机发送第一个数据字节(8 位)
- 从机应答(ACK)
- 主机发送第二个数据字节(8 位)
- 从机应答(ACK)
- ... 重复直到数据发完
- 主机发送 STOP 条件
读操作类似,只是 R/W 位为 1,且主机在最后一个字节后给 NACK 表示读完了。
4.5 知识结构图:I2C 数据传输核心逻辑
下面这张图把字节传输、ACK/NACK、时钟拉伸的关系画清楚了。建议你保存下来,调试时对照着看。
4.6 实际调试中的常见问题
说了这么多理论,咱们来点实战的。我总结了几个我在调试 I2C 时踩过的坑:
- NACK 后不停止:有些新手写的代码,从机 NACK 了还继续发数据。协议上 NACK 后主机应该发 STOP 或重新 START。我曾经见过一个设备,NACK 后继续发数据,结果从机直接锁死了。
- 时钟拉伸超时处理:不是所有从机都支持时钟拉伸,也不是所有主机都支持。如果你的主机不支持时钟拉伸,碰到会拉伸的从机,通信就会卡死。我建议你在主机侧加一个超时计数器,SCL 被拉低超过一定时间(比如 10ms)就强制复位总线。
- 应答位采样点:第 9 个时钟的采样点很关键。主机必须在 SCL 高电平时采样 SDA。如果采样点偏了,可能把 ACK 误判成 NACK。这个在低速下没问题,高速(400kHz 以上)时就要注意了。
个人习惯:我调试 I2C 时,逻辑分析仪是必备的。我会把触发条件设为「NACK」或「SCL 低电平超时」,这样能快速抓到异常波形。另外,我习惯在代码里把每个 I2C 操作的结果(ACK/NACK)都打印出来,配合波形一起看,定位问题快很多。