☰
I2C调试实战:从万用表到示波器的信号与ACK排查指南
2026/9/29 14:17:34 网站建设 项目流程

做嵌入式开发这几年,我调试过最多的总线就是I2C,没有之一。从温湿度传感器、陀螺仪、触摸屏到EEPROM,几乎每个板子上都有它的影子。这总线只有两根线,SCL和SDA,结构简单到新手都觉得三分钟能搞定,可一旦出了问题,排查起来比UART、SPI都难受。因为I2C是半双工、开漏输出、带应答机制的总线,很多故障不是“没波形”这种一眼能看出来的,而是“波形有,但设备压根不搭理你”。这篇文章就聊聊我实际调试中怎么用万用表、示波器、逻辑分析仪一步步把I2C信号和ACK问题查清楚的完整流程,适合刚接触I2C的硬件工程师、嵌入式软件工程师,也适合被传感器、屏幕、触摸芯片折腾到头秃的DIY玩家。

1. I2C信号到底在测什么?

1.1 I2C为什么难测:开漏结构带来的错觉

很多人第一次用示波器测I2C都会有个困惑:SCL、SDA怎么都是高电平?而且看起来是一堆方波,好像也没啥规律。这个疑问背后,就是I2C最核心的电气特性——开漏输出。

I2C总线上所有设备的SCL和SDA引脚都是开漏结构,内部没有主动上拉能力,只能把线拉低,不能主动拉高。总线空闲时,所有设备都释放引脚,线上电平完全靠外部上拉电阻把SCL、SDA拉到VCC。谁要发送数据,就把线拉低,释放后靠上拉电阻恢复高电平。这个过程决定了I2C信号的几个测量特点:

  • 空闲状态是稳定的高电平,不是0V。
  • 波形上升沿由上拉电阻和总线寄生电容共同决定,永远没有推挽输出那种笔直的上升沿。
  • 只要有一个设备异常拉低SDA,整条总线就废了,其他设备也会被拖死。

所以测I2C时,第一件事就是确认这两个引脚在空闲时是不是高电平。如果量出来是0V,先别急着怀疑时序,大概率是总线被拉死了,或者上拉电阻根本没焊。

1.2 测量目标拆解:电平、时序、ACK三件事

I2C调试最怕漫无目的地乱抓波形。我一般把测量拆成三个层次,按顺序排查:

第一层:电平是否正常。这是最基础的检查。上拉电阻接的电压是3.3V还是5V,空闲电平就应该接近那个值。如果实际量出来只有1V、2V或者干脆是0V,说明电路层面就有问题。常见原因包括上拉电阻虚焊、错焊成1Ω(别笑,我见过把10k焊成10Ω的)、总线对地短路、某个从机芯片损坏把SDA拉死。

第二层:时序是否符合协议。包括起始条件(SCL高时SDA拉低)、停止条件(SCL高时SDA拉高)、数据在SCL高电平期间必须稳定、每个字节8位之后第9个时钟是ACK位。这一层通常要用示波器或者逻辑分析仪抓波形来核对。

第三层:ACK/NACK是否正确。前面两层都正常,设备还是不工作,十有八九是ACK出了问题。比如从机地址没对上、从机没上电、速率不匹配、从机正处于忙状态。很多I2C故障的最后根因都在这个第9个时钟上。

说白了,测I2C信号的核心就是看三样东西:线有没有被拉低、时序对不对、接收方有没有回应。后面所有操作都围绕这三件事展开。

2. 万用表在I2C排查里的正确打开方式

2.1 万用表能干什么:静态电平、上拉、通断

很多工程师看不起万用表,觉得I2C这种动态协议必须上示波器。但我的实际经验是,至少一半的I2C故障,用万用表就能定位到具体原因。关键是你要知道拿它测什么。

万用表在I2C调试中最有用的三个场景:

场景一:量空闲电平和上拉电压。板子断电,先用万用表电阻档确认SCL、SDA上拉电阻的阻值,常见的是2.2k、4.7k、10k。然后上电,用电压档量SCL、SDA对GND的电压。如果上拉接的是3.3V,两根线都该量到3.3V左右。量出来偏低,说明有设备在拉低,或者上拉电阻焊错;量出来完全没电压,先查上拉电阻的另一端有没有电。

场景二:用蜂鸣档快速找短路。把万用表打到蜂鸣档,一支表笔点SDA,另一支点SCL,如果直接响,说明这两根线短路了。再分别对GND量,响了就是对地短路。这里有个关键细节:必须先断电再测通断,带电测电阻档或者蜂鸣档很容易烧表,这个坏习惯一定要改。

场景三:配合“强制拉低”判断总线死锁。有时候I2C总线SDA一直是低电平,但你不确定是主机拉死的还是从机拉死的。这时可以断电,用万用表二极管档(其实是在给引脚灌一个微小电流)分别量SDA和SCL对地的压降。如果SDA有0.3V左右的二极管压降,说明有芯片内部的钳位二极管或MOS管在起作用,基本能断定有设备在偷偷拉低总线。这个方法没法精确到具体是哪颗芯片,但至少能确认问题方向。

2.2 万用表的局限:为什么测动态信号会“骗人”

万用表测量基于平均值或者有效值,对I2C这种微秒级别的动态信号来说,它只能给你一个“平均电平”的假象。

举个例子:主机在不停地跟传感器通信,总线上的SDA一会儿高一会儿低,频率可能是100kHz甚至400kHz。你用万用表电压档去量,读数会稳定在某个中间值,比如1.8V或者2.4V。这个数值本身没有太大意义,你不能说“SDA电平不对”,因为通信是正常的。

反过来说,如果某次通信卡住了,SDA被某个设备一直拉低,万用表读数会稳定在0V附近,这时候反而能判断“总线处于死锁状态”。但你要搞清楚是哪一个字节导致的卡死,万用表完全无能为力。

所以万用表只适合做静态排查:上电没、上拉有没有、短路没有。一旦涉及时序、应答、波形边沿,必须换工具。这也是为什么很多初学者拿万用表量了半天,觉得“电压都对啊”,但设备就是不工作——因为问题根本不在静态电平上。

2.3 实操小技巧:用万用表快速定位总线卡死

分享一个我经常用的骚操作。当怀疑SDA被拉死时,先不要急着拆芯片。用万用表电压档量SDA对地电压,记住读数。然后用镊子把SDA对地短接一下再放开,观察万用表读数能不能回到高电平。

  • 如果短接后放开,SDA能恢复到高电平(比如3.3V),说明总线上没有设备持续占用总线,卡死可能是瞬间的通信冲突,或者时序错误导致主机自己进入了错误状态。
  • 如果短接后放开,SDA依然被拉低,说明有设备始终在拉低这根线,这时候就需要逐个断开从机来排查了。

这个方法的原理是:总线空闲时所有设备释放SDA,靠上拉电阻恢复高电平。如果短接后无法恢复,就说明某个设备的驱动管一直处于导通状态,也就是“锁死”了。

另外提醒一句,排查总线卡死时,把主机的I2C外设先禁用或者把引脚配置成普通的GPIO输入,不然主机软件自己也可能在反复操作总线,干扰你的判断。

3. 示波器测I2C的完整操作手册

3.1 探头和通道设置:这些细节决定了波形真假

示波器测I2C,第一原则是别用默认的×1档探头。大部分无源探头有×1和×10两档,×1档虽然灵敏度高,但带宽通常只有几MHz,而且输入电容大,会严重加载I2C总线,导致上升沿变缓、幅值降低,测出来的波形根本不是真实情况。正确做法是打到×10档,同时在示波器菜单里把通道衰减也设成×10,两边不匹配会导致电压读数翻倍或者减半的离谱错误。

探头接地也有讲究。I2C信号本身幅度不大(3.3V系统就是0到3.3V),但板子上往往有电源、电机的各种噪声。测量时接地线越短越好,最好用探头自带的接地弹簧,直接点在SDA或SCL旁边的GND焊盘上。长接地线会形成一个环形天线,把高频噪声耦合进测量回路,你会在波形上看到一堆莫名其妙的毛刺,还以为是信号问题。

通道分配我习惯固定:CH1接SCL,CH2接SDA,并打开通道标签,标上名字。这样看波形时大脑能快速建立映射关系,不会搞混哪根是哪根。如果示波器支持,还可以在解码菜单里分别指定SCL和SDA对应的通道,避免每次测量都得重新配置。

3.2 触发与解码:别再用“Auto”碰运气了

很多新手抓I2C波形就只会按Auto,示波器自动把触发阈值设成50%幅度,触发电平可能落在1.65V左右(对3.3V系统)。问题是I2C总线上经常是长时间空闲高电平,偶尔来一帧数据,用Auto触发很难稳定抓到完整帧。

我推荐的触发方式是:用SDA通道的下降沿触发。I2C通信是SCL高电平期间SDA拉低表示起始条件,所以SDA的下降沿是每一帧通信的起点。把触发源设为CH2(SDA),触发电平设成1.5V(3.3V系统的一半,注意要低于VIH阈值),触发模式选“Normal”(常态触发),这样示波器会一直等待SDA拉低才刷新波形,抓到的都是一帧数据的起点。

这里要特别注意:I2C协议的起始条件是SCL为高时SDA下降沿,而普通数据位传输过程中SDA也可能在SCL低电平期间变化。如果你只设“下降沿触发”而不管SCL电平,有可能抓到的是数据位中间的跳变,看起来波形起始位置不对。更好用的方式是直接用示波器自带的I2C协议触发,选择触发条件为“Start”(起始条件),它会自动判断SCL高电平下的SDA下降沿,比手动设置靠谱得多。

协议解码是示波器测I2C的“开挂”功能。只要在解码菜单里选I2C协议,指定SCL和SDA通道,再设置逻辑阈值(一般是1.5V,根据芯片的VIH/VIL调整),示波器就会自动解析出起始位、地址、读写位、数据、ACK/NACK。解码结果会直接显示在波形上方,比如“Write 0x50, ACK, 0x01, ACK ...”,一眼就能看出通信到哪一步断了。

以力科示波器为例,打开I2C解码的SCPI指令大致是:

COMMS 2 I2C_SETUP SDA,CH2,SCL,CH1,THRESHOLD,1.5 I2C_DECODE ON

鼎阳和普源的菜单路径略有不同,但核心概念是一样的:选协议、指定通道、设阈值。有些示波器还支持“解码表格”视图,把每一帧的地址、数据、ACK状态导出成表格,排查长时间运行才偶发的故障时非常好用。

3.3 采样率、存储深度与长波形抓取

示波器抓I2C最常见的两个坑:采样率不够导致波形失真,和存储深度不够导致只能看到几个字节。

I2C标准模式100kHz,快速模式400kHz,快速模式+到1MHz,高速模式3.4MHz。示波器带宽至少要有信号频率的5倍以上,所以哪怕只测400kHz的I2C,一台50MHz带宽的示波器也够用了。真正的瓶颈是采样率,我建议至少开到500MS/s以上,如果是1GS/s更好。采样率太低,窄的毛刺、短的ACK位被漏采,波形看起来还行,但细节全是错的。

存储深度决定了你能抓多长时间的波形。100MHz带宽、1GS/s采样率的示波器,如果存储深度只有1Mpts,你只能抓1ms的波形,对于400kHz的I2C也就是几十个字节。当你要排查“跑几分钟后偶尔通信失败”这种间歇性故障时,这点时间远远不够。这时候要么降低采样率到250MS/s(仍然够用),把存储深度换时间,要么用滚动模式(Roll mode)长时间监视总线。鼎阳和普源的中端示波器一般有几十Mpts的存储深度,抓几十毫秒的总线波形没问题。

实测中我的习惯配置是:500MS/s采样、全存储深度、Normal触发SCL上升沿,然后按“停止”键等总线跑一会儿,再放大波形逐帧查看。这样既能保证细节,又能覆盖较长时间窗。

3.4 示波器英文界面与SCPI小技巧

身边不少同行用示波器只会中文菜单,一旦切到英文界面就懵。其实I2C调试常用到的英文菜单就那么几个:Trigger(触发)、Decode(解码)、Protocol(协议)、Threshold(阈值)、Acquisition(采集)、Sample Rate(采样率)、Memory Depth(存储深度)。记不住没关系,但至少要把Trigger和Decode这两个认熟。

还有一个容易被忽视的功能:示波器联网后用SCPI指令远程控制。比如力科示波器支持以太网接口,你用Python脚本就能批量设置触发、读取波形数据、甚至自动保存解码结果。排查那种需要长时间监控的偶发故障时,这招能省大量人力。

简单示例(假设示波器IP是192.168.1.100,端口是1865):

import pyvisa rm = pyvisa.ResourceManager('@py') scope = rm.open_resource('TCPIP::192.168.1.100::1865::SOCKET') scope.write('I2C_DECODE ON') scope.write('ARM') # 等待一段时间后读取解码表格 data = scope.query('I2C_TABLE?') print(data)

注意,不同厂家的SCPI命令集不一样,力科、鼎阳、普源都有差异,用之前先查一下对应型号的编程手册。但无论哪家,触发、采集、解码、读数这几个能力都是共通的,会用一家就能快速上手另一家。

4. ACK到NACK:从第9个时钟看穿通信失败

4.1 ACK的时序和判定:不是“有波形”就万事大吉

I2C协议里,主机发完一个字节后,第9个时钟周期会释放SDA,由从机拉低SDA表示ACK(应答),如果不拉低,SDA保持高电平就是NACK(无应答)。这个机制是I2C不同于UART、SPI的核心优势:发送方每发一个字节都能立刻知道对方收到了没有。

但是很多人在示波器上看ACK时犯一个错误:用眼睛瞄了一下,觉得“哦,第9个时钟后SDA变低了,有ACK”,就认为通信正常。实际上ACK判定必须看两个东西:

  • ACK位是否出现在正确的时间窗口:第9个时钟的高电平期间,SDA必须是被从机拉低的状态。如果SDA只是在第8个时钟后偶然变低,或者在第9个时钟结束后才变低,那都不是有效的ACK。
  • SDA在ACK周期内的低电平幅度:理想情况是被拉到接近GND,但实际中如果从机驱动能力弱,或者上拉电阻太小导致拉低后仍有残余电压,电平可能只有1V多。只要低于从机的VIL阈值(一般0.3×VCC),主机就能正确识别为ACK,这部分也是合法的。

为了准确观察ACK,示波器时基要放到每格5µs~20µs(对应100kHz~400kHz速率),这样才能看清时钟周期内SDA的变化。用协议解码功能时,示波器会直接在帧上面标记“ACK”或“NACK”,比肉眼判断可靠得多。

4.2 NACK的几种常见原因,最后一个最隐蔽

NACK是I2C调试里最让人头大的问题。信号看起来全都有,时钟也在跑,就是地址阶段或者数据阶段从机不回ACK。归纳下来,NACK就这几种原因:

原因一:从机地址没对上。这是最常见也最好查的。I2C设备地址分7位和8位两种说法。很多器件数据手册写的是8位地址,比如0xA0(1010 0000),但在总线上实际传输时,是7位地址0x50(1010 0000右移一位),最低位是读写标志。你把0xA0直接写到代码里,等于把读/写位当成地址的一部分发了出去,从机地址不匹配,必定NACK。排查时必须先搞清楚器件手册的地址是7位还是8位。

原因二:从机地址有引脚配置。很多I2C芯片通过A0、A1、A2引脚设置地址(比如EEPROM、IO扩展芯片),板子上这些引脚如果悬空、上拉/下拉电阻错了,地址就会变。测出NACK后,先拿万用表量一下这三个引脚的电压,确认硬件地址和代码一致。

原因三:从机没上电或者复位异常。这个更隐蔽。我碰到过一颗触摸芯片,平时好好的,但系统休眠唤醒后I2C通信就开始NACK。后来发现是芯片的复位引脚没处理好,唤醒后芯片还在复位状态,I2C从机逻辑根本没跑起来。这种问题的特征就是:刚上电时正常,用着用着就NACK,复位一下又好了。

原因四:速率不匹配导致从机来不及响应。尤其是一些老的传感器,只支持100kHz标准模式。你把主机I2C时钟配到400kHz,从机跟不上了,就会在第9个时钟不回ACK。这时把时钟降回100kHz试试,如果好了,说明问题就是速率。改速率时注意整个I2C外设的时钟配置,不是改一个数字那么简单,要用示波器实测SCL频率到底是多少。

原因五:从机处于忙状态。有些设备在内部擦写EEPROM、处理内部ADC时,会不回ACK。比如AT24C系列EEPROM在写入周期内,你发任何地址它都NACK,这个不是故障,是正常工作状态。遇到这种情况,主机侧需要加“写周期延时”或者“轮询ACK直到成功”的逻辑。

4.3 实战案例:GT911触摸屏和AS5600编码器的排查

最近网上很多人问GT911触摸屏I2C通信失败的问题,我自己也踩过这个坑。GT911的I2C地址可以通过引脚配置,常见的7位地址是0x5D或0x14,8位形式则对应0xBA和0x28。很多人代码里用0xBA,但GT911实际工作时如果INT引脚或者RST引脚时序不对,它会切到另一个地址。我的排查顺序是:

  1. 先用示波器抓地址阶段的波形,看SDA上发的地址到底是几。
  2. 解码结果如果显示主机发的是0xBA,但设备不回ACK,就把GT911的RST引脚拉低再拉高,重新初始化一下。
  3. 初始化后再次抓波形,看地址有没有变化,如果变成0x28了,说明设备切换地址成功,代码里同步修改地址即可。

AS5600磁编码器是另一个常见案例。这芯片支持硬件I2C和软件I2C两种读取方式,硬件I2C时序严格,但很多人的MCU硬件I2C实现有bug,程序跑起来后读寄存器一直NACK。排查时我建议先用软件I2C(GPIO模拟)方式读,确定芯片本身没问题,再回头查硬件I2C外设的配置。软件I2C在时序上天然灵活,而且读到的数据和波形可以直接对应,排查问题比死磕硬件外设寄存器快得多。

5. 万用表到示波器的完整排查流程

5.1 三板斧的定位分工:万用表、示波器、逻辑分析仪各管一段

到这里,你已经知道万用表和示波器各自的强项和短板了。在实际项目中,我还会加一个逻辑分析仪参与排查。这三样工具的定位是:

工具擅长不擅长适用阶段
万用表静态电平、上拉电阻、短路、通断看时序、看波形、看ACK拿到板子最先用的工具
示波器波形细节、时序测量、协议解码、噪声分析长时间不间断监控很多通道定位协议层问题的核心工具
逻辑分析仪多通道、长时间抓波形、协议解析测量电压幅度、模拟信号细节抓偶发故障、分析总线上多设备交互

逻辑分析仪用起来比示波器简单,采样率要求也不高。I2C两根线,逻辑分析仪只要每个通道用个几十MHz的采样率就完全够了,关键是它能同时监控十几个通道,而且存储深度大,能连续抓几秒钟的总线数据,把每一帧通信都记录下来。排查“系统运行半小时后I2C死掉”这种问题,用示波器你得一直盯着屏幕,用逻辑分析仪只要挂上去等它触发就行。

但注意逻辑分析仪测不了模拟电平。如果怀疑是上拉电阻太大导致波形边沿太缓,逻辑分析仪可能仍然能解码成功(因为它的阈值是固定的),但示波器能看出上升沿缓慢的问题。所以最终结论还是要用示波器确认。

5.2 五步排查法:从不上电到波形到ACK

现在总结一套我实测高效的I2C排查流程,按步骤来,基本能覆盖绝大多数问题:

第一步:断电静态检查。万用表蜂鸣档量SCL、SDA是否短路,分别对GND量是否有短路。再量上拉电阻阻值,4.7k、10k都正常,低于1k就要警惕,高于100k基本可以断定通信会不稳定。

第二步:上电量静态电平。万用表电压档,红表笔点SDA,黑表笔接GND,读数应该在VCC附近。如果为0V或者异常低,回到第一步检查短路和上拉。再量SCL,标准一致。

第三步:让主机发数据,示波器抓起始条件。用SDA下降沿触发,看能否稳定抓到波形。如果能抓到,说明主机侧的I2C外设配置正常,软件在跑。如果抓不到,先查单片机引脚复用(I2C功能是否映射到正确引脚),再查引脚电平。

第四步:协议解码核对地址和数据。打开示波器I2C解码,读解码表格,核对主机发送的从机地址是不是预期值,读写位对不对。如果地址不对,回代码查地址定义。如果地址对了但显示NACK,进入第五步。

第五步:针对NACK专项排查。按上一小节列出的NACK原因逐个排除。先确认从机电源、复位引脚,再确认地址引脚配置,然后尝试降低速率,最后考虑从机忙状态。每改一个条件,重新抓一次波形,看NACK有没有变成ACK。

这套流程看起来繁琐,但每一步排除了一个问题维度,实际上比拿到波形就一顿瞎猜快得多。

5.3 常见问题速查表

现象可能原因优先排查动作
SDA一直为0V有设备拉死总线、对地短路、上拉缺失断电量通断,短接测试能否恢复高电平
SCL无波形主机I2C未使能、引脚复用错误、时钟源没配查单片机寄存器,示波器触发SCL下降沿
有波形但无ACK地址错、设备没上电、速率太快、从机忙解码看地址,量从机电源,降速试
偶发通信失败上拉电阻过大、干扰、电源纹波示波器长时间抓波形,查边沿质量
波形上升沿很缓上拉电阻太大、总线电容大、上拉电压不足换小上拉电阻,或缩短总线长度
解码显示乱码阈值设置错误、采样率不足、探头接触不良检查解码阈值和采样率,换接地弹簧

这套速查表是我自己在项目里反复沉淀出来的,每次排查新问题都先对号入座,大部分情况十分钟内能锁定方向。

测I2C这件事,说难也难,说简单也简单。难的是它不像UART那样收发分明,也不像SPI那样有明确的片选线,总线上一堆设备全靠地址和ACK协调,任何一个环节出问题都会让整个系统“装死”。简单的是,只要你把“电平-时序-ACK”这三层拆开,用对工具,就能一步步缩小范围。

我个人的习惯是,项目里只要涉及I2C,就会在测试治具上预留SCL、SDA、GND三个测试点,并且串联33Ω的电阻引出到排针,这样示波器探头可以直接夹上去,不用每次焊线,也减少了对总线电容的影响。另外,I2C调试器在便宜方案里非常好用,二十来块钱的逻辑分析仪配合免费软件,能解码I2C还能导出CSV,比示波器做长时间监控更省心。最后一个建议,排查I2C问题时,先把代码里的错误处理(超时重试、出错复位)关掉,让总线错误直接暴露出来,不要让它被程序自动恢复掉,这样你才能在示波器上看到真实的故障现场。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询