上周帮人看一块传感器板现象很典型主控日志刷i2c read failed, ack? no但用万用表量 SCL 和 SDA 都有 3.3V上拉电阻也在地址来回换了好几个依旧读不回寄存器。接上示波器想看看波形结果又耗了一个多小时——不是总线没波是我触发条件没选对老看不见完整的 START 条件。事后复盘I2C 这种两条线的低速接口排查完全有固定路径先静态再动态最后协议层。按这个顺序走五分钟能定位的问题绝不用五十分钟。这篇就把我从万用表、示波器到 ACK 判断的完整流程写清楚新手可以直接照做老手也能对照查漏。1. 排查前先想清楚三条链路三种工具1.1 静态链路万用表的 30 秒体检I2C 出问题时我建议先分清是哪个层面的问题。第一层是静态链路也就是总线在不通信时的默认状态。I2C 的 SCL 和 SDA 都是开漏结构必须依靠外部上拉电阻把电平拉高所以空闲状态下两条线都应该等于上拉电源电压常见是 3.3V 或 1.8V。如果其中一条被拉低或者上拉电阻虚焊、阻值异常主机这边发什么命令都是白搭因为从机看到的根本不是合法高电平。静态链路检查不需要示波器万用表就能完成。断电测上拉电阻上电测空闲电压能够在三十秒内排除掉一大半“看起来像通信问题”的物理故障。很多项目里出现 I2C 偶发失败最后查出来是上拉电阻松了或者 PCB 走线被划伤这一类问题在静态阶段就能结束战斗。1.2 动态链路示波器的主场第二层是动态链路指通信过程中 SCL 是否有时钟、SDA 数据跳变是否正常、上升沿是否拖尾以及波形是否满足对应模式下的电气规格。比如标准模式 100kHz 要求信号最大上升时间不超过 1µs快速模式 400kHz 则要求不超过 300ns。如果上拉电阻选得太大或者总线上并联了太多从机设备电容过大波形就会成一条“缓坡”从机在 SCL 高电平采样时可能还没判到正确电平进而漏读数据、产生 ACK 错误。动态链路必须靠示波器看。这里要记住一点I2C 调试不是把探头夹上去就能出结论的触发方式错了可能抓半小时全是噪声。后面我会专门写示波器设置。1.3 协议链路ACK 与数据帧的拼图第三层是协议链路。波形上能看到高低电平但看不到“这是哪个地址”“这字节是什么值”“ACK 到底发没发出来”。协议层的问题要靠逻辑分析仪解码或者靠人眼一帧一帧数波形的时钟周期。例如主机发 7 位地址 0x3C写方向时第 8 位为 0实际总线字节是 0x78。如果程序里把地址当 8 位地址用发出来的就变成 0x3C从机当然不会 ACK。这种错误在示波器上表现为“有波形、但第九拍 SDA 居高不下”而逻辑分析仪解码列表里直接显示没有 ACK定位就非常快。检查层面万用表示波器逻辑分析仪静态电平、上拉、短路最有效能测但浪费判断不直观动态时序、上升/下降沿、频率看不到最有效只能粗看地址、数据、ACK 协议帧看不到人眼可数但慢解码最直观分清三层后工具选择就不会乱。下面按实际排查顺序从万用表开始讲。2. 万用表测 I2C不是量个电压那么简单2.1 断电后先测电阻和短路别带电乱戳我的习惯是万用表阶段分两步第一步是断电测电阻。把板子电源断掉用电阻挡或二极管挡测 SCL 对地、SDA 对地、SCL 与 SDA 之间的阻值。I2C 上拉电阻典型值是 1k、2.2k、4.7k、10k实测读数应该和标称差不多如果读出来只有几十欧或者干脆开路那问题基本锁定了。要特别提醒一下千万别在带电状态下用电阻挡去戳总线。万用表电阻挡内部会输出一个测试电流带电测量时读数没有任何参考意义还可能在双电源系统里额外灌电流造成逻辑芯片闩锁损坏。我见过不止一个工程师拿着表笔在运行中的板卡上乱量量出来一堆乱七八糟的数字越量越糊涂。第二步是断电时用通断挡测引脚间短路尤其是 FPC 排线转接板这类场景SCL 和 SDA 相邻引脚焊锡桥连是常见故障。通断挡发出蜂鸣就说明有短路需要先处理再上电。2.2 上电后量三个关键电压重新上电后我一般量三个电压SCL 空闲电压正常应等于上拉电源电压比如 3.3V。SDA 空闲电压同样应接近上拉电源电压。上拉电源本身确认上拉供电端确实有电而不是只量到总线上的残压。这里有个非常实用的判断点如果 SCL 正常为高电平但 SDA 被拉低到 0V最常见的原因是某个从机处于异常状态正把 SDA 死死拉低。例如 I2C 从机刚上电时内部寄存器初始化异常或者数据线被某个设备占用。也有可能是软件曾经发起过 START 但没有正常结束从机还在等待 STOP总线被卡死。这时万用表读数能直接指导下一步先查谁在拉低再谈时序。如果两条线都在 1V 到 2V 之间的中间值而不是明确的高或低那多半是上拉电阻阻值太大、总线电流不足或者某个端口配置成了弱上拉。这种模糊电压用示波器看会更清楚万用表只能提示这里有异常。2.3 老万用表的两个操作细节现在数字万用表很普及但偶尔还能看到有人用 MF50 这类老指针表。这类表的拨盘档位多而密很容易拨错档位图各个型号还不一样。用之前一定要确认两点一是电阻档位有没有打到正确量程二是测电阻前是否做了“红黑表笔短接调零”。一个细节没做好读数可能差出一个数量级。老表测 I2C 空闲电压时内阻通常较低对总线会有轻微负载所以读到的数值可能比数字表偏低一点。只要不是拿来测高频波形作为静态排查还能用但别指望它去捕捉 ACK 抖动信号。2.4 万用表阶段就能下结论的常见现象到这一步很多问题已经能定位了。下面这几个现象我几乎每次调试都会对照一次测量结果指向原因下一步动作SCL 高、SDA 恒为低从机拉死总线/软件未释放总线枚举每个从机检查异常复位SCL、SDA 都是中间电压上拉阻值过大或弱上拉换上更小的上拉电阻再测上拉电阻开路虚焊或 PCB 断裂补焊、飞线然后复测两条线都正常 3.3V但通信失败故障在动态/协议层上示波器和逻辑分析仪万用表测不到波形也测不到 ACK但它能帮你排除八成物理链路问题。别小看这一步很多“玄学”I2C 故障最后都死在上拉电阻上。3. 示波器测 I2C触发设置决定了你浪费多少时间3.1 接线、量程、带宽限制示波器测 I2C很多人第一步就做错了用一支长接地夹的探头夹在离测量点很远的螺丝孔上结果地线回路太长波形上全是振铃和尖峰。测低速总线时这是最大的噪声来源。正确做法是用探头自带的短弹簧地针尽量让接地回路贴着信号点。量程方面以 3.3V 系统为例垂直档位设在 500mV/div 到 1V/div 比较合适。别忘了确认探头是 1x 还是 10x示波器通道设置要和探头衰减比一致否则屏上读数会差 10 倍。低频 I2C 测量可以在通道菜单里打开 20MHz 带宽限制能滤掉不少高频毛刺让波形更干净不会影响 400kHz 到 1MHz 的有效信号。3.2 触发源选 SDA 下降沿一抓一个准如果只抓 I2C 通信过程触发源建议选SDA 下降沿而不是 SCL。原因很简单I2C 的 START 条件是 SCL 高电平时 SDA 从高变低SDA 下降沿就是每一帧通信的开始。用 SDA 下降沿触发探头一碰到总线每次通信开始都会稳定触发屏幕上必然能看到完整一帧。如果用 SCL 做触发源抓到的往往是时钟中段虽然也能看到波形但地址和 ACK 部分可能已经跑出屏幕还得手动滚动很低效。触发电平设在实际高电平的一半比如 3.3V 系统设 1.6V 左右。如果总线空闲高电平不足 3.3V比如只有 1.8V触发电平也要跟着改成 0.9V 左右。触发模式必须切到Single单次或者至少 Normal不然屏幕上不断刷新根本看不清一帧细节。单次捕获到帧后立刻按下停止扫描慢慢量。3.3 一帧波形的识别START、数据、ACK、STOP抓到一帧后先看大结构起始位置是 SDA 下降沿然后 SCL 开始产生一连串方波。每个字节 8 个时钟后面跟着 1 个 ACK 时钟所以屏幕上会出现“八字一组加一拍”的规律。把光标放在第九拍的高电平位置观察此时 SDA 电平低电平是 ACK高电平是 NACK。标准模式 100kHz 的一个时钟周期是 10µs一帧如果包含地址字节、寄存器地址字节和一个数据字节大概 30 到 40 拍总时长也就 300µs 到 400µs。时间档位设在 50µs/div 到 100µs/div 就能容纳整帧。如果是 400kHz时间档位要密一点20µs/div 左右。还要注意一个细节千万不要用示波器的自动测量“频率”去判断 I2C 是否正常。波形上可能包含大量毛刺和噪声如果误触发了自动测量出的“频率”会变成几百 kHz 甚至几 MHz吓人一跳。看 I2C 波形要以手动光标为主。3.4 只会肉眼看波形不够SCPI/联网也是排查手段如果你用的是带联网功能的示波器比如力科、鼎阳、普源这类支持 SCPI 的型号可以把示波器接上网络后用脚本自动抓波比人盯屏幕高效得多。特别是做老化测试或偶发故障复现时脚本可以让示波器在触发条件满足时自动保存波形。通用思路是这样的把触发条件设为 SDA 下降沿单次触发然后循环查询捕获状态。触发到了就把 CH1 和 CH2 的波形数据读回来存成文件。不同厂家命令有差异名义意思大体相同。我常用的伪命令大概长这样:TRIGger:MODE SINGLE :TRIGger:EDGE:SOURce CH1 :TRIGger:EDGE:LEVel 1.6V :ACQuire:COMPlete 100% :WAVeform:SOURce CH1 :WAVeform:DATA? :WAVeform:SOURce CH2 :WAVeform:DATA?拿实际波形文件再去慢慢分析比在屏幕前等几小时舒服得多。鼎阳这类示波器联网后还能直接 WEB 远程查看界面对调试装置不在手边的场景很管用。4. ACK 为什么是第 9 拍以及它告诉你什么4.1 ACK 的物理过程从机在第 9 拍拉低 SDAACK 是 I2C 协议里最容易理解又最容易被忽略的一环。主机每发出一个字节后会继续产生第 9 个时钟脉冲。在第九个时钟的低电平期间发送方会释放 SDA由接收方把 SDA 拉低到第九个时钟的高电平采样时总线保持低电平这就是 ACK。如果接收方没有拉低SDA 会靠上拉电阻回到高电平主机在第 9 拍看到高电平就认为是 NACK。这样理解就够了ACK 是接收方用自己的低电平向主机报告“我收到了”。所以示波器上判断 ACK 不要看 SDA 的下降沿要看第九个 SCL 高电平期间 SDA 是不是低电平。这里有个常见误解有人以为 ACK 是主机发出的实际上地址字节和数据字节的 ACK 来源不同。主机发地址后由从机回 ACK主机写数据时也由从机回 ACK主机读数据时前几个字节由主机回 ACK最后一个字节主机主动不回 ACK以此告诉从机“不要再发了”。把这几者的方向搞清楚很多问题立刻有解。4.2 地址阶段无 ACK地址、电平、复位三个方向地址字节后面没有 ACK是最典型的 I2C 故障。遇到这种情况按三个方向排查。第一地址算错。7 位地址和总线字节差一位。比如从机手册写着 7 位地址 0x1D写方向是 0x3A。如果程序直接填了 0x1D 作为 8 位地址总线发出去就成了 0x3A从机当然不理你。很多触摸芯片比如 GT911 这类还支持硬件引脚电平切换地址硬件上和软件里必须一致否则首地址就会无 ACK。第二电平不匹配。主机是 3.3V从机是 1.8V中间如果没有电平转换从机看到的信号可能超过自己的耐压也可能把高电平识别不准导致无 ACK。低功耗传感器板特别喜欢出现这种混压组合。第三从机没复位好。部分从机需要先拉复位引脚或者要等电源稳定几百毫秒才就绪。上电时序不满足从机还在复位中主机发地址过去自然没有 ACK。用示波器看主机命令和从机供电的时序关系就能确认。4.3 数据阶段无 ACKEEPROM 写入和寄存器不存在地址阶段 ACK 正常数据阶段反而 NACK这类问题也很常见。最典型的是 EEPROM 写入。AT24C 系列这类 EEPROM 在内部写周期完成前不会响应新的写命令所以如果主机连续写入第二个字节就可能收到 NACK。正确处理是等写周期结束再发下一条或者忽略一次 NACK 后重新轮询。另一种情况是主机写了从机不存在的寄存器地址。很多传感器芯片只实现了部分寄存器访问未定义地址时从机在数据阶段直接 NACK。这个不是说总线坏了而是你的软件寄存器表匹配错了。4.4 手动 ACK用 GPIO 模拟第九拍拉低判断谁是“装死”的一方调试陷入僵局时我经常用“手动 ACK”的办法。思路是用主控的 GPIO 直接模拟 I2C或者在主机代码里把 ACK 检测改成强制拉低人为在第九拍把 SDA 拉到低电平然后再看从机后续反应。这个方法能快速区分问题在主机的 ACK 检测逻辑还是从机确实没回应。如果强制拉低后从机后续给出的数据还是乱码说明总线物理层或从机状态有问题如果强制拉低后一切变正常那就说明主机在 ACK 采样时机上慢了半拍错过了从机早早就拉低的窗口。4.5 主机主动 NACK 不一定是坏事最后说一个新手经常误判的点主机在读取最后一个字节时会主动不回 ACK也就是发 NACK然后发 STOP。这是标准操作不是错误。如果主机每个读字节都回 ACK从机会一直输出数据导致多读一个字节、寄存器指针混乱。示波器或逻辑分析仪上看到最后一拍是高电平先检查这是不是主机主动 NACK而不是从机失去响应。判断依据很简单看 STOP 位置。主机主动 NACK 之后紧跟 STOP且整帧没有异常停顿那就是正常结束。5. 逻辑分析仪把波形“翻译”成协议帧5.1 采样率和通道选择的实际标准逻辑分析仪和示波器最大的区别是不擅长看模拟波形极擅长把数字协议解码成可读列表。测 I2C 时采样率不需要太高但对通道数有要求。常见 8 通道 USB 逻辑分析仪就够用CH0 接 SCL、CH1 接 SDA其余通道留给以后扩展。采样率建议至少设到 10MS/s 以上。I2C 快速模式 400kHz 时一个位宽只有 2.5µs10MS/s 一个位周期能采 25 个点足够稳定解码。如果总线还挂了一些低频传感器采样率低到 1MS/s 也能勉强看但边缘噪声可能造成误识别所以宁高勿低。5.2 接好线设好阈值选对解码器逻辑分析仪接线比示波器简单但接地必须可靠公共地不接解码出来的完全是乱码。信号线不区分正负接反了其实也能测只是解码列表里 SCL/SDA 对调会出现异常。阈值设置要按实际电平来。3.3V 总线阈值设在 1.65V 左右1.8V 总线设在 0.9V 到 1.0V不能一律按 TTL 1.5V 去判断否则低压总线的数据可能被误读。选解码器时直接用 I2C 协议族把 SCL 通道指向 CH0SDA 通道指向 CH1其余默认。5.3 看解码列表从地址到 ACK 一目了然解码开始后重点看协议解析列表而不是原始波形。列表里通常有几列起始、地址、读写方向、数据、ACK 状态。以 EEPROM 读操作为例解码结果会像下面这样序号内容ACK 状态1Start-20xA0地址写ACK30x00寄存器地址ACK4Start重复起始-50xA1地址读ACK60x55读出数据NACK主机主动7Stop-看到这样的列表大部分疑问五分钟内就解决了。如果第二步没有 ACK问题在从机响应如果第五步没有 ACK问题在读地址配置或从机状态如果数据全是 0xFF那要考虑 SDA 上拉或从机没真正输出数据。5.4 自由数据模式和 PMBus 的注意点逻辑分析仪使用中还有两个容易踩的坑。第一个是 I2C “自由数据模式”也就是从机在收到起始条件和地址后不按“寄存器地址数据”的方式交互而是连续往外吐数据。常见于某些传感器和加了自动递增读模式的芯片。这种模式下逻辑分析仪解码列表里会看到地址后没写寄存器地址直接跟一长串数据看起来像协议缺失其实是从机特性别误判成总线故障。第二个是 PMBus。PMBus 物理层和 I2C 兼容但它多了一整套命令码、PEC 校验和 SMBus 时序要求。如果用普通 I2C 解码器硬解 PMBus会发现多出好几个字节而且校验字节看起来很“多余”。Linux 里有的 PHY 芯片不走 MDIO 而是通过 I2C/PMBus 去访问寄存器就经常遇到这种误解。此时建议换用支持 PMBus 或 SMBus 的解码器或者手动把附加字节剥掉分析。6. 五个真实故障案例波形背后藏着什么6.1 SDA/SCL 接反逻辑分析仪解码全是乱码有一回排查一块 OLED 驱动板SSD1306 怎么都点不亮I2C 扫描一个设备都找不到。用示波器看两条线上都有波形但 SDA 的跳变和 SCL 的上升沿总是不合拍。用逻辑分析仪一解列表全是错误帧。后来核对原理图才发现FPC 座子上 SDA 和 SCL 的丝印标反了PCB 上实际接反。这类问题在手工样板、转接板上很常见。用示波器看时可以这样判断I2C 通信期间SCL 上应是有规律的时钟脉冲SDA 上的跳变频率看起来更高、更随机。如果 CH1 上满是低频规矩方波CH2 上也规矩得跟时钟一样那大概率是接反了。调换两个通道的物理位置或软件映射问题立刻消失。6.2 10k 上拉拖出 2.5µs 上升沿100k 总线卡在规格边缘另一块板子主机频率只有 100kHz总线速率不高但偶尔读写 EEPROM 失败。示波器波形一放大SCL 上升沿非常缓慢实测 2.5µs远超标准模式 1µs 的上限。为什么总线上一共挂了五个从机加上排线分布电容总线总电容超过 250pF而上拉电阻又用了 10kRC 时间常数算下来就是 2.5µs 左右。解决办法是把上拉电阻从 10k 改成 2.2k同时把没必要的长排线剪短。改动后上升沿降到 400ns 以内读写不再失败。普适经验是总线设备多或线长超过 20cm 时优先用 2.2k 或 3.3k 上拉别迷信 10k 省电。6.3 从机拉长时钟致主控超时波形里多出一段“停留”有些传感器支持时钟拉伸也就是从机在准备数据时会把 SCL 拉低一段时间主机要一直等待直到 SCL 释放。这个机制本身是合法的但如果主控的 I2C 控制器超时时间设置太短就会在等待期间报超时错误。示波器上很好识别正常的 SCL 是一串规则方波但这时候你会看到方波中间突然有一段很长的低电平宽度是普通周期的好几倍甚至几十倍。SDA 在高电平位置保持不变。看到这个波形就不再怀疑硬件直接去查主控 I2C 控制器对时钟拉伸的支持和超时阈值把超时调到从机手册要求以上。6.4 示波器测 ADC 电压反而变高先怀疑你的地线有一次同事说“示波器打开 ADC 后电压变高了”本应 1.8V 的输入屏上稳定显示 2.5V 甚至更高。第一反应是 ADC 坏了但拔掉示波器探头后板子工作正常。问题出在测量回路他用了一根很长的鳄鱼夹地线夹在另一块 PCB 的螺柱上地回路面积被拉得很大环境中的开关电源噪声全被串进来。示波器测出来的不是真实的直流 1.8V而是叠加了高频共模噪声后的平均效果。换短地针把带宽限制设为 20MHz再测一次读数稳稳落在 1.8V。测量高频共模噪声时建议再从通道设置里查看交流耦合下的峰峰值能更直观地看到噪声幅度。6.5 I2C HID 设备代码 12不是波形问题别盲目调线最后一类要单独说设备管理器里 I2C HID 设备报“找不到足够资源可以使用代码 12”。很多人第一反应是拿示波器去量 I2C 总线实际上这基本不是信号问题。代码 12 是 Windows 给设备分配资源失败常见原因包括 BIOS 里的 I2C 控制器/中断资源与其他设备冲突、芯片组驱动版本不匹配、或者电源管理策略把设备禁用。处理顺序是先看设备属性里的资源页面找冲突项然后更新 BIOS 和芯片组驱动再关掉相关设备的“允许计算机关闭此设备以节约电源”选项。如果还不行尝试在 BIOS 里重置 I2C 控制器设置。这一步逻辑分析和示波器都帮不上忙别在信号上浪费时间。最后给自己留个“收工动作”这些流程走下来我自己养成了一个固定习惯。每次定位完 I2C 问题我会在调试记录上写下四个数字空闲电压、上拉阻值、总线频率、ACK 状态。等项目过几个月再出问题翻记录就能快速排除是否换了物料或者有没有人在别的模块上改过上拉。如果你也经常跟 I2C 打交道我建议你按“万用表静态检查、示波器看时序、逻辑分析仪看协议”这个顺序练习三次。第二次和第三次你会发现大部分问题根本不需要同时动用三台仪器。两根线而已耐心一点就好。
