示波器接上、采样率调好,然后就盯屏幕的时间到了。干嵌入式这行,I2C大概是“看起来最简单、调起来最闹心”的协议。两根线,SCL、SDA,上拉电阻一接,按说信号清清楚楚,可一旦设备没反应,很多人的第一反应就是上网搜“I2C怎么测”,一整晚下来示波器波形抓了一大堆,却还是分不清是“没发出来”还是“没应答”。这篇文章就用实际排查的思路,从万用表最简单的通断、电压测量,到示波器抓时序、看ACK/NACK,把I2C从电气到协议的排查路径完整走一遍。适合手里正好有一块不通信板子的硬件工程师,也适合刚上手嵌入式、想搞明白I2C时序到底长什么样的初学者。文章会尽量少讲虚的,每一步都告诉你为什么要这么测,以及测出来的波形该怎么解读。
1. I2C信号到底在传输什么:先知道要测哪些关键特征
万事开头先别急着上仪器。I2C排查之所以容易卡壳,是因为很多人不知道自己在找什么。测I2C根本目标就两个:电学上通不通、协议上对不对。先把这个底摸清楚,后面所有操作才不会乱。
1.1 两根线、开漏上拉:为什么I2C测起来和SPI不一样
I2C不像SPI或UART那样靠主动驱动高低电平。它的两根线SCL和SDA都是开漏结构,空闲时靠上拉电阻把电压拉到高,设备要发送低电平时才把引脚内部下拉导通。这就带来一个直接后果:信号下降沿很陡,但上升沿完全看上拉电阻和总线分布电容,经常呈现出明显的RC充电曲线形状。
理解这个电气特性对看波形极其重要。我在排查时第一眼从来不看数据对不对,而是看两样东西:空闲时SDA和SCL是不是都稳定在高电平,以及数据线上升沿是不是够快、有没有毛刺。曾经遇到过一块板子,SCL看起来有方波、SDA也乱跳,但设备就是不响应,示波器放大后才发现上升沿已经软得像条抛物线,原因是PCB走线过长加上上拉电阻用了22k。这种问题单纯看逻辑电平是发现不了的,必须结合电气认知才看得明白。
1.2 一个事务里必须确认的四件事:起始/停止、地址、数据、ACK
I2C的一次完整事务,大体等于主机在总线上唱一出有剧本的戏。先制造起始条件(START):SCL为高时,SDA从高拉低。然后主机逐位发出从机地址和读写标志。接下来每传输完一个字节,第9个SCL时钟就留给应答位:正常情况下,接收方会在第9个时钟把SDA拉低,称为ACK;如果SDA保持高,则是NACK。最后主机用停止条件(STOP)收场:SCL为高时,SDA从低拉高。
所以用示波器或逻辑分析仪测I2C时,心里要按这四个关键节点去切分波形:起始条件是否出现,地址字节和读写位有没有发对,数据字节一位一位读出来是什么值,以及每个字节后面的第9个时钟上SDA到底是低还是高。只要你形成了这个分段意识,抓到的波形就不再是一堆乱线,而是一帧可以逐格阅读的报文。
1.3 万用表、示波器、逻辑分析仪各能干到哪一步
工具选择决定了排查效率。我在不同场景下的使用习惯是这样的:
| 工具 | 擅长回答的问题 | 明显局限 |
|---|---|---|
| 万用表 | 供电是否正常、地线是否连通、上拉电阻是否在、空闲电平对不对 | 测不到毫秒级以下的脉冲,完全看不到时序和ACK |
| 示波器 | 起始/停止条件、时序边沿、ACK/NACK、毛刺和振铃 | 存储深度有限,长时间抓协议流比较吃力 |
| 逻辑分析仪 | 长时间记录、按协议解码出地址/数据/ACK,适合跑压力测试 | 看不到真实电压、上升沿质量和毛刺细节 |
三者不是替代关系,而是配合关系。我习惯先用万用表做“电气体检”,再用示波器做“时序诊断”,只在需要长时间分析大量I2C报文时,才把逻辑分析仪挂上去。工具越多,越要清楚当前这一步到底在排查哪个层面,否则就是拿着示波器干万用表的活,白白浪费精力。
2. 万用表先上场:三步筛掉明显电气故障
很多工程师一上来就直奔示波器,其实有相当比例的I2C故障在万用表阶段就能定位。尤其是那种“上电后设备纹丝不动”的情况,往往不是协议问题,而是供电、地线、上拉电阻这些基础电气环节出了岔子。先用万用表把这层滤掉,后面用示波器时才不会自乱阵脚。
2.1 上电测电源和空闲电平:两根线正常时应该是什么样
第一步,给板子正常上电,万用表打到直流电压挡,先确认器件的VDD脚电压对不对。这步看起来多余,但真遇到过因为LDO虚焊导致VDD只有1.2V、而设备偏偏还“半死不活”的情况。
第二步,把黑表笔接在靠近I2C器件的GND上,红表笔分别点SCL和SDA,测空闲电压。正常时两条线都应该接近上拉电压:3.3V系统约3.3V,5V系统约5V。如果你测到某条线电压明显比上拉电压低,比如只有1V左右,那基本可以断定这条线上有设备正在把它拉低,或者引脚已经被内部锁住。空闲电压不对,后面什么都免谈。
值得注意,测电压时表笔落点尽量靠近从机芯片引脚,不要图方便夹在排针或者杜邦线远端。曾经排查一块GT911触摸屏I2C通信失败的板子,排针处电压正常,但触摸屏附近SDA被异常拉低,问题出在触摸屏复位时序导致内部状态机异常,这一点靠万用表只能看到结果,具体原因还是得靠示波器后面抓。
2.2 断电测上拉电阻和短路:把隐藏的硬件坑揪出来
上电看电压只能发现问题,断电测电阻才能找出原因。先把板子断电,用万用表电阻挡或通断挡测三组数据:VDD对GND的阻值、SCL对VDD的阻值、SDA对VDD的阻值。后两项正常应该等于你板子设计的上拉电阻值,比如4.7k或10k。如果测出来是几百欧甚至更低,说明可能存在不正常的钳位或短路;如果显示超出量程,则说明上拉电阻很可能没焊上或焊盘虚焊。
测量时有个小技巧:先把有可能参与总线的设备逐个断开再测,尤其是带I2C电平转换的模块,很多模块上有保护二极管,在线测量会给你一个假性的低阻值。我遇到过一块板子,SDA对地测出不到10Ω,怎么看都像芯片烧了,最后把一颗ESD保护器件摘下来再测,阻值恢复正常,原来只是保护器件击穿,MCU和从机其实都完好。
2.3 万用表测不出来的部分:别被“电压正常”骗了
万用表最容易骗人的地方在于:它测出来一个值,看着“正常”,但完全无法告诉你这个信号是不是正确时序。因为I2C在100kHz下,一个周期只有10微秒,万用表的采样速度根本跟不上。就算SCL和SDA都测到约3.3V,也不代表总线在正常工作,可能只是两条线停在空闲高电平,压根没有事务发生。
另外,很多万用表的交流挡和直流挡采样逻辑不同,测数字信号时偶尔会出现莫名其妙的读数。我的建议是,万用表阶段只要确认三件事就够了:电源到没到、地线通不通、上拉电阻和不正常的短路存不存在。做完这三项,直接上示波器看时序,别在万用表上做过多纠结。
3. 示波器上场:探头怎么接、触发怎么设、波形怎么看
万用表把电气层筛完,示波器就是主战场。但示波器如果设置不对,很可能抓到的波形既不能稳定触发,也看不懂在说什么。我见过太多人拿示波器探头往SCL上一搭,自动挡按一下,屏幕上一堆密密麻麻的波形,根本没法分析。设置要按I2C的特点来。
3.1 探头连接和通道设置的实操细节
尽量用两个通道同时抓SCL和SDA,通道1接SCL,通道2接SDA。这样做的好处是你能直接看到两条线的相对时序,例如SDA在SCL高电平期间跳变到底发生在什么位置。如果只有一个通道,很多时序关系只能靠猜。
探头的地夹务必共地,且落点要靠近被测芯片的GND。高频测量时,地线夹子的电感会产生振铃,所以地线尽可能短。带宽方面,100MHz的示波器完全够用,I2C标准模式100kHz、快速模式400kHz,连1MHz的超快速模式都谈不上高带宽。反而是电压挡位要关注:3.3V系统把垂直挡位设成1V/格或2V/格,能看到完整高电平和低电平。
还有个小细节:探头建议打到10×衰减挡。探头的输入电容在10×挡下更小,对总线影响更小,而且你测的是3.3V信号,10×挡配合1V/格不会让波形顶到屏幕外。
3.2 触发电平和时基选择:示波器必须理解的核心参数
触发设不好,波形在屏幕上永远是一团乱晃。对I2C来说,最实用的是用SDA通道的下降沿触发,因为任何事务都是以SDA从高拉低这个START条件开头的。触发电平设在大概1/2总线电压的位置,3.3V系统就设1.5V左右。不要设太高,否则上升沿较缓时可能触发不稳定;也不要设太低,否则会把噪声也当成触发点。
时基的选择要看目的。想抓整个事务全局,100kHz时设每格0.5ms到1ms,把一帧完整的读写流水账尽收眼底;想细看起始条件、ACK位、数据位的电平翻转,时基要缩到每格2微秒到5微秒,不然屏幕上连每个时钟周期的分开样子都看不清。很多示波器都支持缩放功能,所以我一般先用长时基抓全局,抓下来以后再放大去看细节,这样比直接用小量程盲抓效率高得多。
3.3 用单次触发抓一帧完整I2C事务:排查偶发故障的可靠方法
排查偶发I2C异常时,示波器的自动触发模式往往不好用,因为波形不断滚动,等到你眼睛看到异常早就翻页了。正确做法是使用示波器的单次触发(Single)功能:先设置好SDA下降沿触发,按一下单次,然后去执行一次I2C读写操作,示波器会在触发条件满足的那一瞬间抓下完整波形,之后自动停止。
这个方法我屡试不爽。曾排查一块SSD1306 OLED偶发花屏的问题,屏幕平时能显示,但每隔一两分钟会出现一块乱码。把波形抓下来后发现,某一次写操作过程中,从机在第N个数据字节后没有回ACK,后续所有数据全部错位,导致显存数据被打乱。如果不用单次触发,这种偶发的NACK几乎不可能在自动模式下抓住。
需要提醒的是,单次触发时存储深度和采样率是一对矛盾。长时基抓全局,采样率可能被压缩得很低。抓I2C时采样率最好不低于100M Sa/s,也就是每10ns一个点,这样信号边沿失真可接受。示波器会标出当前采样率,留意一下就行。
3.4 别忽视逻辑分析仪:协议级排查的加速器
用示波器逐位读I2C报文是一件很辛苦的事,尤其你要连续看几百个字节的时候。逻辑分析仪的价值在于它可以按I2C协议自动解码,直接把地址、寄存器、数据、ACK显示成表格,省掉人工数时钟脉冲的麻烦。
但逻辑分析仪代替不了示波器。它只有高低电平判断,测不了1.8V还是3.3V,也看不到上升沿是不是软塌塌的。所以我养成的习惯是:先用示波器确认信号质量没问题,再用逻辑分析仪去抓长报文分析内容。如果信号本身质量问题没排除,逻辑分析仪解码出来的内容就不可信,让你误判问题方向。
4. 认准ACK这个“心脏”:从波形到故障定位
I2C调试中,几乎所有疑难杂症最后都会归结到ACK或NACK上。你可以把ACK理解成两个人对话时的“嗯,听到了”:发送方每说完一句话,都期待对方回一个“嗯”,听不到这个“嗯”,就说明对方要么不在线、要么没听懂、要么正忙得没空理你。所以掌握ACK的波形特征,等于掌握了I2C故障定位的第一把钥匙。
4.1 写一个字节的完整波形拆解:ACK到底长什么样
我拿最常见的写EEPROM举例:主机先发出START,然后发0xA0这个字节,其中高7位是从机地址0x50,最低位是写标志0。从机收到自己地址后会在第9个时钟把SDA拉低,这就是ACK。随后主机继续发寄存器地址字节,例如0x10,从机再回ACK。然后主机发数据字节0xAA,从机第三次回ACK。最后主机产生STOP。
关键在读法上:数据位看的是前8个时钟,SCL高电平时SDA的电平就是该位的值;第9个时钟高电平时SDA的电平就是ACK状态。如果SDA被拉低,说明从机应答;如果SDA保持高,说明从机没应答。这里有个常见误区,有人数脉冲只数8个,把第9个ACK时钟当成下一个字节的第一个时钟,导致怎么看都对不上。
4.2 ACK、NACK和“主机的NACK”:三种情况要分清
不是所有NACK都是故障。做I2C读操作时,主机读完倒数第二个字节后,会刻意不回ACK、释放SDA,从机看到主机不收,就不再发数据,随后主机发STOP。这里的NACK是主机主动制造的,属于通信流程的一部分,不代表出错。
真正的故障NACK主要出现在两种情况。第一种是地址阶段的NACK:从机不存在、地址写错、从机还没上电、复位时序不对,都会让第9个时钟上SDA保持高。第二种是数据阶段的NACK:有些EEPROM在写保护引脚被拉高时,地址字节照样ACK,但写数据字节时拒绝接收,直接回NACK。这种“半应答”状态最容易让人头痛,因为光看地址阶段一切正常。
判断技巧是看NACK出现在哪一级:如果地址字节后就NACK,问题大概率在寻址、电源、复位这条链路上;如果地址应答了但后续某个字节NACK,问题多半在从机内部状态,比如写保护、寄存器地址超范围、设备忙。
4.3 从ACK/NACK反推问题的排查路径
碰到持续NACK,我的排查顺序是这样的:先看第9个时钟上SDA是不是真的保持高,还是波形毛刺导致示波器解码误判。然后放大起始条件附近的波形,确认地址字节每一位是否正确,尤其注意7位地址和8位地址的差别。很多器件的地址除了硬件引脚决定的bit,还包含一个固定bit,算错一位就会看到地址阶段NACK。
如果地址对、ACK也有,但是读写结果不对,那就要检查寄存器映射和字节顺序了。曾经遇到一个传感器,数据手册写的是大端寄存器,代码按小端解析,导致读出来的温度值始终不对,而总线波形上每一个ACK都完美无缺。这提醒我们:ACK只代表“收到了”,不代表“理解对了”,协议格式问题在波形上未必一眼能看出来。
4.4 示波器I2C解码功能:该用但别迷信
现在主流示波器基本都带I2C解码功能,开启以后屏幕上会直接标出START、地址、数据、ACK/NACK等标签。对排查来说效率很高。开启方法一般在解码菜单里选I2C总线,指定SCL和SDA通道,再设置阈值电平(一般设总线电压一半)。有些示波器还会给出解码结果表格,方便快速浏览。
但我的建议是:解码功能用来定位“大概是哪一段出错”,真正的根因确认还是要回到原始波形上。解码是示波器内部软件根据阈值做的判定,如果信号有振铃、地线噪声大、触发电平设错,解码结果可能告诉你“这个字节是0x5A”,实际波形却是0x5B。遇到可疑问题,放大原始波形逐位读一遍,也是最踏实的一步。调试从机的时候,我还试过在主机发出地址后手动把SDA拉低来模拟ACK,用来验证主机的发送逻辑是否正常,这种“手动ACK”的办法在调试初期排除从机问题时很好使。
5. 完整排查流程与常见问题速查
前面把工具和方法讲了不少,这一节把它们串成一条完整的排查流水线,并整理一些高频故障现象。以后遇到I2C问题,可以按这个顺序一条条过。
5.1 从电气到协议的八步排查顺序
我把日常排查I2C的步骤固定成下面八步,按顺序执行,能最大程度避免漏查和误判:
- 确认供电和地线:用万用表量VDD、GND,排除掉电源虚焊和共地问题。
- 测空闲电平:上电后量SCL、SDA对地电压,正常应接近上拉电压。
- 断电查短路和上拉:量SCL、SDA对VDD的电阻,确认上拉电阻值合理,排除短路。
- 示波器看正常事务:单次触发抓一帧读写操作,确认START、地址、数据、STOP都在。
- 逐段核对ACK:先看地址字节后的第9个钟,再看每个数据字节后的第9个钟。
- 检查时序参数:对照数据手册,确认SCL频率、上升时间、建立保持时间是否满足要求。
- 做压力测试:连续读写几千次,看是否出现偶发NACK或数据错位。
- 软件层排查:确认初始化时序、寄存器配置、中断优先级是否干扰I2C通信。
这八步看起来简单,但真正做到位,至少能过滤掉九成以上的I2C故障。直接跳步的后果是,你明明排了好久,最后发现第一步就没过关。
5.2 高频故障速查表
把这些年搜集到的I2C排查案例整理成一张表,基本上覆盖了日常遇到的大部分问题:
| 现象 | 可能原因 | 优先检查方向 |
|---|---|---|
| SDA一直为低 | 有设备锁住总线、从机未复位导致状态机卡死 | 逐个断开设备,量SDA对地电阻 |
| SCL有波形但SDA无任何变化 | 从机没上电、上拉缺失、从机地址不匹配 | 先确认空闲电压,再放大看地址字节 |
| 地址字节后一直是NACK | 地址算错、设备未上电、总线时钟速率过快 | 查器件地址位,确认读/写位是否正确 |
| 数据字节后NACK | 写保护生效、寄存器地址非法、设备忙 | 查写保护引脚状态,参考寄存器手册 |
| ACK全部正常但数据不对 | 寄存器映射、大小端、位序理解错误 | 回读寄存器内容,和手册参数对比 |
| 一根线上加多个设备后失效 | 地址冲突、总线上拉能力不足、总线电容变大 | 检查从机地址配置,降低上拉电阻 |
| 高速模式偶发失败 | 线长过长、上升沿过慢、总线电容超标 | 降频测试,缩短走线,换更小的上拉 |
| 休眠唤醒后I2C卡死 | 外设状态机异常,需要复位 | 重新初始化或手动GPIO拉高释放总线 |
5.3 软件复位、时钟拉伸等容易踩的坑
排查到后期,很多问题出在软件和硬件交接的地方。一个典型就是总线锁死:某个从机在异常状态下把SDA拉低,这时候哪怕主机怎么发START都发不出去,因为起始条件要求SDA从高拉低,可SDA已经永远低电平了。很多人的第一反应是给MCU的I2C外设做软件复位,但恢复的是主机内部状态机,从机还卡着呢,总线依旧是死的。
正确做法是先把SDA释放出来:把SCL多翻转几次,或者临时把SDA和SCL配成GPIO输出高电平,让从机状态机复位,再切回I2C功能。只要硬件本身没有烧毁,绝大多数总线锁死都能这样救回来。还有一些从机支持时钟拉伸,也就是从机在准备数据时会把SCL拉低,让主机等一等。如果你抓波形时发现SCL低电平时间莫名很长,先别认定是故障,查一下从机是不是在时钟拉伸。
这几年调过EEPROM、OLED、触摸屏、各类传感器,I2C排查的大致套路基本没变过。我个人最坚持的一个习惯是:不管问题多玄乎,永远先量空闲电平,再上示波器抓完整事务,最后才动代码。顺序反了,轻则白费功夫,重则把正常工作的总线改出新的故障来。如果你手头正有一块调不通的板子,不妨按这个流程走一遍,很多时候答案就在第一步的万用表读数里。