I2C信号排查:万用表、示波器与ACK位判读实战指南

发布时间:2026/9/28 14:39:22
I2C信号排查:万用表、示波器与ACK位判读实战指南 做嵌入式这些年凡是调过I2C的几乎都经历过同一个画面传感器读不出数、EEPROM写进去再读全是0xFF、触摸屏第一次能响应第二次就卡在总线上折腾到最后只想把芯片换了。I2C大概是SPI、UART、CAN里物理连线最少的总线SCL和SDA两根线而已可偏偏就是这两根线电气和时序的坑一个比一个深。万用表能帮你确认总线“有没有活着”但抓不到通信细节示波器能抓到完整波形但很多人不知道起始条件在哪、ACK又该从第几个时钟找起。这篇文章就沿着万用表、示波器、ACK这条线把I2C信号的完整排查流程讲清楚适合刚调通第一块板子的新手也适合被NACK困扰的老手用来查漏补缺。1. 排查前先搞清楚I2C信号的三个测试目标1.1 两根线上的“只能拉低”逻辑先别急着上仪器得先把I2C信号到底是什么搞清楚。I2C总线是开漏结构所有器件的SCL、SDA引脚都是开漏输出内部只能把引脚拉到低电平不能主动输出高电平。高电平靠外部上拉电阻从上拉电源VDD“借”过来。你可以把它想成会议室里一个共用的按钮任何人都能把按钮按下去拉低松开以后靠弹簧弹回来上拉电阻把线拉回高电平。这个结构决定了测量时的两个基本判断看一个引脚能不能被拉低能不能顺利释放回高电平。所以排查I2C信号核心就是围绕这两个问题展开哪个设备在拉总线拉低之后有没有正常释放至于数据内容则是通过SCL高电平期间SDA的稳定状态来表达的。1.2 时序的最小骨架起始、地址、ACK、数据、停止I2C一帧通信的基本流程主机拉低SDA产生起始条件然后在SCL上送出地址字节地址字节是7位从机地址加1位读写位共8位。第8位之后紧跟第9个SCL时钟这就是ACK位。从机如果地址匹配并且能接收会在第9个时钟的高电平期间把SDA拉低主机看到低电平就知道从机“应答”了。接下来每传输一个字节都会重复一次“8位数据1位ACK”的结构直到主机发出停止条件。为什么ACK在排查里这么重要因为它是从机对主机唯一的应答通道。通信链路是否打通、地址是否写对、从机是否忙几乎都能从ACK位上看出端倪。很多问题看起来像是“数据不对”但用示波器一看其实是ACK这一位先出了问题。1.3 三个目标对应三套工具排查I2C信号前先想清楚当前要回答的是“哪一个为什么”是怀疑硬件短路或虚焊那用万用表是怀疑时序、电平、上升沿这些模拟量不对那用示波器是想快速知道地址、数据、ACK这些协议内容对不对那用逻辑分析仪或示波器的协议解码。我见过不少新人上来就把示波器探头到处点抓了一堆波形又不知道看哪里。其实只要先按这个思路分层万用表查链路示波器查时域特征解码工具查协议内容再笨的问题也能一步步逼出来。2. 万用表测I2C信号的两个关键步骤静态电阻和空闲电压2.1 断电测电阻先排除短路和开路万用表能做的第一件事是断电状态下测SDA、SCL对地的电阻。把万用表拨到电阻挡或蜂鸣挡一只表笔接板子GND另一只分别点SDA和SCL。正常情况下因为总线上有上拉电阻SDA和SCL对地都不会是0欧通常会显示一个几百欧到几千欧的数值具体大小取决于上拉阻值和并联在总线上的芯片引脚等效阻抗。如果测出来接近0欧且蜂鸣长响说明有器件把总线钳到了地或者PCB上存在桥连、锡渣短路。这时别急着换芯片先把可疑器件的SDA/SCL引脚断开有条件的话挑开串在总线上调试用的0欧电阻每断开一个再测一次蜂鸣消失的那个就是问题源。反过来如果测出来是无穷大说明上拉电阻没焊好、焊盘虚焊或者总线走线断了。注意测电阻一定要断电带电测不仅读数没意义还有可能损坏万用表的输入保护电路。2.2 上电测空闲电压看总线有没有“喘气”断电测完电阻下一步上电用直流电压挡20V量程分别测SCL对地、SDA对地的电压。空闲状态没有通信时两根线都应该被上拉到接近VDD比如3.3V系统里通常能测到3.2V左右5V系统里接近4.8V。如果某个引脚只有0V或者低于0.7×VDD那就说明该引脚要么被某设备拉死要么上拉没接对。这里有个典型的误判场景如果你的主机程序在周期性地扫描总线SDA和SCL上其实一直在跳变万用表表现出来的是一个“平均电压”比如3.3V系统里显示1.6V。很多人在这一步以为自己板子坏了其实总线是好的只是万用表跟不上I2C的速率。遇到这种情况别慌要么把主机代码里的通信循环停掉再测要么直接上示波器看瞬时波形。2.3 用蜂鸣挡和二极管挡快速压缩故障范围万用表还有一个很实用的用法二极管/蜂鸣挡配合“逐个断开”的方法快速定位故障设备。板上挂了好几个I2C从机时如果发现SDA空闲电压不对就用蜂鸣挡测SDA到地同时逐个移除从机的电源或断开其SDA引脚直到蜂鸣消失。这比盲目换芯片高效得多。另外提醒一句很多板子的SDA和SCL共用一个排阻做上拉排查时先量排阻公共端到VDD是否导通再分别量两路到SDA/SCL的通断。排阻虚焊在批量板子里不算少见这个细节很容易被忽略。3. 示波器抓I2C波形探头、触发、时基与ACK判读实战3.1 探头接法和补偿波形是真是假一半取决于探头想用示波器看I2C先把探头接对。CH1接SCLCH2接SDA两个探头的地线夹都夹在板子GND上尽量靠近被测点。最怕的是两个探头共用一个很远的GND点地线回路一长测出来的波形会多出明显的振铃尤其是400kHz通信时振铃甚至会被误判成额外时钟。探头挡位建议拨到10x并且先做探头补偿。10x探头输入电容通常在10pF左右1x挡位的输入电容可以到几十甚至上百pF接入后会把I2C信号边沿拉缓看起来像是上拉电阻过大容易误导排查。这个细节实测很坑我曾经在一台老示波器上用了1x探头400k信号上升沿直接变成圆头排查了半天结果是探头问题。3.2 触发和时基让波形稳定“定”在屏幕上抓I2C建议优先用SDA下降沿触发因为起始条件的标志就是SDA在SCL高电平期间从高跳低。把触发源设到CH2SDA触发电平设到电源电压的一半比如3.3V系统设1.65V。触发模式先用Normal或Single等主机发起一次传输时示波器就能把这一帧定格下来。时基要先宽后窄刚开始用100us/div到1ms/div看完整帧搞清楚一帧大概多长找到目标字节后再把时基收到2us/div到10us/div放大看ACK细节。垂直档位在3.3V系统用1V/div5V系统用2V/div就够了。如果条件允许最好让主机程序每隔几百毫秒主动发起一次I2C传输这样单次触发很快就能抓到不用对着屏幕干等。如果你用的是支持SCPI远程指令的示波器比如力科、普源、鼎阳这些牌子还可以把手动设置变成脚本。以某品牌为例Python调用大致长这样具体指令以机器手册为准import pyvisa scope pyvisa.ResourceManager().open_resource(USB0::0xXXXX::INSTR) scope.write(:TIM:SCAL 100US) scope.write(:TRIG:SOUR CH2) scope.write(:TRIG:LEV 1.65) data scope.query_ascii_values(:WAV:DATA?)先把示波器手动调到能稳定触发再用SCPI导波形数据做后续分析比一张张截图省事得多尤其适合批量验证产线板。3.3 波形判读先认起始、停止和数据再谈ACK拿到波形后第一步不是找ACK而是认起始条件和停止条件。起始条件是SCL高电平期间SDA从高跳低停止条件是SCL高电平期间SDA从低跳高。这两个边界看清了一帧的起点和终点就明确了。第二步是确认SCL上面确实有连续的时钟。如果SCL一个沿都没有那主机根本没在发起传输问题在主控配置不在从机。如果SCL正常而SDA几乎不动很可能地址没对上或者总线没真正开始传数据。还有一个健康信号要养成习惯去检查在SCL高电平期间SDA应该保持稳定它的跳变只允许发生在SCL低电平期间。如果看到SDA在SCL高电平期间乱跳那要么是噪声把时序打乱了要么是总线上存在异常电平冲突。这一句话基本能过滤掉一半“看起来很奇怪”的波形。3.4 ACK位怎么找、怎么判找ACK位的方法很机械从起始条件之后的第一个SCL上升沿开始数数完8个时钟就是第一个字节紧接着的第9个时钟就是ACK位。在第9个时钟的高电平区间看SDA如果SDA是低就是ACK如果SDA是高就是NACK。这里要特别解释一下为什么第9个时钟之前SDA经常会先变高因为主机发送完8位数据后会释放SDA让上拉把它拉高然后把第9个时钟发给从机从机在这个时钟的高电平期间把SDA拉低表示应答。所以波形上“先高后低”是正常的你只要看第9个时钟的高电平期间SDA最终落位是低还是高就行。很多新手会犯一个错误只看到SDA上有低电平就以为有ACK没注意这个低电平出现在第几个时钟。ACK的有效窗口是第9个时钟的高电平区间在其他时间出现的低电平可能只是普通数据位。手动数时钟容易数花眼建议用示波器的光标功能一个光标放在起始条件之后第一个上升沿另一个光标放到第9个上升沿这样能准确锁定ACK窗口。3.5 常见异常波形速认表现象可能原因下一步动作SCL有波形、SDA一直低从机将SDA钳位拉死断开从机再测逐颗排查SCL有波形、SDA基本不动且保持高主机没有真正发送数据 / 地址未匹配查看主机代码I2C外设是否初始化SCL低电平被拉长从机时钟延展从机忙属正常机制确认从机配置上升沿圆头、爬升缓慢上拉电阻过大或总线电容过大换小阻值上拉或缩短线缆高电平带明显振铃探头地线过长或走线阻抗不连续换短接地弹簧优化走线SDA在SCL高电平期间跳变噪声 / 建立时间不足查电源纹波、上拉阻值、地回路3.6 没有协议解码怎么办手动数时钟和逻辑分析仪如果示波器不带I2C协议解码又想快速看ACK可以按上面“数到第9个时钟”的办法手动判读。一帧数据一般不超过几个字节数起来并不算累。但如果你要连续分析几十帧或者看数据内容对不对强烈建议用一个几十块的逻辑分析仪。把四根杜邦线分别接到SDA、SCL、GND再用Saleae逻辑分析仪软件或兼容工具解码地址、数据、ACK/NACK会直接标在波形上方效率高很多。用逻辑分析仪时注意采样率不能太低。400kHz的I2C采样率建议至少4MHz以上否则边沿会丢解码会出现随机错误。有些人解码出来一会儿地址对一会儿不对十有八九是采样率不够。4. 从NACK看问题I2C地址、从机忙、电平不匹配的排查顺序4.1 先分清NACK出现在地址阶段还是数据阶段遇到NACK第一件事不是怀疑芯片而是看NACK出现在哪里。如果是地址阶段主机发出地址字节后的第9个时钟SDA为高问题基本集中在从机地址写错、从机没上电、从机不支持这次读写、甚至SDA和SCL接反。如果是数据阶段地址已经ACK但后面的数据字节NACK方向完全不一样常见原因是EEPROM正在内部写周期、寄存器地址越界、从机不支持当前指令长度、主从速率不匹配。这一步判断可以把排查范围缩小一大半。我见过很多人在数据阶段NACK时反复改地址折腾半天没效果或者地址阶段NACK时去查上拉电阻当然也查不出问题。4.2 地址换算7位地址和8位地址的坑I2C地址是两个字段拼在一起发送的7位从机地址加1位读写位合起来才是地址字节。很多数据手册里写的是“7位地址0x50”但示波器解码或者驱动代码里看到的是“0xA0”这种8位写法。0xA0 0x50 1最低位为0表示写读操作就是0xA1。这个左移一位的换算关系几乎是I2C调试里出错率最高的地方。比如一颗EEPROM如果A0/A1/A2引脚都接地7位地址是0x50写地址0xA0读地址0xA1。如果代码里用了7位地址当成8位地址直接发比如发了0x50那第9个时钟大概率收到NACK。还有一个容易忽略的细节有些从机比如触摸控制器、多路复用器的地址受外部引脚电平控制原理图上引脚虽然存在实际没焊接或接错也会导致地址阶段NACK。用示波器把地址字节抓出来和手册一张一张对bit比瞎猜快得多。4.3 从机忙导致的“假NACK”别误判EEPROM写入是需要时间的AT24C02这类片子内部写周期最长能到5ms左右。在写周期内你对它发任何命令它都会以NACK回应。这不是故障是正常行为。正确做法是写完后延时大于tWR或者用写轮询方式反复发送写命令直到收到ACK为止。用示波器验证也很直观在写命令之后紧接着再发一次写命令如果看到SCL照常翻转、SDA在第9个时钟保持高而间隔几毫秒后再次发送就变成低那就是从机忙的“良性NACK”不用处理硬件。同理很多传感器上电后需要几十毫秒的启动时间刚上电立刻读取也会出现地址阶段NACK等一会儿就好了。4.4 速率不匹配和上升沿太慢主控配置的速率和从机支持的速率不一致也会以各种随机NACK、丢字节来表现。建议用示波器直接量SCL周期反推实际频率。有些单片机库的分频配置有坑你写400kHz实测可能跑出500kHz甚至更高这种隐蔽问题只有实测才能发现。上升沿慢也会被从机判为无效高电平。快速模式400kHz要求上升时间小于300ns标准模式100kHz要求小于1000ns。上拉电阻过大、总线电容过大时上升时间很容易超标。你可以用经验公式估算上升时间约等于0.8473乘以上拉电阻值再乘总线电容。例如4.7k上拉加300pF总线电容算出来约1.2us连标准模式的1us上限都超了。所以工程上I2C上拉一般取1k到4.7k线缆和设备多时更要往小选同时也不能太小否则低电平可能拉不下去。4.5 电平不匹配波形看得见但阈值吃不饱如果主控3.3V从机5V两者直接相连又没做电平转换波形可能看起来“正常”但就是ACK不出来。原因在于从机的高电平阈值是0.7×VDD5V系统约3.5V而3.3V主控输出的高电平只有3.3V勉强不到阈值或者从机侧的5V上拉把SDA拉到5V反向灌进3.3V主控引脚。两种情况下都会出现时好时坏、偶尔NACK的现象。排查方法是用示波器量SDA和SCL的高电平、低电平对照从机手册的VIH和VIL。高电平应高于0.7×VDD低电平应低于0.3×VDD从机视角。不满足就得加电平转换芯片或者统一上拉电源和逻辑电平。4.6 所有从机都NACK时的系统性检查还有一种更让人崩溃的情况挂在总线上的所有从机都NACK。这时问题大概率不在某个从机而在总线自身或者主机。按顺序查万用表确认上拉电阻有没有焊、阻值对不对示波器看SCL到底有没有时钟波形看SCL和SDA有没有接反检查主控I/O是否配置成开漏和复用模式。很多单片机的I2C引脚不配置成开漏复用内部推挽输出就会导致总线保持某个电平通信自然起不来。还有一个缩小范围的土办法把总线上其他从机全部断开只保留主控和当前要调的从机重新抓波形。如果只剩一颗设备时通信正常说明问题出在设备地址冲突、总线电容过大或者某颗设备的异常下拉上。逐个恢复设备每恢复一个测一次很容易定位到肇事设备。5. 真实案例复盘I2C信号测试流程怎么用5.1 案例一EEPROM读出来全0xFF问题出在地址我调一块新板子时遇到AT24C02读出来全0xFF。先用万用表量SDA和SCL空闲电压都是3.3V正常断电量对地电阻也没发现短路。于是上示波器抓波形SCL时钟正常地址字节也发出去了但第9个时钟SDA保持高明显是地址阶段NACK。回头看原理图EEPROM的A0、A1、A2都接地7位地址应该是0x50而代码里用了0xA8这种地址相当于把A0当成1自然收不到ACK。改成0xA0后EEPROM读写立刻正常。这个案例说明在万用表“看不出问题”的时候示波器抓一下ACK几秒钟就能锁定方向。5.2 案例二传感器第一次读正常第二次开始NACK另一个案例是BH1750光照传感器上电后第一次读lux正常紧接着第二次读就开始NACK。万用表量电平都正常示波器抓波形发现地址阶段是ACK但数据阶段第9个时钟变成NACK。这就把问题引向了数据阶段的常见原因传感器还没完成一次测量主机又发起了读操作从机忙不过来。修改代码在两次读取之间加入足够的转换等待时间后连续读取恢复正常。这个案例也验证了前面说的判断顺序先分清NACK是地址阶段还是数据阶段能少走很多弯路。5.3 I2C排查流程速查清单步骤工具判读标准1. 断电测SDA/SCL对地电阻万用表电阻/蜂鸣挡不应为0欧也不应无穷大2. 上电测SDA/SCL空闲电压万用表直流电压挡接近上拉电压0.7×VDD以上3. 抓完整帧波形示波器起始、停止条件清晰SCL有连续时钟4. 找ACK位并判读示波器/逻辑分析仪第9个时钟高电平期间SDA为低ACK5. 按ACK位置归因示波器手册地址阶段NACK vs 数据阶段NACK6. 测电平与上升沿示波器高电平≥0.7×VDD上升沿满足速率要求5.4 最后提醒示波器地线夹和探头补偿整套流程里最容易忽略的其实是示波器本身。每次换探头或者换示波器通道先做一次探头补偿再把地线夹换成接地弹簧能减少很多无谓的振铃干扰。I2C虽然不是高速总线但在400kHz甚至1MHz模式下地线回路对波形的影响已经肉眼可见。用短地线测出来的上升沿和用一长溜地线夹测出来的上升沿可能是两个完全不同的故事。调试I2C这些年我个人最深的体会是大多数所谓“灵异事件”都不是芯片坏了而是总线状态没查干净。先万用表后示波器先静态后动态先分清NACK阶段再动手改代码九成问题都能定位。如果你手上暂时没有示波器一个几十块的逻辑分析仪加杜邦线也能把ACK问题看得很清楚但真要判断电平、上升沿这些模拟量示波器还是绕不过去。还有一个始终要放在心头的小技巧I2C的地址换算、上拉电阻取值、ACK窗口位置这三个点几乎包含了调试中一半以上的坑。希望这份流程能帮你少走弯路。