上周帮同事调一块板子,MCU 通过 I2C 读温湿度传感器,读数永远是 0xFF。他先用万用表量了两根线,SDA、SCL 都能量到电平,觉得总线没问题,可数据就是不对。我过去把示波器探头怼到 SDA 上,触发设为下降沿,抓了一帧波形放大一看:地址字节发完后,第 9 个时钟周期里 SDA 一直是高——从机压根没给出 ACK。这个问题很典型,也暴露了一个常见误区:万用表只能证明总线静态电平正常,I2C 的真正问题经常藏在动态时序和应答位里。所以我把从万用表、示波器到 ACK 识别的一整套排查路径写下来,给同样被 I2C 通信失败折磨过的开发者一个能直接照着做的流程。
1. 为什么先从万用表开始:静态电平、上拉电阻与短路筛查
很多教程一上来就让你掏示波器,但我的习惯是先拿万用表做一轮快速筛查,价格便宜、操作快,而且能把一大批低级问题直接排除掉。示波器和逻辑分析仪是抓动态问题的,但如果你板子上的 I2C 总线压根没上拉电阻,或者 SDA 被焊短路了,上示波器反而容易看得一头雾水。
1.1 万用表能确定的三件事:电平、短路与上拉
第一件事是测量空闲状态下的静态电平。把万用表拨到直流电压挡,黑表笔接 GND,红表笔分别点 SDA 和 SCL。I2C 总线在空闲时两根线都应该被上拉电阻拉到高电平,数值应该接近 VDD。如果量到 SDA 被拉低到接近 0V,说明有设备在占用总线,或者某个从机异常拉死了 SDA。这种情况你直接上示波器,看到的可能是一团乱波形,甚至看不到任何边沿,因为总线从头到尾都是低电平,根本没有数据翻转。
第二件事是断电后的通断测试。这里要强调一下,必须断电,最好把板子的电源完全断开再测。用万用表的通断挡,从主控芯片的 I2C 引脚出发,分别测到每个从机引脚的连续性。板子上多从机共总线时,虚焊、断线、过孔不良都会导致某一路信号缺失。通断测试能在五分钟内把这种物理层问题找出来。
第三件事是测量上拉电阻。断电后,用电阻挡测 SDA 和 SCL 引脚对 VDD 的阻值,对比原理图上的预期值,常见的是 2.2k 到 4.7k。这里有个小坑:如果总线上并联了多个设备,电阻挡量出来的读数会比单个上拉电阻小,因为等效电阻是并联关系。你量到 1k 左右不一定是上拉电阻焊错了,可能只是两个 2.2k 并联的结果。所以这个测量只能做粗略参考,别绝对化。
1.2 万用表测不了动态时序,别让它背锅
万用表本质上是一个平均值工具,它显示的是信号在一段时间内的统计结果,对 I2C 这种边沿触发、事件驱动的协议几乎没有诊断能力。
举个极端例子:总线上一帧数据里 SDA 在高低电平之间来回翻转,万用表会显示一个介于 VDD 和 GND 之间的电压值,比如 1.6V。有些新手看到这个值会以为总线“状态不对”,实际上这完全正常,只是因为信号变化太快,万用表积分出来的平均值落在了中间。反过来,如果总线确实卡死在半电平,万用表也会显示一个中间值,但此时示波器能看到信号根本就没有满幅跳变。所以说,万用表的读数只能回答“高低电平是否存在”,回答不了“边沿是否按时出现、ACK 是否存在”这类动态问题。
1.3 万用表测量时最容易出现的两个误判
第一个误判是带电测电阻。板子还在供电时去测上拉电阻,读数会被电路里其他通路干扰,甚至完全错误。我见过有人带电测出上拉阻值只有几十欧,以为电阻烧了,结果只是 VDD 到 GND 之间有其他低阻通路。正确做法是彻底断电,最好等板子电容放干净再测。
第二个误判是忽略表笔接触电阻。I2C 测试点经常是细走线、过孔或者 QFN 封装的引脚,普通表笔尖很难压稳,稍微一动就接触不良,量出来的电平会随机跳变,导致你误判“总线不稳定”。我的做法是在测试点上直接焊一根短的杜邦线或者用夹子夹住,确保接触可靠。这一点在测小封装芯片时尤其重要,别让接触问题浪费你半小时。
2. 示波器抓波形的三个关键设置:触发、采样率与时基
万用表筛查完,确认静态电平、上拉电阻和通断都没问题之后,才轮到示波器出场。示波器测 I2C 的核心不是把探头一夹然后看波形,而是要让示波器在正确的位置停下来、以足够的分辨率记录数据。触发、采样率、时基这三个设置决定了你抓到的是能定位问题的波形,还是一团没有意义的乱线。
2.1 没有 I2C 触发时,用下降沿触发抓 START
高档示波器通常带 I2C 协议触发选件,可以直接设置从机地址和读写方向,触发到指定帧。但很多入门级示波器没这个选件,这时候最实用的替代方案是:把触发挂在 SDA 上,用下降沿触发。原理很简单,I2C 的 START 条件就是 SCL 为高时 SDA 从高到低跳变,这一跳必然是下降沿。你只要抓到 SDA 的第一个下降沿,接下来跟着的基本就是一帧完整通信。
具体操作上,我建议通道 1 接 SCL、通道 2 接 SDA,这样两根线的时序关系一眼就能看清。触发电平设在 VDD 的一半左右,触发模式选 Normal 或者 Single。总线空闲时间长的板子,用 Single 模式手动触发一次最稳妥,不然示波器可能会被其他边沿反复触发,抓出一堆无关波形。还有一个小技巧:如果示波器支持“释抑时间”(Holdoff),可以设置成稍大于一个字节的时间,比如 100us 左右,这样匹配触发器会跳过之前的边沿,更容易直接停在目标帧上。
2.2 采样率与时基怎么取舍:单帧和间歇故障两套打法
抓单帧波形和抓间歇性故障,对采样率和时基的要求完全不同,我先说结论:以 100k 标准模式为例,SCL 周期是 10us,一个字节加 ACK 总共 9 个时钟周期,大约 90us。抓完整帧,时基放在 20us/格到 50us/格比较合适。采样率至少要有 2MSa/s,也就是每个时钟周期至少采 20 个点,这样才能看清 SDA 在第 9 个时钟的高低状态。
如果你要排查的是偶发故障,比如一小时出现一次通信失败,那就要靠长时基加浅存储深度,或者直接用逻辑分析仪挂机。普通示波器的存储深度一般是 4M 到 10M 点,按 1MSa/s 采样,只能记录大约 4 到 10 秒,对于“几分钟才错一次”的场景远远不够。逻辑分析仪在这方面有天然优势,几十 MSa/s 采样率连续记录几十分钟毫无压力,而且解码 I2C 比示波器更直观。所以我的原则是:单帧、看边沿、量时序用示波器;长时间监控、频繁交互、数 ACK 用逻辑分析仪。两者互补,不是替代关系。
2.3 探头输入电容会悄悄改变上升沿
很多人没注意,示波器探头本身是有输入电容的。普通 10x 无源探头输入电容大约 10 到 15pF,1x 探头更高,可能到几十 pF。I2C 总线靠的是上拉电阻给寄生电容充电产生上升沿,总线电容越大,上升沿越慢。如果你总线上已经承载了多个从机、走线又长,电容本来就接近临界值,探头一接上去,等效电容增加,上升沿会变得更慢,甚至导致原本能工作的总线开始出现偶发错误。
这就产生了一个测量悖论:你接上仪器去测一个“本来有问题”的波形,仪器本身可能让波形变得更糟。不过实际排查中,我不建议一上来就纠结探头电容,因为大多数 I2C 故障的根因不是探头造成的,而是板子本身。只有当你测到的上升沿时间非常接近规格上限时,才需要怀疑探头电容的影响,可以考虑换低电容探头或者用有源探头复核。另外一个细节:测上升时间时,多数示波器默认按 10% 到 90% 定义,但某些 I2C 规格书里用的是 30% 到 70%,对比参数时记得换算,别直接拿数据比大小。
3. ACK 到底长什么样:从“第 9 个时钟”看从机的应答
ACK 是整个 I2C 排查里最关键也最容易看漏的一环。地址发出去之后,从机有没有响应、能不能继续通信,就靠这一位来判断。你不需要完整读出所有数据字节,抓到地址字节和后面的 ACK 位,基本就能判断问题出在“从机不应答”还是“数据阶段出错”。
3.1 从波形上认 ACK 与 NACK:一个字节加第九个时钟
I2C 协议里,主机每发送一个字节(8 个数据位),从机要在第 9 个时钟周期内给出应答。具体表现是:主机在第 8 个数据位结束后释放 SDA,此时 SDA 会变高;紧接着第 9 个 SCL 脉冲的高电平期间,从机把 SDA 拉低并保持到时钟结束,这就是 ACK。如果 SDA 在整个第 9 个时钟期间一直保持高电平,那就是 NACK,表示从机没有响应。
识别 ACK 最靠谱的方法不是看波形长得像不像,而是数时钟。从 START 之后开始数,第一个字节的 8 个脉冲是地址和读写位,第 9 个脉冲就是 ACK 位。常见误判是把某个数据位当成 ACK,尤其当数据位本身就连续几个“1”时,波形上看起来会有一段平台,如果不数时钟很容易看错。我的习惯是把时基放大到每格几微秒,用光标把第 9 个上升沿位置标出来,然后直接读此时 SDA 的电平,高就是 NACK,低就是 ACK,一目了然。
3.2 逻辑分析仪里的“手动 ACK”设置是什么意思
示波器看 ACK 靠肉眼,逻辑分析仪则是靠解码算法自动判断。常见的逻辑分析仪软件(比如 Saleae、DSView、PulseView)在解码 I2C 时,都会按标准协议解析 ACK 位。但某些场景下从机不响应,解码器会在 ACK 处报错并且停止继续解析后面的字节,这时候很多软件提供了一个选项,翻译过来意思类似“手动 ACK”或者“忽略 ACK”。
这个选项的本质是:当软件检测到 NACK 时,仍然强制把当前字节标记为完成,然后继续解析后续字节。调试时这个功能很有用,比如你想看某个从机在 NACK 之后是否还输出了数据、或者主机后续发了什么命令,就可以开启这个选项,让解码不中断。但我要提醒一句:定位问题时别依赖这个功能,它相当于容错处理,会把错误吞掉。我更推荐在设置里开启严格的 ACK 检查,让 NACK 直接标红报错,这样哪个字节出了问题一眼就能看到。
3.3 ACK 异常背后的四类常见根因
从实际排查经验看,ACK 异常基本可以归到四类。
第一类是地址不匹配。I2C 从机地址有 7 位和 10 位两种模式,很多芯片的地址引脚(比如 A0、A1、A2)决定低几位地址,原理图上画得模棱两可,贴片时焊错或者漏焊,导致地址对不上。我记得有一次查一块 GT911 触摸屏的通信失败,量波形时发现主机发的地址和芯片要求的地址差了整整一位,GT911 的地址可以通过引脚配置成不同值,初始化时序不对甚至会让芯片根本不进入有效的 I2C 模式,表现出来就是第一个地址字节之后直接 NACK。
第二类是从机供电、复位或使能问题。很多传感器上电后需要一段时间完成初始化,如果主机在从机还没 ready 时就去读,从机会直接 NACK。另外有些器件有复位引脚、使能引脚,这些引脚电平不对,从机就处于关闭状态,自然不会应答。
第三类是地址冲突。I2C 总线上挂了两个相同地址的从机时,应答会非常混乱,两个从机可能交替拉低 SDA,表现时而 ACK 时而 NACK,甚至总线数据错乱。排查这种问题要用逻辑分析仪长时间采样,看每次应答对应的是哪个设备在驱动总线的电平。
第四类是主机端配置错误。比如 MCU 的 I2C 外设时钟分频配错了,导致实际 SCL 频率远超从机支持的范围,从机跟不上就会 NACK。还有主机发送的寄存器地址、命令字不符合器件手册,从机在数据阶段给出 NACK 作为“拒收”信号。这类问题别死磕硬件,先回去把芯片手册里的寄存器读写流程再对一遍。
4. 完整排查流程:七步从现象直达根因
前面几章其实是把工具和关键概念拆开讲了,这一章我把它们串成一条可复现的流程。这套流程我自己在多个项目里用过,从消费电子到工控板卡都适用,核心思路是:先排除物理层,再观察协议层,最后根据 ACK 定位根因。
4.1 动手前的确认清单:供电、电平域与器件地址
正式测波形之前,有几个信息必须先确认,不然拿到波形也解读不出来。
第一,确认所有相关器件的供电。量 VDD 实际值,很多 I2C 故障其实是电源纹波大或者电压偏低造成的,从机会出现上电后偶发不响应。第二,确认电平域。主控是 3.3V,外部传感器是 1.8V 的话,上拉电阻接在哪个电源域就很关键,SDA 和 SCL 的高电平不能超过从机的 VDD 承受范围。第三,查原理图,确认每个从机的 I2C 地址和读写位,很多芯片地址由引脚上下拉决定,这个信息必须从具体板子上去核对,不能只依赖芯片默认值。第四,确认你用的时序模式是标准 100k、快速 400k 还是快速+ 1M,这决定了后面时序参数的判定基准。
4.2 七步排查链路的具体操作
下面这七步是实际操作链路,每一步都有明确判定条件和下一步去向:
- 万用表直流挡测 SDA/SCL 空闲电平。两个都接近 VDD 则通过;任何一个为低,先查哪个设备拉低了总线,常见原因是从机死锁、上拉电阻没焊、或者 GPIO 配置错误。
- 断电后测上拉电阻和引脚通断。阻值明显异常或者某一段不导通,先修物理层,修完回到第 1 步重新测。
- 示波器抓一帧波形,定位 START 和 STOP。确认波形确实是一帧完整的 I2C 事务,排除抓错或者触发位置不对的问题。
- 数地址字节的 8 个数据位,核对地址和读写位是否正确,然后看第 9 个时钟的 ACK/NACK。
- 如果 ACK 正常,继续核对数据字节的 ACK 和最后的 STOP 是否完整。数据阶段 NACK,多半是寄存器地址或命令字不对。
- 如果地址字节后直接 NACK,按 3.3 节里的四类原因逐项排查:地址配置、供电/复位、地址冲突、主机时钟频率。
- 如果问题不是每次必现,用逻辑分析仪长时间挂机采样,记录多次事务的时间戳,寻找偶发错误的规律。
这套流程的关键是每一步都要有明确结论,不要跳到下一步的时候还带着“这个可能没问题吧”的念头。
4.3 一个 AT24C02 读失败的完整复盘
拿最常见的 EEPROM 为例,AT24C02 的 I2C 地址是 1010 加 A2/A1/A0 三个引脚电平再加读写位。写操作时控制字是 0xA0,读操作时是 0xA1。有一次板子读 AT24C02 总是失败,我按上面流程走:万用表量空闲电平正常,上拉电阻正常,示波器抓波形发现主机完整发出来了 0xA0(10100000),地址位没问题,第 9 个时钟 SDA 却是高,NACK。
按 NACK 的排查顺序,先检查供电,正常;再检查地址引脚,结果发现 A2/A1/A0 三个引脚全部悬空,既没接高也没接低,手册里要求必须明确接入固定电平。补焊之后,再抓波形,第 9 个时钟 SDA 稳稳拉低,ACK 出来了,读写恢复正常。这类问题就是典型的静态电平和上拉都正常、但 ACK 才暴露出来的例子,你不看 ACK 只看万用表,永远找不到根因。
5. 时序余量、上拉计算与总线负载:藏在波形背后的底层细节
很多时候,I2C 波形“看起来”没问题,但通信就是不稳定的偶发失败。这时候问题往往出在时序余量和总线负载上。这一章讲的是那些不直接体现在 ACK 上、却能让整个通信系统处在崩溃边缘的底层细节。
5.1 100k 模式下的时序基准:建立时间和保持时间怎么量
I2C 规范定义了不同速率模式下的时序参数,我整理了最常用的三档,方便排查时对照:
| 参数 | 标准模式 100k | 快速模式 400k | 快速+ 1M |
|---|---|---|---|
| SCL 低电平时间 tLOW | 最小 4.7us | 最小 1.3us | 最小 0.5us |
| SCL 高电平时间 tHIGH | 最小 4.0us | 最小 0.6us | 最小 0.26us |
| 上升时间 tr(10%-90%) | 最大 1.0us | 最大 0.3us | 最大 0.12us |
| 下降时间 tf | 最大 0.3us | 最大 0.3us | 最大 0.12us |
| 数据建立时间 tSU;DAT | 最小 250ns | 最小 100ns | 最小 50ns |
| 数据保持时间 tHD;DAT | 最小 0ns | 最小 0ns | 最小 0ns |
测量建立时间和保持时间时,要把示波器两个通道分别接 SDA 和 SCL。数据建立时间指的是 SDA 变化到 SCL 上升沿之间的时间,数据保持时间是 SCL 下降沿之后 SDA 保持的时间。很多时候从机采样出错、偶发读到错误数据,就是因为主机在 SCL 上升沿附近才改变 SDA,建立时间不够,从机捕捉到了不稳定的数据位。示波器光标一量就能量化,别只靠肉眼判断“应该来得及”。
另外注意,MCU 外设配置的 SCL 频率和实际抓到的 SCL 频率经常不一致。有些芯片分频配置写的是 100k,但实际因为系统时钟的整除关系,抓出来是 120k 甚至更高。这类超规格运行在多数情况下能工作,但一旦总线电容变大或者从机响应变慢,就会变成头疼的偶发 NACK,所以波形抓出来之后,建议顺手用示波器频率计测量一下实际 SCL 频率。
5.2 上拉电阻的选择:从最小值到最大值的计算路径
上拉电阻不是随便选一个就行,它的上下限都有约束,搞清楚计算逻辑,排查时会更有针对性。
最小值约束来自 I2C 规范中 VOL 的要求,也就是从机或主机在拉低 SDA 时,引脚上的电压必须低于 0.4V(在 3mA 灌电流条件下)。如果上拉电阻太小,拉低时的电流过大,引脚电压可能抬升超过 0.4V,逻辑低电平就不可靠了。计算公式是:Rmin = (VDD - 0.4V) / 3mA。以 3.3V 系统为例,Rmin 大约是 (3.3 - 0.4) / 0.003 = 967Ω,取整后用 1k 或 1.2k 都行。
最大值约束来自上升时间要求。总线上的等效电容 Cbus 和上拉电阻 R 构成 RC 充电回路,上升时间大约等于 0.8473 乘以 R 乘以 Cbus。以标准模式 tr 最大 1us 为例:Rmax = 1us / (0.8473 × Cbus)。如果总线上有三个从机加上走线寄生电容,Cbus 按 200pF 估算,Rmax = 1us / (0.8473 × 200pF) ≈ 5.9k。所以 4.7k 上拉在这个条件下没问题,但如果总线电容到了 400pF,4.7k 的上升时间就可能超规格了。这也是为什么长走线、多从机系统里,很多工程师会主动把上拉从 4.7k 降到 2.2k。
5.3 总线电容、多从机与扩展器:哪些事会让波形悄悄恶化
I2C 总线上每多挂一个从机,就会多几百皮法的引脚电容,走线过长、过孔过多也会增加寄生电容。电容变大、上升沿变慢的后果是:SCL 高电平时间可能被蚕食,SDA 的数据建立时间被压缩,从机在边沿处采样就容易出错。
多个从机还有一个隐患是地址冲突。I2C 没有片选引脚,所有从机靠地址区分,两个设备用了相同地址,总线必然出问题。排查手段是逐个从机扫描地址,确认每个地址只有一台设备应答。
另外,设计上用 I2C 多路复用器或扩展器(比如 TCA9548)能解决地址冲突,但也带来了新变量。扩展器本身也是一个 I2C 从机,它在子通道上的信号质量取决于子总线的电容和上拉配置。我踩过一个坑:切换通道后立即发数据,结果子总线上第一个字节直接 NACK,后来发现是通道切换后总线稳定需要一点时间,加了几毫秒延时就好了。调试这类扩展芯片时,先抓主总线的 ACK,确认扩展器本身响应正常,再抓子总线的波形,分步骤定位,别混在一起猜。
5.4 别把 PMBus 和 HID over I2C 当普通 I2C 排
最后提两个和 I2C 容易混淆的场景,遇到它们时要先认清协议边界,不然会浪费大量时间。
PMBus 电气上基于 I2C,但有自己的一套命令集和时序规则。它要求发送方在每帧数据里带上 PEC 校验字节,支持 ALERT 引脚事件,而且 SCL 最低频率限制在 1kHz 以下(有些规范要求不能低于 1kHz)。如果你拿裸 I2C 的方式去排查 PMBus,看到 PEC 字节可能会当成未知数据位,把 ALERT 当成普通 GPIO。正确做法是先把 PMBus 的命令帧格式搞清楚,或者用支持 PMBus 解码的逻辑分析仪协议解析插件。
另一个是 HID over I2C,也就是 Windows 系统里触摸屏、键盘等设备通过 I2C 传输 HID 报文。如果设备管理器里报“I2C HID 设备找不到足够资源可以使用(代码 12)”,多数情况下不是总线波形问题,而是 I2C 控制器驱动、ACPI 资源分配、电源管理策略出了问题。这种问题你拿示波器测 I2C 波形大概率看不出异常,应该先查系统的设备资源和驱动状态,别把波形排查用在错误的层级。
顺带澄清一个概念:I2C 是主机驱动的总线,从机不能主动往总线上发数据,所以别指望从机“主动更新主机寄存器”。如果看到某些资料里提到从机主动通知,那通常是在 SMBus/PMBus 场景下通过 ALERT 引脚实现的事件机制,并不是 I2C 标准协议允许的从机主动传输。这个边界理清楚,很多“为什么从机不发数据”的疑问自然就解开了。
最后分享一个我自己的习惯:抓 I2C 波形一定要先把帧头帧尾找出来再谈其他。很多人看到一串看似规则的脉冲就开始猜协议,结果把 STOP 当数据位、把 ACK 当地址位,越猜越乱。先把 START 和 STOP 在波形上标出来,再数每个字节的 9 个时钟,ACK/NACK 一目了然,很多“诡异”问题其实只是没数清楚时钟而已。希望这套流程能帮你少走一圈弯路。