1. I2C协议基础回顾:物理层、协议层、起始/停止条件、数据有效性、应答机制
各位同学,咱们正式开始这门课之前,先把I2C协议的老底翻出来晒一晒。你可能会说:“I2C基础谁不会啊?” 嗯,我当年也是这么想的。直到有一次在多主模式下总线死锁,示波器抓了一整天波形,最后发现是起始条件时序不满足从机要求——从那以后,我每次调试多主系统,都会老老实实回头检查物理层和协议层的基础。
说白了,I2C就两条线:SCL(时钟线)和SDA(数据线)。但就是这两条线,玩出了花。咱们这一章把物理层、协议层、起始/停止条件、数据有效性、应答机制这五个核心点彻底讲透。
本章核心脉络:物理层决定电气特性 → 协议层决定通信规则 → 起始/停止条件决定帧边界 → 数据有效性决定采样窗口 → 应答机制决定传输可靠性。这五层缺一不可,多主模式下的所有坑,几乎都跟这五个点有关。
1.1 物理层:两条线的大学问
I2C的物理层,说白了就是开漏输出加上拉电阻。SCL和SDA都是双向的,任何设备都可以拉低它们,但没人能主动拉高——只能靠上拉电阻把电平拉回高。
这就引出了一个关键特性:线与逻辑。只要有一个设备拉低总线,总线就是低电平。所有设备都释放了,总线才回到高。你想想看,这个特性就是多主仲裁的基础。
实战经验:上拉电阻的取值很讲究。我见过太多工程师直接抄参考设计用4.7kΩ,结果在400kHz高速模式下波形惨不忍睹。标准模式(100kHz)用4.7kΩ~10kΩ没问题,快速模式(400kHz)建议用2.2kΩ~4.7kΩ,高速模式(3.4MHz)得上1kΩ左右。具体算一下总线电容和上升时间,别偷懒。
| 参数 | 标准模式 (100kHz) | 快速模式 (400kHz) | 高速模式 (3.4MHz) |
|---|---|---|---|
| 上拉电阻典型值 | 4.7kΩ ~ 10kΩ | 2.2kΩ ~ 4.7kΩ | 1kΩ ~ 2.2kΩ |
| 最大上升时间 | 1000ns | 300ns | 120ns |
| 总线电容上限 | 400pF | 400pF | 100pF |
注意:多主模式下,每个主机的SCL和SDA引脚必须是开漏输出,绝对不能推挽输出。我曾经遇到一个同事把GPIO配成了推挽,结果两个主机同时发送时直接短路,芯片冒烟了。嗯,这个教训挺深刻的。
1.2 协议层:帧结构是通信的骨架
I2C的协议层,核心就是帧结构。每一帧包含:起始条件 → 7位从机地址 + 读写位 → 应答位 → 数据字节 + 应答位(重复) → 停止条件。
这里有个细节:地址是7位,但实际发送时是8位——高7位是地址,最低位是读写方向(0=写,1=读)。所以你在数据手册里看到的0x50其实是7位地址左移1位后的结果,别搞混了。
帧结构速记:S + [7位地址 + R/W] + ACK + [8位数据 + ACK]×N + P
S = 起始条件,P = 停止条件,ACK = 应答位(低电平有效)
1.3 起始/停止条件:总线的“发令枪”和“终止符”
起始条件(S):SCL为高时,SDA从高切换到低。
停止条件(P):SCL为高时,SDA从低切换到高。
这两个条件有个共同点:SCL必须是高电平。为什么?因为数据采样也是在SCL高电平时进行的,起始/停止条件利用SCL高电平时的SDA变化来标识帧边界,这样就不会和数据传输混淆。
我调试时经常用示波器抓这两个条件。有一次发现从机不响应,仔细一看,起始条件中SCL还没完全变高SDA就拉低了,时序差了那么几十纳秒——从机不认。所以,起始条件的建立时间(tSU:STA)和保持时间(tHD:STA)必须严格满足。
| 时序参数 | 标准模式 | 快速模式 |
|---|---|---|
| tHD:STA(起始保持时间) | 4.0μs | 0.6μs |
| tSU:STA(起始建立时间) | 4.7μs | 0.6μs |
| tSU:STO(停止建立时间) | 4.0μs | 0.6μs |
| tBUF(总线空闲时间) | 4.7μs | 1.3μs |
1.4 数据有效性:SCL高电平时采样
I2C的数据有效性规则很简单:SCL为高电平时,SDA必须保持稳定;SCL为低电平时,SDA允许变化。
为什么这样设计?因为数据是在SCL的上升沿或高电平期间被采样的。如果SDA在SCL高电平时变化,采样值就不确定了。你想想看,如果SCL高电平时SDA抖动了一下,接收方可能采到错误位——这就是噪声导致误码的根源。
我个人的习惯是:在PCB布局时,SCL和SDA尽量走短、走平行,并且远离高频开关信号。如果总线长度超过10cm,建议加串联电阻(22Ω~33Ω)抑制过冲和振铃。
1.5 应答机制:通信的“握手”
应答机制是I2C协议中最容易被忽视但最容易出问题的环节。每个字节(9位:8位数据 + 1位应答)传输完成后,接收方必须在第9个SCL周期拉低SDA表示ACK,或者保持高表示NACK。
应答位的位置:发送方在第8个SCL周期结束后释放SDA,接收方在第9个SCL周期拉低SDA(ACK)或保持高(NACK)。
避坑指南:我曾经在一个项目中,从机因为内部忙,在应答位时没来得及拉低SDA,主机检测到NACK后直接发了停止条件。但问题是,主机没有重试机制,整个通信就断了。后来我加了一个重试逻辑:收到NACK后等待1ms再重发,最多重试3次。这个改动解决了现场80%的通信故障。
常见的应答场景:
- 主机发送地址后:从机ACK表示存在,NACK表示无此设备或忙
- 主机发送数据后:从机ACK表示接收成功,NACK表示不能接收更多数据
- 主机接收数据后:主机ACK表示还要继续读,NACK表示够了,准备停止
多主模式特别提醒:仲裁过程中,失去仲裁的主机必须释放SDA和SCL,并且不能产生应答位。如果失去仲裁的主机还试图拉低SDA做ACK,就会破坏总线上其他主机的通信。我调试时遇到过这种情况,示波器上看到SDA波形异常,最后发现是软件里仲裁退出逻辑没处理好。