☰
I2C信号测量与故障排查实战:万用表+示波器定位ACK/NACK问题
2026/9/27 12:05:51 网站建设 项目流程

做嵌入式这些年,I2C 是我又爱又恨的一种总线:两根线就能挂一堆传感器、存储芯片和触摸屏,看起来简单,可一旦通信失败,排查起来却非常磨人。前阵子帮朋友查一块板子,现象很典型:主机一直读不到传感器数据,万用表量 SCL 和 SDA 电压都正常,示波器上也确实看到波形在跳,可通信就是不成功。折腾了半天,最后把波形放大到 ACK 位才发现,从机从头到尾压根没回应过主机。那次经历让我决定把 I2C 信号测量这件事完整写一遍:万用表能帮你确认什么,示波器应该怎么抓、怎么测,ACK 又该怎么判,从工具到流程一次讲透。

这篇文章适合两类人:一类是刚入门的硬件或嵌入式工程师,想知道 I2C 信号到底该怎么测;另一类是已经踩了坑但还没爬出来的工程师,手头有万用表和示波器,却不知道下一步该看哪里。我会尽量把排查路径讲成一条清晰可复用的流程,让你遇到 I2C 问题时不用靠猜,靠测量就能一步步定位根因。

1. 排查前先搞清楚:I2C 总线上到底有哪些"会骗人"的信号

1.1 开漏结构决定了你测量的不是"信号"而是"状态"

很多工程师第一次上手测 I2C 时,习惯性把它当成普通数字总线:高电平代表"输出 1",低电平代表"输出 0"。这个理解放在 I2C 上会带偏整个排查方向,因为 I2C 用的是开漏结构。

所谓开漏(Open-Drain),指的是设备内部只有一个下拉 MOSFET,它能把总线拉到地(低电平),但没有任何能力把总线"推"到高电平。总线的高电平完全靠外部上拉电阻连接到电源来实现。用一个生活类比:总线是一根被弹簧(上拉电阻)拉起来的绳子,任何设备都可以伸手把绳子拽到地上,但没有任何设备能把它向上推。所以你在万用表或示波器上看到的高电平,只是"此刻没有人拽绳子"的结果,而不是某个设备在"发送 1"。

这个底层结构决定了测量时的核心认知:I2C 电平本质上反映的是"总线当前是被占用还是释放",而不是"某一位数据是 1 还是 0"。上拉电阻的阻值、总线上挂了多少设备、走线长度带来的电容,都会直接改变你看到的波形。换句话说,I2C 的信号完整性问题与普通推挽输出总线很不一样,排查时要换一套思路。

1.2 一次完整通信里有哪些关键边界:START、STOP、数据位与第 9 个时钟

要把 I2C 波形看明白,得先知道一帧通信里有哪些"关键位置"。任何一次主机和从机的交互,拆开看都包含这样几部分:

  • START 条件:SCL 为高电平时,SDA 从高变低。这是通信开始的标志,也是示波器触发的最佳参考点。
  • 地址字节:紧接着的 8 个时钟周期里,主机依次发送 7 位从机地址加 1 位读写标志(0 表示写,1 表示读)。
  • ACK 位:第 9 个时钟周期,用于从机确认自己收到了该字节。这里有个极容易踩的坑:7 位地址和设备手册里写的 8 位地址经常被混用,后面案例里我会详细聊。
  • 数据字节:后续每个字节同样由 8 位数据加 1 个 ACK 位构成,数据位在 SCL 高电平期间保持稳定。
  • STOP 条件:SCL 为高电平时,SDA 从低变高,表示传输结束。

除了这些基本边界,还有两个平时容易忽略的变体。一是时钟拉伸(Clock Stretching):从机在需要处理数据时会把 SCL 拉低,让主机等待,这时候你抓波形会看到 SCL 出现一个"额外的低电平",这是正常现象,不是故障。二是多主机仲裁:任何设备都能拉低总线,如果两个主机同时发起通信,低电平占优。建议动手测之前先在脑子里过一遍这些概念,否则示波器上一堆波形很容易看得云里雾里。

2. 万用表能帮你解决什么:静态电平、上拉电阻和"假死"判断

2.1 电压档:先确认总线有没有被拉死

我最常对同事说的一句话是:I2C 排查不要一上来就抱示波器,先拿万用表量两下,成本最低,信息量却很大。

上电状态下,用直流电压档分别测 SCL 对地、SDA 对地电压。正常情况下,总线空闲时两根线都应该被上拉到接近电源电压的位置。比如 3.3V 系统里,空闲状态测到 3.3V、SDA 也测到 3.3V,这是最理想的情况;如果其中一根线测到接近 0V,比如 0.05V,那基本可以断定有设备把总线拉住了,这就是俗称的"总线锁死"。

这种情况我在现场遇到过很多次,最典型的表现是主机软件一启动 I2C 通信就报 BUSY,反反复复重新初始化也没用。这时候用万用表量 SDA 电压就能立刻定位:如果 SDA 一直低,说明有设备占着总线不放手;如果 SCL 一直低,问题多半出在从机的时钟处理上。更省事的做法是断电状态下把疑似从机的 SDA、SCL 引脚断开,如果电压恢复正常,真凶基本锁定。

还有一种容易被误判的情况:量到 0.5V、1.2V 这种不上不下的电压。最常见原因是上拉电阻虚焊、没焊接,或者上拉电源没接对。这种浮动电压最坑人,因为它既不像正常的空闲高电平,也不像被拉死的低电平,不仔细看很容易被当成"波形异常"去调软件参数,调半天却没解决硬件问题。

2.2 通断档与电阻档:上拉电路的检查

静态量完电压,下一步是断电量电阻。用通断档或欧姆档检查上拉电阻有没有接上、阻值是否合理。I2C 上拉电阻通常取 1kΩ 到 10kΩ 之间,具体取决于总线速率、总线总电容和电源电压。

为什么会有范围?因为上拉电阻既不能太小也不能太大。电阻太小,设备拉低总线时需要灌入的电流变大,可能超过器件允许的灌电流,低电平电压会抬得过高,波形很难看;电阻太大,总线上升沿变慢,高速通信时极易踩到时序违规。快速模式(400kHz)下总线最大上升时间一般要求不超过 300ns,如果上拉电阻和总线电容形成的 RC 时间常数过大,上升沿就会超时。

你可以用两个公式快速估算:

  • 最小上拉电阻:Rmin = (VCC - VOLmax) / IOLmax。以 3.3V 系统为例,VOLmax 取 0.4V、IOLmax 取 3mA 时,Rmin 约等于 1kΩ。
  • 最大上拉电阻:由需要的上升时间(tr)和总线总电容(Cb)决定,Rmax 约等于 tr / (0.8473 × Cb)。总线电容每米线缆大约有 100pF 到 200pF,板上短走线加上每个器件的引脚电容,通常按总电容 50pF 到 200pF 估算。

万用表在这一步的价值,是把"上拉电路是否健康"这个基础问题先排掉。很多看起来诡异的 I2C 故障,最后追根溯源都出在上拉电阻上。

2.3 频率档的局限:能看出"有没有在跑",看不出"跑得对不对"

带频率档的万用表在 I2C 排查里有一个很实用的初级用途:用频率档去测 SCL,如果能看到 kHz 级别的读数,至少证明主机在尝试产生时钟。这对快速判断"主机程序到底有没有在跑 I2C 通信"很有帮助,特别适合排查软件初始化问题时顺手验证一下。

但必须说清楚,频率档能提供的信息极其有限。它只能告诉你"SCL 在翻转",却完全无法回答三个关键问题:地址对不对、从机回没回 ACK、数据内容是不是预期值。我见过有人用频率档测到 SCL 有 100kHz 频率,就认为"I2C 正常工作",结果通信其实一直在 NACK。万用表在这里只适合做"有没有"的确认,至于"对不对",必须交给示波器或逻辑分析仪。

3. 示波器抓 I2C 的正确姿势:探头、触发和解码设置

3.1 探头选择与接地:长地线是波形失真的头号元凶

到了示波器环节,第一个要说的不是通道参数,而是探头。很多人用标配无源探头时,习惯把探头根部那根又长又软的鳄鱼夹地线夹在板子某个地孔上。这在低频信号上问题不大,但 I2C 上升沿只有几十到几百纳秒,长地线形成的环路电感和探头电容会一起改变波形,让你看到根本不存在的过冲和振铃。

正确做法是尽量用探头自带的短接地弹簧,或者把探头地线压到离测量点最近的地平面上。如果你抓到的上升沿有莫名其妙的尖刺,先别急着怀疑电路,把接地方式换短一点再抓一次对比。这个细节在排查时救过我很多次,有两次差点把问题归咎于 PCB 走线,其实全是探头接地造成的假象。

测量点的选择也有讲究。优先测器件引脚本身,而不是瓷片电容或者过孔;如果信号线上有串联电阻(不少设计会在 SCL、SDA 上串 22Ω 或 33Ω),要测器件侧还是主机侧需要想清楚。建议两侧都看一眼,两侧电平差异能反映出当前是哪一端在驱动总线。

3.2 触发设置:用 START 条件而不是普通边沿

示波器抓 I2C 最典型的坑在触发设置。如果你用 SCL 的上升沿去触发,肯定能触发,但看到的是密密麻麻的时钟脉冲,根本看不到完整一帧;如果总线大半时间空闲,SCL 半天不跳一次,你又可能一个波形都触发不到。

正确思路是优先使用 I2C 协议触发菜单里的 START 条件,示波器会自动锁定通信起点。如果设备没有协议触发功能,就退而求其次:触发源选 SDA,触发方式选下降沿,配合 Normal 模式。需要说明的是,普通下降沿触发也可能触发到数据切换边沿,但这不影响排查,你可以在抓到的波形里找到 SCL 为高电平时 SDA 下降的那个位置,那才是真正的 START。

通道分配建议 CH1 接 SCL、CH2 接 SDA,触发源选 CH2。时基可以先放到 200μs/div 左右,保证能抓到地址加至少几个字节,抓到后再用 Zoom 功能放大看细节,而不是一开始就开到 20μs/div,那样很容易错过帧边界。

3.3 采样率、时基与存储深度:抓 I2C 到底要开多大

I2C 的速率在数字总线里不算快,标准模式 100kHz、快速模式 400kHz,哪怕高速模式也就 3.4MHz。示波器只要带宽在 50MHz 以上,抓 I2C 完全够用,采样率 1GSa/s 更是绰绰有余,不用刻意追求高带宽高采样。

真正容易忽略的是存储深度。I2C 一帧往往包含地址和连续多个数据字节,比如往 EEPROM 连续写 32 字节,整个操作可能持续几百微秒甚至几毫秒。如果存储深度太浅,你用大时基抓帧时会发现波形后期"变糊",或者采样点严重不足,ACK 位根本看不清楚。

我的习惯是:先大时基(1ms/div 左右)抓完整操作,确认帧边界,然后对感兴趣的小段直接 Zoom 放大,利用深存储重新显示细节。现在很多入门示波器都有大存储深度,打开深存储模式后这个操作基本没压力。如果手头示波器存储特别浅,可以分多段抓,每次抓 2 到 3 个字节,配合信号重复触发也能拼出完整链路。

3.4 解码头:从"看图猜"到自动解析

现在带串行解码的示波器已经很普及,抓 I2C 时开解码效率会高一大截。设置不复杂:在解码菜单里选 I2C 协议,指定 SCL 用哪个通道、SDA 用哪个通道,再设一个逻辑电平阈值。3.3V 系统一般设 1.65V,5V 系统设 2.5V,1.8V 系统设 0.9V。

打开解码后,示波器会在波形下方直接标出 START、地址、读写方向、ACK/NACK 和数据内容,肉眼完全不用去数时钟。但我必须泼一盆冷水:解码结果只代表"示波器认为协议长这样",它是一把高倍放大镜,不是裁判。尤其在 NACK 判定这种关键问题上,我仍然建议回到波形本身,手动确认第 9 个时钟时 SDA 的电平状态,防止因为阈值设置不对或探头接触不良,把正常波形解码成一片乱码。

如果你手头有逻辑分析仪,抓协议帧确实比示波器更方便,因为它可以按协议级触发,一次抓多路信号;但排查信号完整性、上升沿、过冲这类模拟问题,还是得靠示波器的模拟通道。两者互补,不是替代关系。

4. 从波形反推时序:SCL、SDA 和 ACK 的真实判定方法

4.1 如何读数据位:SCL 高电平期间的 SDA 才是有效的

拿到一帧波形后,下一步是手动读位。I2C 协议规定,SDA 上的数据只在 SCL 为高电平时有效,SDA 的电平切换发生在 SCL 低电平期间。所以读数据位时不要盯着 SDA 的整个波形看,而要看每个 SCL 高电平区间内 SDA 是 1 还是 0。

举个例子。假设你抓到地址字节,前 8 个时钟里 SDA 在 SCL 高电平期间依次为高、低、高、低、低、低、低、低,翻译出来就是 10100000,也就是 0xA0。这个 0xA0 是常见的 8 位写地址,它对应的 7 位地址是 0xA0 右移一位,即 0x50。如果你在示波器解码里看到地址显示 0x50,又查到手写手册写的是 0xA0,不要慌,二者是同一个地址的两种表达方式,一个是 7 位格式、一个是 8 位格式。很多 NACK 问题就出在这种换算上。

还有一个小技巧:波形里 SDA 在 SCL 低电平期间跳变是正常现象,可以不用管;真正需要警惕的是 SDA 在 SCL 高电平期间突然跳变,那通常意味着时序错误、电平竞争或设备驱动异常。

4.2 ACK 去哪里找:第 9 个时钟沿前后的 SDA 电平

ACK 位是 I2C 排查里最容易被忽视、也最常出问题的地方。它的位置很好找:每个字节发送完 8 个数据位之后,紧接着的第 9 个 SCL 时钟就是 ACK 位。

ACK 的判定逻辑是:发送完地址或数据字节后,主机会释放 SDA,也就是把它从驱动状态切换为输入状态;从机如果正常收到,就会在第 9 个时钟的高电平区间主动把 SDA 拉低。你在示波器上看到的结果就是:第 9 个时钟上升沿附近,SDA 从高变到低,且在整个高电平区间保持低电平。

如果第 9 个时钟时 SDA 保持高电平不动,说明从机没有应答,这就是 NACK。这里特别提醒一个容易搞反的概念:ACK 不是主机发的,是从机发的。主机在第 9 个时钟里的职责是"释放总线并观察结果"。很多人以为 ACK 是主机在确认,看到 NACK 后就去查主机发送代码,方向从一开始就错了。

4.3 NACK 的含义:不是"出错",而是"拒绝"

NACK 经常被当成"通信出错了"的同义词,这不够准确。更贴切的理解是:从机在说"这个地址不是我的,或者我此刻不想接收数据"。

常见 NACK 场景有三类。第一类,地址阶段 NACK:主机发出的地址没有从机认领,最常见原因是地址写错、器件使能脚没拉对、器件根本没上电,或者总线上压根不存在这个设备。第二类,数据阶段 NACK:从机收到了数据但拒绝接收,比如写入的寄存器地址不存在、写入值不合法,或者从机正忙。第三类,读操作结束时主机的 NACK:这在读操作里是正常的协议动作,主机读完最后一个字节后主动发 NACK 表示"不用再发了",然后发 STOP。如果连这种情况都当成故障去查,纯粹是白费功夫。

另外,PMBus 这类管理总线,底层用的就是 I2C 那套电气和时序协议,只是数据格式和命令定义不同,ACK/NACK 判定规则完全一样。如果板上同时挂了 I2C 设备和 PMBus 设备,这套排查方法可以通用。

5. 完整排查流程:从"读不到数据"到根因定位的逐级递进

5.1 静态检查:万用表三连击

无论症状是什么,我的排查第一步永远是静态三连:断电量上拉、上电量电压、量完再复位重新上电。

具体来说:

  1. 断电状态下,用欧姆档测 SCL 和 SDA 到电源之间的上拉电阻,确认阻值在 1kΩ 到 10kΩ 范围,且不是无穷大(焊接问题)也不是接近 0(短路)。
  2. 上电后,用直流电压档量 SCL、SDA 对地电压,正常空闲状态都应该接近电源电压。
  3. 如果发现 SCL 或 SDA 被拉低,逐一断开从机引脚排查,确定是谁在拉总线。

这套动作五分钟就能做完,但能排除掉至少三分之一的基础故障。我见过太多人在软件里反复调参数,最后发现是上拉电阻虚焊或从机复位引脚没拉起来,这类问题软件调一百遍都不会好。

5.2 动态检查:示波器抓帧与 ACK 定位

静态检查通过之后,才轮到示波器。我习惯按下面几步走:

  1. 按上一节的方法配置探头、接地、触发和通道,保证能稳定抓到 START 条件。
  2. 抓一帧完整波形,依次核对 START、地址、读写位、ACK/NACK、数据、STOP。
  3. 如果看到 NACK,先判断它出现在地址阶段还是数据阶段,然后用解码功能读出实际发送的地址,再和器件手册核对。
  4. 如果 ACK 正常但数据不对,把波形放大,逐个数据位与期望值比较,同时检查 SCL 高电平期间 SDA 上是否有毛刺。

整个过程的关键原则是:一次只改一个变量。改地址就只改地址,改上拉就只改上拉,改完重新抓波形对比前后差异。不要同时改软件、换芯片、调电阻,否则你永远不会知道是哪个改动起了作用。

5.3 症状对照表:现象与优先怀疑方向

现象优先怀疑方向验证手段
主机报 BUSY 或初始化失败总线被从机拉死万用表量 SCL/SDA 电压,逐段断开从机
地址阶段连续 NACK地址错误、器件不在、使能脚没拉对示波器解码读地址,核对 7 位/8 位格式
数据阶段 NACK寄存器地址不存在、写入值非法、从机忙查看手册寄存器表,可尝试降低总线速率
偶发通信失败,时好时坏上拉电阻偏大、总线电容大、干扰测上升时间,估算 RC 时间常数
波形出现严重过冲或振铃探头接地不良、上拉电阻过小换短接地,检查上拉电阻阻值
电平在正常范围但通信失败逻辑电平阈值设置错误、IO 电平不匹配检查主机和从机的 IO 电平是否兼容

这张表不能代替理解,但能在你脑子发懵时快速给出方向,省去从头猜起的时间。

5.4 排查顺序为什么必须"供电-地址-波形-时序"

最后说说为什么要把流程固定成这个顺序。核心原因是成本和信息量的平衡:查供电和上拉只需要一块万用表,五分钟能确认;查地址只需要看手册加示波器解码,十分钟能确认;查波形才需要正确配置示波器,可能要半小时起步;查时序和信号完整性是最后才该做的事,因为它最复杂、变量最多。

很多新手反过来,一上来就抱着示波器到处点,结果抓了一堆波形却不知道自己在看什么。先把静态问题排掉,再让协议开口说话,最后才谈波形质量和时序,这是我在实践中验证过效率最高的路线。如果手头连万用表都没有,直接用示波器的直流测量功能做静态检查也可以,只是效率没有万用表高。

6. 三个典型 I2C 故障案例:从波形到修复的完整复盘

6.1 案例 1:从机一直 NACK,根因是 7 位/8 位地址搞混

某次调试一块板子,主控要通过 I2C 读取温湿度传感器。起初症状是读寄存器数据全是 0xFF,软件上换了模拟 I2C 和硬件 I2C 两套方案都失败。我用示波器抓 START 后的前 9 个时钟,发现地址字节后的第 9 个时钟上 SDA 一直是高,也就是从机完全没有应答。

从波形上看,主机发送的地址字节是 0x90,对应 7 位地址 0x48,加读标志。我翻传感器手册,写的是"地址 0x49(7 位)",于是把主机地址改成 0x92,也就是 0x49 左移一位再加读位 1,NACK 立刻消失。问题就是这么简单:之前软件工程师把手册里的 7 位地址直接当成 8 位地址发送,地址发错,从机自然不理你。

这个案例的启示是:碰到 NACK 第一反应应该是用示波器读出实际发送的地址字节,然后老老实实看手册,分清器件手册写的是 7 位地址还是 8 位地址。不要凭印象猜,也不要急着怀疑芯片坏了。

6.2 案例 2:400kHz 快速模式下偶发通信失败,根因是上拉电阻与总线电容不匹配

另一块板子在标准模式 100kHz 下运行稳定,一调到 400kHz 就偶发通信失败,而且不是每次都失败,出错概率大概二十分之一。这种"时好时坏"的故障最让人头疼,因为复现困难,看波形又好像一切正常。

我用示波器抓了二十多帧才找到规律:SDA 的上升沿明显偏慢,在 400kHz 下总有某个边沿踩过协议规定的最大上升时间。实测上升沿大概 500ns,而快速模式要求不超过 300ns。板子上拉电阻用的是 10kΩ,我估算总线上挂的设备加走线电容大约 150pF,RC 时间常数算下来就是 1.5μs,上升沿偏慢一点不奇怪。

处理方式是把 SCL 和 SDA 的上拉电阻从 10kΩ 换成 4.7kΩ,重新量上升时间降到 250ns 左右,400kHz 下连续跑了两小时再没出过错。这里也能看出为什么上拉电阻要针对具体总线去调:设备数量、走线长度、IO 电容都会影响总线电容,一个固定的"10kΩ 万能值"并不存在。

6.3 案例 3:总线被"锁死"在低电平,从机复位时序才是真凶

第三种情况最像"硬件坏了":主机运行后第一次 I2C 通信就失败,读寄存器永远超时。我用万用表量 SDA,发现它一直停在 0.03V 左右,SCL 倒是正常的 3.3V。强行断开从机的 SDA 引脚后电压才恢复正常,说明从机在使劲拉着总线不放。

很多人到这里会直接认定"从机烧了",但我先查了从机的复位时序。查完才发现,从机是一个自带 MCU 的传感器模块,它上电后需要大约 200ms 完成自检,自检完成之前 GPIO 默认是推挽输出低电平,直接把 SDA 拉死了。主控这边上电后立刻发起 I2C 通信,正好撞上这个窗口。修复办法是主控延时 300ms 再初始化 I2C,同时把从机侧在复位期间的 GPIO 配置成高阻输入,总线锁死问题彻底消失。

复盘时记住一点:总线锁死不一定等于硬件损坏,它经常是某个从机在"不合适的时机"抢占了总线。治本的办法是规定好上电和复位时序,让所有设备先进入高阻状态,再允许主机开始通信。

下次再遇到 I2C 通信失败,我的建议是先量电压、再抓波形、把 ACK 盯死。这套流程帮我省下了无数个排查的夜晚,希望也能让你少走几次弯路。

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

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

立即咨询