2. I2C协议基础回顾:起始条件、停止条件、数据有效性、字节格式与ACK/NACK
各位同学,咱们今天聊点基础但极其重要的东西。I2C协议看起来简单,就两根线——SCL和SDA。但你要是真把它吃透了,后面做多主仲裁、抓包分析才会顺手。我见过不少工程师,上来就调代码,结果波形乱七八糟,连个起始条件都找不对。嗯,咱们先把地基打牢。
2.1 起始条件(S)与停止条件(P)
I2C总线上,所有通信都是从起始条件开始,以停止条件结束。这是总线的“发令枪”和“终止符”。
起始条件(S):SCL为高电平时,SDA从高电平切换到低电平。
停止条件(P):SCL为高电平时,SDA从低电平切换到高电平。
说白了,就是SCL在高的时候,SDA跳变一下。这个跳变的方向决定了是开始还是结束。
关键点:起始和停止条件必须由主机产生。从机只能被动响应,不能主动发起或终止通信。
我个人习惯在逻辑分析仪上先找这两个边沿。如果波形里SDA在SCL高电平时乱跳,那多半是总线冲突或者代码逻辑有问题。我曾经在一个项目中,从机地址写错了,结果主机发完起始条件后,SDA一直拉不低,整个总线卡死。后来用分析仪一看,起始条件之后根本没有ACK,总线一直处于高阻态。
2.2 数据有效性
I2C的数据采样规则其实很直观:
- SCL低电平期间:SDA允许变化(数据准备阶段)
- SCL高电平期间:SDA必须保持稳定(数据采样阶段)
你想想看,如果SDA在SCL高的时候变了,那就会被误判成起始或停止条件。所以,数据必须在SCL低的时候准备好,高的时候锁存。
避坑指南:我曾经调试一个温湿度传感器,读出来的数据总是跳变。抓波形发现,SDA在SCL上升沿附近有毛刺,导致采样错误。后来在SDA上加了个10k上拉电阻,问题就解决了。记住,I2C是开漏输出,上拉电阻的质量直接影响数据有效性。
2.3 字节格式与传输顺序
I2C传输的数据是8位一字节,高位在前(MSB first)。每个字节后面必须跟一个ACK/NACK位。所以,一个完整的字节传输其实是9个SCL时钟周期。
| 位序 | Bit 7 (MSB) | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 (LSB) | ACK/NACK |
|---|---|---|---|---|---|---|---|---|---|
| 功能 | 最高位 | 数据位 | 最低位 | 应答位 | |||||
举个例子,你要发送0x55(二进制01010101),顺序是:0→1→0→1→0→1→0→1,然后等ACK。
注意:地址字节也是同样的格式。7位地址左对齐,最低位是R/W位(0表示写,1表示读)。所以0x50(写)实际上是0xA0左移一位再加0。
2.4 ACK与NACK机制
这是I2C协议里最容易被忽视但又最关键的部分。每个字节传输完后,接收方必须在第9个SCL时钟周期拉低SDA表示ACK,或者保持高电平表示NACK。
- ACK(应答):接收方拉低SDA,表示“我收到了,请继续”。
- NACK(非应答):接收方保持SDA高,表示“我没收到”或“我不想再收了”。
主机怎么知道从机是否存在?就是靠这个ACK。如果主机发完地址字节后,SDA在第9个时钟还是高,说明总线上没有这个地址的从机,或者从机忙。
实战经验:我调试多主系统时,最常遇到的就是ACK丢失。两个主机同时发数据,总线仲裁失败的那个主机就会失去对总线的控制,它的数据字节后面往往跟着NACK。逻辑分析仪上看到连续的NACK,基本可以断定总线冲突了。
2.5 知识结构图
下面这张图把I2C协议的基础框架串起来了,方便你对照理解。
2.6 常见问题与排查思路
搞懂了这些基础,咱们来看看实际调试中会遇到什么坑。
问题1:起始条件发不出去
现象:SCL和SDA一直高,主机拉不低SDA。
原因:总线上有其他设备在占用,或者上拉电阻太大导致上升沿太慢。
排查:用逻辑分析仪看SCL和SDA的静态电平。如果都是高,检查上拉电阻和总线负载。
问题2:ACK丢失
现象:主机发完地址后,SDA在第9个时钟还是高。
原因:从机地址不对、从机未上电、或者从机忙。
排查:先确认地址对不对(注意7位地址和8位地址的区别)。我曾经被这个坑过——手册上写0x50,但那是8位地址,实际7位地址是0x28。
问题3:数据字节错位
现象:读出来的数据跟预期完全对不上。
原因:SCL时钟数不对,或者SDA在SCL高时变化了。
排查:数一下每个字节的SCL脉冲数。正常应该是9个(8个数据+1个ACK)。如果多了或少了,检查代码里的时钟控制逻辑。
好了,这一章的内容就这些。起始条件、停止条件、数据有效性、字节格式、ACK/NACK——这五个概念是I2C协议的基石。你把这些搞清楚了,后面学多主仲裁、看逻辑分析仪波形,才会觉得顺理成章。记住,协议是死的,但总线上的信号是活的。多抓波形,多对比,慢慢就有感觉了。