I2C协议时序分析与中断处理波形故障定位实战 - 第1节
1.1 物理层特性:SDA/SCL 与上拉电阻
I2C 总线物理上就两根线:SDA(数据线)和 SCL(时钟线)。
这两根线都是开漏输出。什么叫开漏?说白了,芯片内部只能把线拉低到 GND,不能主动拉高。要拉高,全靠外部上拉电阻。
我刚开始做 I2C 时,总觉得开漏设计很麻烦。后来踩过几次坑才明白——开漏是 I2C 能支持多主设备、能实现时钟拉伸的根本原因。你想想看,如果每个设备都能主动推高电平,那多个设备同时驱动时,总线不就打架了吗?
核心要点:开漏 + 上拉电阻 = 线与逻辑。任何设备拉低总线,总线就是低电平;所有设备都释放,总线才回到高电平。
上拉电阻怎么选?
上拉电阻的取值直接影响通信质量和功耗。我一般遵循这个原则:
- 标准模式(100 kHz):4.7 kΩ ~ 10 kΩ
- 快速模式(400 kHz):1.5 kΩ ~ 4.7 kΩ
- 高速模式(3.4 MHz):几百 Ω ~ 1 kΩ
电阻太小,灌电流太大,功耗高;电阻太大,上升沿变缓,信号质量差。我在一个项目中用过 100 kΩ 上拉,结果总线根本没法正常工作——上升沿慢得像蜗牛爬。
我的经验:如果总线上挂的设备多(超过 8 个),或者走线较长(超过 10 cm),适当减小上拉电阻。我习惯先按 4.7 kΩ 起步,再用示波器看上升沿,调到满意为止。
1.2 协议层概述:主从架构
I2C 是典型的主从架构。主设备产生时钟、发起通信;从设备响应地址、收发数据。
一个总线上可以挂多个主设备和多个从设备。但同一时刻,只能有一个主设备控制总线。为什么?因为总线是开漏的,多个主设备同时驱动就会产生冲突——这就是仲裁机制要解决的问题。
我记得有一次调试一个多主系统,两个主设备同时发起通信,结果数据全乱了。后来查了几天才发现,其中一个主设备的仲裁逻辑有 bug。嗯,从那以后我每次做多主设计,都会在逻辑分析仪上盯着仲裁过程看一遍。
7 位寻址 vs 10 位寻址
I2C 的地址分两种:7 位和 10 位。绝大多数器件用 7 位地址,够用。
| 特性 | 7 位寻址 | 10 位寻址 |
|---|---|---|
| 地址范围 | 0x00 ~ 0x7F(128 个) | 0x000 ~ 0x3FF(1024 个) |
| 保留地址 | 0x00(广播)、0x01~0x07 等 | 与 7 位兼容 |
| 可用地址数 | 约 112 个 | 约 1008 个 |
| 帧格式 | 1 字节(地址 + R/W) | 2 字节(首字节 11110xx + 次字节) |
| 常见场景 | 传感器、EEPROM、ADC/DAC | 多路复用器、复杂 SoC |
7 位地址的帧格式很简单:主设备先发一个起始条件,然后发 7 位地址 + 1 位读写标志(0 写、1 读),再等从设备的应答位。
10 位地址稍微复杂一点:首字节的前 5 位固定为 11110,后 2 位是地址的高 2 位,再加上 R/W 位;然后发第二个字节,包含地址的低 8 位。
注意:10 位地址的从设备,在应答机制上跟 7 位设备不太一样。我曾经遇到一个 10 位地址的传感器,手册上没写清楚应答时序,结果我按 7 位的逻辑去读,死活读不到数据。后来用示波器一帧一帧地抓,才发现它需要两个地址字节都应答完才能继续。
1.3 知识体系总览
下面这张图把 I2C 协议的基础框架串起来了。我建议你先看一遍,有个整体印象,再往下细抠每个模块。
1.4 常见误区与避坑指南
误区一:上拉电阻越大越好
我见过有人用 100 kΩ 上拉,觉得省电。结果总线上升沿超过 1 μs,400 kHz 模式下根本没法用。上拉电阻不是越大越好,要平衡功耗和信号完整性。
误区二:地址冲突只查一次就够了
同一个 I2C 总线上,两个从设备地址不能相同。但有些器件有多个可选地址引脚,焊接时容易搞错。我习惯在 PCB 打样回来后,先用 I2C 扫描程序扫一遍所有地址,确认没有冲突再开始调试。
误区三:开漏输出可以直接连 3.3V 和 5V 设备
理论上可以,但要注意上拉电阻接的电压。如果主设备是 3.3V,从设备是 5V,上拉电阻接 5V 的话,3.3V 设备可能承受不住 5V 的高电平。我一般用电平转换芯片,或者用 MOSFET 做双向电平转换。
1.5 小结
这一章我们聊了 I2C 的物理层和协议层基础。说白了,I2C 就两根线,开漏输出加上拉电阻,主从架构加 7 位或 10 位寻址。看起来简单,但每个细节都有坑。
我个人觉得,理解开漏和上拉电阻的物理原理,比死记硬背时序参数更重要。因为只有懂了底层,你才能在示波器上看出问题在哪,才能快速定位故障。