
做嵌入式这些年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.65V5V 系统设 2.5V1.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 静态检查万用表三连击无论症状是什么我的排查第一步永远是静态三连断电量上拉、上电量电压、量完再复位重新上电。具体来说断电状态下用欧姆档测 SCL 和 SDA 到电源之间的上拉电阻确认阻值在 1kΩ 到 10kΩ 范围且不是无穷大焊接问题也不是接近 0短路。上电后用直流电压档量 SCL、SDA 对地电压正常空闲状态都应该接近电源电压。如果发现 SCL 或 SDA 被拉低逐一断开从机引脚排查确定是谁在拉总线。这套动作五分钟就能做完但能排除掉至少三分之一的基础故障。我见过太多人在软件里反复调参数最后发现是上拉电阻虚焊或从机复位引脚没拉起来这类问题软件调一百遍都不会好。5.2 动态检查示波器抓帧与 ACK 定位静态检查通过之后才轮到示波器。我习惯按下面几步走按上一节的方法配置探头、接地、触发和通道保证能稳定抓到 START 条件。抓一帧完整波形依次核对 START、地址、读写位、ACK/NACK、数据、STOP。如果看到 NACK先判断它出现在地址阶段还是数据阶段然后用解码功能读出实际发送的地址再和器件手册核对。如果 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加读标志。我翻传感器手册写的是地址 0x497 位于是把主机地址改成 0x92也就是 0x49 左移一位再加读位 1NACK 立刻消失。问题就是这么简单之前软件工程师把手册里的 7 位地址直接当成 8 位地址发送地址发错从机自然不理你。这个案例的启示是碰到 NACK 第一反应应该是用示波器读出实际发送的地址字节然后老老实实看手册分清器件手册写的是 7 位地址还是 8 位地址。不要凭印象猜也不要急着怀疑芯片坏了。6.2 案例 2400kHz 快速模式下偶发通信失败根因是上拉电阻与总线电容不匹配另一块板子在标准模式 100kHz 下运行稳定一调到 400kHz 就偶发通信失败而且不是每次都失败出错概率大概二十分之一。这种时好时坏的故障最让人头疼因为复现困难看波形又好像一切正常。我用示波器抓了二十多帧才找到规律SDA 的上升沿明显偏慢在 400kHz 下总有某个边沿踩过协议规定的最大上升时间。实测上升沿大概 500ns而快速模式要求不超过 300ns。板子上拉电阻用的是 10kΩ我估算总线上挂的设备加走线电容大约 150pFRC 时间常数算下来就是 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 盯死。这套流程帮我省下了无数个排查的夜晚希望也能让你少走几次弯路。