多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

用示波器调试I2C:从波形抓到故障根因的完整实战指南

用示波器调试I2C:从波形抓到故障根因的完整实战指南 开头干嵌入式这行的谁还没被I2C折磨过几回一个传感器早上还能读到数据下午就飘了EEPROM偶尔写进去读不出显示屏初始化时好时坏。这种间歇性故障最恶心代码翻来覆去查不出毛病最后多半是总线时序、上拉电阻或者电平匹配的锅。这种时候与其对着代码干瞪眼不如直接上示波器看波形——I2C是标准协议波形长什么样、哪里不对全都写在屏幕上了。这篇文章我结合自己调试I2C的实际经历从示波器探头的接法、触发的设置、时序的测量到用波形定位具体故障一步步拆给你看。适合刚接触I2C调试的硬件工程师和嵌入式开发也适合那些被总线问题折磨到想转行的朋友——看完你会发现很多棘手的I2C问题一根探头、几个按键就能查得明明白白。1. 整体设计思路示波器调试I2C的底层逻辑1.1 为什么调试I2C首选示波器而不是逻辑分析仪很多人一提到调试I2C第一反应是拿逻辑分析仪。确实逻辑分析仪能直接解码I2C数据帧看着地址、寄存器、数据清清楚楚但它在某些关键场景下会误导你。逻辑分析仪采样的是数字电平它对模拟世界里的信号质量完全不敏感。总线上的过冲、振铃、缓慢的上升沿、电平没有完全被拉低在逻辑分析仪眼里统统被“修正”成标准的高电平或低电平。如果总线上存在严重的信号完整性问题逻辑分析仪可能照样把数据解出来但你的系统却是时好时坏——这种问题用逻辑分析仪根本发现不了。示波器则是这个领域的“照妖镜”。它能看到真实的电压变化过程SDA/SCL线上的上升沿到底有多慢是否满足I2C协议规定的最大上升时间电平被拉低后是否真的低于从机的VIH阈值通常为0.3VDD有没有振铃、过冲、毛刺是否会造成额外时钟周期起始条件和停止条件附近的信号是否干净I2C的本质是开漏输出加上拉电阻靠多个设备共同驱动总线的线与逻辑工作所以信号质量直接决定了通信的成败。示波器能把这些模拟问题看得一清二楚这就是我把它放在第一优先级的原因。1.2 I2C调试的完整链路代码、波形、器件三要素实际调试I2C时问题可能出在三个层次软件时序逻辑不对、硬件信号质量不达标、器件本身不按套路出牌。示波器调试的核心价值就是帮你把这三个层次拆开快速定位是哪一环出了问题。以我调试一颗气压传感器的经历为例。现象是单片机读到的数据偶尔全是0xFF排查时我先在代码里加了读ID的测试命令然后用示波器抓SCL和SDA波形。发现波形上总线的地址帧、寄存器地址帧都是正确的但主机发出读方向位后从机始终没有拉低SDA做ACK应答——问题直接从“软件怎么不对”变成了“从机为什么不应答”。接下来我量了传感器供电电压发现只有1.6V而芯片最低工作电压是1.8V。换一颗正常供电的传感器再抓波形ACK立刻出现了。这个案例说明用示波器调试I2C要遵循一个基本思路先确认波形时序是否符合协议再确认电平是否满足双方阈值最后才回到代码和器件本身。这三要素缺一不可但波形永远是最客观、最不会被代码逻辑掩盖的证据。2. 波形分析基础I2C时序图和关键测量项2.1 从波形上一眼认出的I2C协议要素如果你已经熟悉I2C协议这部分可以快速扫过如果还不太熟建议仔细理解因为后面所有的调试都建立在这些波形特征之上。I2C总线由两根线组成SCL时钟和SDA数据。空闲状态下两根线都被上拉电阻拉到高电平。通信开始后波形上有几个标志性的时间点起始条件STARTSCL保持高电平时SDA从高电平跳变到低电平。这是所有通信的开始标志波形上非常显眼。停止条件STOPSCL保持高电平时SDA从低电平跳变到高电平。表示通信结束。数据位传输SCL为高电平期间SDA上的电平必须保持稳定SCL为低电平期间SDA允许变化。也就是说SCL高电平期间读SDA才是有效的。应答位ACK主机发送完一个字节8位数据后在第9个SCL时钟周期释放SDA由从机拉低SDA表示“我收到了”。如果从机没拉低SDA保持高电平就是NACK。掌握这几个特征你就能在示波器上手工解码一段完整的I2C波形。我用过的最笨但最有效的办法是把示波器时间轴放大一格一格数SCL脉冲然后在SDA高电平时记1、低电平时记0手动拼出完整的字节。虽然慢但能逼你把协议理解得非常透彻之后再配合示波器的解码功能效率就上来了。从调试角度看第一眼扫波形时先找这几个关键点有没有正常的起始和停止条件每个字节的第9个脉冲SDA有没有被拉低SCL上是否存在多余毛刺。这三个点能筛掉一大批低级问题。2.2 上拉电阻与电平阈值的波形特征I2C规定使用开漏输出加上拉电阻这决定了波形上升沿是被动缓慢上升的不是主动驱动。上升沿的斜率直接取决于上拉电阻阻值和总线等效电容的乘积也就是时间常数τ R × C。标准I2C协议对上升时间有明确要求标准模式100kHz最大上升时间1000ns快速模式400kHz最大上升时间300ns快速模式1MHz最大上升时间120ns用示波器测量上升时间时我喜欢把时基调到比较高的分辨率比如每格200ns或者500ns然后打开“上升时间”测量项直接读数值。如果测出来的上升时间接近甚至超过协议上限总线信号质量就有问题可能导致通信不稳定。电平阈值的波形特征也很明显。正常工作的I2C总线低电平应该被拉低到0.4V以下VOL最大0.4V高电平应该接近VDD。如果低电平降不下去、停留在1V左右说明从机的开漏输出能力不足或者总线上挂的负载太重。这时候噪声余量已经很小了稍微有点干扰就会误判电平。我见过一个典型场景一颗MCU的GPIO没有配置成开漏模式而是复用成了推挽输出结果总线低电平被硬拉得更低、高电平也被强驱表面上看波形更“方”了但这时总线已经不是真正的线与逻辑了多主机场景下会直接烧驱动管。如果看到SCL/SDA波形异常尖锐、完全不是RC充放电的曲线先检查软件里的GPIO模式配置这问题在波形上真的藏不住。2.3 100k与400k速率下示波器带宽和采样率怎么选示波器本身的带宽和采样率是很多新手忽略的参数。I2C虽然速率不高但上升沿很陡而上升沿里含有丰富的高频分量。如果示波器带宽不够上升沿会被显示得比实际更缓从而误判信号质量。这里有一个经验公式示波器带宽至少要是信号最高频率的5到10倍。对100k/400k的I2C来说信号频率并不高但算上谐波建议至少用100MHz带宽的示波器。如果你手里的示波器只有20MHz带宽抓I2C波形不是不能用但上升时间显示出来会明显偏缓这时候不宜直接拿示波器测出来的上升时间去判断协议合规性误差太大。采样率方面现代数字示波器都是带宽的10倍左右比如100MHz带宽配1GSa/s采样率这对观察I2C波形是绰绰有余的。我反而更建议你关注存储深度因为I2C调试经常要抓一整段完整通信一帧包含地址、寄存器、多个数据字节时间跨度可能从几十微秒到几毫秒。存储深度不够的话示波器为了显示整段波形会自动降低采样率导致细节丢失。抓完整帧用“深存储”模式然后缩放看细节这是我的常用操作。3. 实操过程用示波器抓取和测量I2C波形3.1 硬件连接探头接哪根线、地线怎么夹我先从最基本的连接开始讲别嫌啰嗦探头接不好后面全白搭。I2C有两根信号线SCL和SDA再加上公共地。示波器用两根探头分别接SCL和SDA地线夹子直接夹到板子上的GND测试点或排针的GND上。如果探头只有一根也可以只接SDA或SCL先确认一路信号是否正常再换到另一路去测。这里有几个关键细节探头的接地线要尽量短。我见过不少人把示波器探头的地线夹子拉出一长条飞线接到很远的GND点。这根长地线会引入过大的电感导致测高电平毛刺还会给自己引入额外的噪声。正确做法是在板子上找一个离SCL/SDA测试点最近的GND点比如旁路电容的接地端、排针旁边的GND孔让地线夹子尽量短。通道的衰减比要设置正确。探头打到1×还是10×示波器通道菜单里就要选成对应的档位不然显示的电压幅值会偏得离谱。I2C这种低速信号我用10×挡比较普遍因为输入阻抗更高对电路的负载效应更小。两根探头尽量都用10×挡保证两路的延迟不一致和负载一致。有些示波器探头本身有可调电容补偿先用示波器自带的1kHz方波校准信号校准一下让波形上升沿没有过冲或者塌陷再上板子。接好之后最好先静态测一下空闲状态下的电平。如果SDA和SCL都接近VDD说明上拉正常如果电压偏低说明总线漏电或者器件没有正确释放总线这时候后面抓的波形大概率也是乱的。3.2 触发设置让示波器稳定显示I2C通信波形接好线之后最头疼的问题通常是怎么让示波器稳定地显示波形。如果你只把时基调到合适范围示波器会乱跳很难看清一个完整的通信帧。解决思路是用触发功能。I2C协议有明确的起始条件也就是SCL高电平时SDA的下降沿。所以最常见的触发方式是设置边沿触发触发源选SDA通道触发类型选下降沿触发电平设在VDD的一半左右。这样示波器每当检测到SDA下降沿就会刷新一次波形由于起始条件是唯一的波形就能稳定显示。如果你的示波器自带I2C触发功能那就更简单了在触发菜单里选择I2C设置触发条件为起始条件START示波器就会自动寻找I2C起始位的特征来触发比单纯的边沿触发更准确尤其是总线上有其他毛刺干扰时I2C触发能有效过滤掉无关的下降沿。时基怎么调先大概估算一下一帧通信需要多长时间。100kHz标准模式下传一个字节需要10个时钟周期8位数据加1位ACK也就是大约100us。如果一次通信有5个字节总时长约500us加上起始和停止位时基设置在50us/格到100us/格之间比较合适。400kHz快速模式下时基相应缩短到20us/格到50us/格。设置好之后让设备板正常运行并周期性地发起I2C通信你会发现波形稳定地“锁”在屏幕上了。再按一下示波器的Single单次触发按钮可以在触发后只抓一帧波形非常适合分析单次通信。3.3 用测量项和光标快速验证时序参数波形稳定显示后不要光看形状要学会用示波器的测量功能和光标去量化参数。光看“波形好像是这么回事”是不行的要用数据说话。我常用的测量项组合是这样设置的以SCL通道为测量源频率直接读出实际的总线时钟频率用来确认代码里配置的100k还是400k是否真的符合预期。上升时间测量SCL和SDA的上升沿时间和协议规定的最大上升时间做对比。低电平电压和高电平电压快速验证电平是否满足VIH/VIL要求。周期和占空比观察时钟信号是否对称不过I2C对占空比要求没有SPI严格这个条件一般作为参考。光标功能一般用来测量两个事件之间的时间。比如我想确认停止条件后经过多长时间才开始下一次起始条件把X1光标放在停止条件的SDA上升沿X2光标放在下一个起始条件的SDA下降沿差值就是总线空闲时间。如果空闲时间太短从机可能来不及处理上一帧数据导致下一帧无应答。验证时序合规最核心的寄存器级测量是确认SCL高电平期间SDA保持稳定。把时基放大观察每个字节的数据位在SCL高电平期间SDA不应该发生跳变。如果看到SCL高电平时SDA在变化说明从机写入数据有问题或者总线上存在毛刺干扰这在波形上是明显的“重影”——SDA在高电平时段出现不稳定的抖动或双沿。3.4 实际案例从波形图定位EEPROM偶发写失败讲一个我亲身经历的实战这样大家能更直观地理解波形分析到底怎么用。当时的现象是系统上电后往EEPROM里写配置数据大约每五次有一次写失败读回来全是0xFF。代码是在多块板上复制的换一个板子就正常说明代码逻辑本身没问题问题出在这块板子的环境上。我先用示波器同时抓SCL和SDA触发设在SDA的下降沿Single模式抓了一整帧写操作。从波形上看START条件正常地址帧0xA0写方向发送后在第9个时钟周期SDA被拉低ACK正常寄存器地址0x00发送后ACK也正常然后传第一个数据字节0x5AACK也正常。看起来一帧波形完全没问题。注意这里的细节如果整帧都正常为什么写入会失败我把时基放大到每个字节的波形仔细观察每个字节最后一位和ACK位之间的过渡。结果发现了问题在第几个数据字节传输时SDA线在SCL高电平期间出现了大约300mV的毛刺而在这个毛刺后ACK位从机依然应答了但EEPROM内部可能识别成了乱的命令导致写入数据没有被正确存储。这个毛刺从哪来我进一步排查发现这块板子的I2C总线上同时挂了一个电机驱动板而电机PWM切换时会对整个板子的电源轨造成纹波干扰。SDA线上的毛刺实际上是电源噪声通过总线上拉电阻耦合进来的。解决方法是给I2C上拉电阻的VDD侧加一个100nF的去耦电容并适当增加上拉电阻阻值同时给电机驱动板单独加滤波。改完后反复写了几千次一次失败都没有。这段经历说明波形分析不能只停留在“有没有波形”的层面要到“波形的每个细节是否干净”的层面。毛刺、抖动、电平偏移这些看似微小的异常往往才是间歇性故障的真正元凶。4. 常见问题与排查技巧实录4.1 I2C常见故障波形问题速查表这几年调过的I2C问题不少我把常见故障现象和对应的波形特征整理成一个速查表大家在现场可以直接对照排查。故障现象波形特征常见原因排查方向总线完全无响应SCL和SDA都保持高电平看不到任何翻转程序没启动I2C外设或GPIO复用配置错误上拉电阻缺失检查代码初始化用万用表确认上拉电压SCL有时钟SDA一直是高有SCL脉冲但SDA始终不拉低从机地址不匹配从机未上电总线地址冲突核对从机地址引脚配置和手册地址确认从机供电波形有但ACK缺失每个字节第9个时钟SDA保持高电平从机忙碌未准备好寄存器地址不存在总线速率过快从机跟不上降低传输速率试一下检查寄存器地址是否正确SDA/SCL上升沿缓慢上升沿呈明显的RC充电曲线爬升时间远超协议要求上拉电阻过大总线电容太大减小上拉电阻检查总线上挂载器件数SCL高电平时SDA发生跳变数据位与时钟位对齐关系错乱波形出现重影从机输入建立时间不足代码中数据切换时机错误降低通信速率在起始和停止条件前后加延时低电平拉不下来空闲正常但通信时低电平只有1V左右总线过载从机驱动能力不足上拉电阻太小导致灌电流过大增大上拉电阻逐颗摘除从机排查波形频繁出现毛刺SCL或SDA上出现额外窄脉冲电源噪声长走线串扰探头地线过长引入干扰检查电源纹波改进探头接地给上拉电源加去耦这张表我用过很多次现场调试时拿着表一项一项对照比自己瞎猜快得多。4.2 排查实录上拉电阻小了导致通信不稳定的完整过程热词里有一条“i2c上拉电阻小了不通信”这正好是我遇到过的一个经典案例。有一次给一个开发板调I2C温湿度传感器代码逻辑是从官方例程移植的按说不会有问题但传感器数据就是偶尔读到全0。我抓波形时发现一个很反常的现象SDA的下降沿有一个明显的阶梯——电压不是干净地降到0V而是先降到大约1V左右停留一两个微秒再继续往下掉。SCL的上升沿也特别慢看起来像总线上挂了一个很大的电容。我量了板子上的上拉电阻发现用的是1kΩ按照标准100kHz模式1kΩ其实不算夸张。问题在于这块板子的I2C总线上除了传感器还接了一个带I2C接口的IO扩展芯片和一块小屏三个器件并排挂在同一条总线上总线的分布式电容加起来有600多pF。虽然1kΩ的上拉在纸面上也能满足100kHz的上升时间要求——我们来算一下tR ≈ 0.8473 × R × C 0.8473 × 1000 × 600p ≈ 508ns确实小于1000ns的上限——但实测数据为什么还是不稳定进一步排查发现问题出在器件灌电流能力上。I2C协议规定低电平VOL最大不能超过0.4V在3mA灌电流条件下。但我这个电路上1kΩ上拉在VDD3.3V时灌电流达到(3.3-0.4)/1000≈2.9mA接近3mA的极限。而实际用的传感器芯片在高温下驱动能力下降VOL可能超过0.4V导致从机识别低电平不可靠。解决方法是把上拉电阻从1kΩ换成2.2kΩ重新计算tR ≈ 0.8473 × 2200 × 600p ≈ 1.118us正好勉强符合1000ns左右的要求。改完后波形干净了很多低电平阶梯消失通信稳定了。代码上我也把速率从100k降到更保守的80k留出余量。这个案例告诉你上拉电阻不能只算上升时间还要算灌电流和VOL余量。小上拉确实能让上升沿更快但会让低电平变得不够“低”反而引发更隐蔽的问题。4.3 从波形反推软件问题死锁和延时配置判断经验不足的朋友往往以为波形不对就是硬件问题其实很多波形异常是从软件里“写”出来的。我经常干的一件事是用示波器去验证代码里的时序延时是否真的符合预期。最典型的例子是软件模拟I2C。很多单片机没有硬件I2C外设或者硬件I2C被复用了只能用GPIO模拟时序。模拟I2C的代码里有一堆延时函数比如时钟高电平保持时间、数据建立时间、停止条件后的总线释放时间。这些延时如果写得太短波形上就会有明显的异常SCL高电平时间极短甚至出现SDA在SCL高电平时翻转的情况。用示波器验证方法非常简单直接量SCL高电平和低电平各自持续的时间看是否和代码里配置的延时一致。比如代码里写的是延时尚空着如果标称5us但波形上量出来只有800ns说明延时函数被编译器优化了或者系统时钟配置和预期不符。这时候要在延时函数里加volatile声明、或者用定时器做精确延时才能保证时序正确。还有一种情况是软件I2C和硬件I2C混用导致的死锁。比如某段代码先用软件模拟I2C发送了起始条件但因为异常分支跳转没有发送停止条件就退出了。这样总线上SDA一直处于低电平变成了一种“总线占用”状态。之后切回硬件I2C发起通信时硬件I2C检测到SDA被占用会一直等待总线释放表现为程序卡死在I2C等待标志位的地方。这时候示波器上能看到SDA恒为低SCL没有时钟输出。解决办法是在系统初始化I2C前手动把SDA和SCL配成普通GPIO输出各发送9个时钟脉冲强制让挂在总线上的从机释放总线再切回硬件I2C模式。这个技巧在很多MCU平台上都通用算是软件级“总线复位”。还有一个和调试相关的实用场景当程序跑飞进入HardFault时很多人会一脸懵但如果I2C当时正在传输数据从波形上能看出一些端倪——SCL停在低电平或高电平不动、SDA悬在半空、起始条件之后没有后续时钟这些都是程序异常退出的痕迹。配合HardFault的调试信息去查代码比盲猜指针的问题要快得多。4.4 Keil调试助手不够用时用示波器补足最后的证据链这个热词组合“keil调试助手里面的debug模式如何显示结构体变量”和“串口调试助手”结合起来说一句调试器能告诉你软件在干什么但示波器能告诉你硬件到底发生了什么两者是互补的。用Keil的Debug模式可以查看I2C外设寄存器的值、当前发送缓冲区的数据、结构体变量里的指针地址等等。比如你在代码里定义了一个结构体存传感器校准数据Debug模式里右键变量选择“Add to Watch”窗口展开就能看到结构体的每个成员值。如果读回来的数据全是一致的0xFF很有可能是I2C通信失败导致缓存区没有被正确写入。但Debug模式有一个局限它只能看到MCU内部的状态看不到总线上真实的电信号。我曾经遇到过一个现象Debug模式下看I2C发送数据寄存器已经装入了0xA0程序运行正常但从机就是不响应。如果只看调试器你可能会怀疑是地址写错。用示波器一抓才发现MCU输出的地址字节里第0位读写方向位的正确值是0写但代码里由于结构体指针错位实际发送的地址是0xA1读方向导致从机没有匹配。这种问题通过Debug模式看寄存器是能发现的但波形证据更直观、更可靠。所以我建议的调试组合拳是先用Keil的Debug模式看代码执行流程和变量值确认软件逻辑没问题再用示波器抓总线波形确认物理层是否真的按协议工作。两边证据对齐了问题定位就八九不离十了。5. 更实用的技巧与经验总结5.1 低速信号调试中Single和Roll模式怎么用不少人的示波器买了几年就只会用Auto触发模式遇到低频信号就开始抓瞎。这里我单独说两个在I2C调试中非常实用的模式Single和Roll。Single单次触发模式适合抓取“只有一次”或者“间歇性出现”的通信事件。比如系统上电后只在启动阶段读一次传感器的ID正常运行时不再读取。这种一次性事件在Auto模式下很难稳定显示因为大部分时间总线都是空闲的高电平示波器只能在触发后显示一次波形。用法是先接好探头选好触发条件SDA下降沿把水平时基调到覆盖整个通信周期的范围然后按“Single”键示波器进入等待触发状态。接着重启板子或者执行一次读操作示波器会在触发后把这一帧完整记录下来。这里要提醒一句如果数据帧时间超过屏幕宽度可以用“时基放大”或“Zoom”功能在保持采样率的情况下缩放查看波形细节。Roll滚动模式则适合观察极慢速的信号。比如你用GPIO模拟I2C在很低速率下通信甚至每秒只有几十个字节常规时基下波形看起来就像一条直线一个脉冲都看不到。Roll模式下屏幕会像心电图一样从左往右滚动显示最新数据你能直观地看到SCL和SDA随时间缓慢变化的过程判断它们是否在正常翻转。不过Roll模式下波形是滚动的没法做精细测量一般用于初步判断“这条线上有没有信号在动”真正要量参数还得改用普通模式并调小水平时基。5.2 逻辑分析仪与示波器的搭配使用思路前面我说了示波器的不可替代性但也不是说逻辑分析仪就没用了。两者配合才是效率最高的方案。逻辑分析仪的优势在于解码能力。你可以在屏幕上直接看到I2C地址、读写方向、寄存器地址、数据内容、ACK/NACK的状态几十个字节的通信一屏就能看完非常适合验证通信内容是否符合预期。示波器虽然也有解码功能但解码速度和解码长度通常有限几十帧数据逐个看很费劲。我常用的组合方式是先用逻辑分析仪跑一遍完整的通信过程快速确认“软件发出的内容对不对”。如果解码结果全部正确、但设备依然工作异常再上示波器看信号质量。如果是信号质量问题引发的不稳定通常逻辑分析仪解码会偶发出错——比如某一位被误判——这时候示波器就要上场了重点看上升沿、毛刺和低电平电压。有些示波器本身支持I2C触发和解码比如鼎阳、普源的中高端型号这种就一台机器搞定。但如果你手头的是基础款示波器没有I2C触发解码功能也没关系用边沿触发加手工分析的方式完全够用无非是慢一点而已。我最初学I2C调试时用的就是一台没有I2C功能的简易示波器手动数时钟脉冲、手动拼数据字节很多细节反而是这么学明白的。5.3 上手实践的几个小建议看到这里你可能有点迫不及待想拿示波器试试了。我就以过来人的身份给你几点非常具体的建议。第一找一个I2C从机设备比如EEPROM或者传感器模块主动在代码里写一个循环反复发送写数据再读回的操作故意在循环里加一个断点或者延时给示波器留出足够的观察时间。你不需要一次抓太多数据一帧写操作加一帧读操作就足够了。第二别急着换参数先把正常的波形彻底看明白。SCL的时钟长什么样、SDA数据怎么和时钟对齐、ACK位在哪、START和STOP长什么样这些看得足够熟后面再遇到问题才判断得准。我见过很多工程师拿示波器抓波形看到有波形就以为总线在工作结果连起始条件都没找到这就是基本功不扎实。第三主动制造几个故障来练习。比如故意把上拉电阻换成10kΩ或100Ω观察上升沿和电平的变化故意把从机地址写错观察ACK缺失的波形故意把速率配成1MHz观察从机跟不上的表现。用示波器把这些异常波形都记录下来和正常波形对比形成肌肉记忆。真到了现场调试的那一天你会感激自己的这些练习。5.4 从波形到结论我常用的排查顺序最后总结一下我个人最常用的I2C排查顺序算是一个浓缩的“武功秘籍”先确认总线空闲电平SDA和SCL都应该接近VDD。只要有一条不对劲先解决上电和上拉问题。再确认Start条件是否出现SCL高电平时SDA是否有一个干净的下降沿。没有Start从机根本不会理会总线上的任何变化。再确认时钟是否正常SCL的频率是否和预期一致有没有多余的毛刺或脉冲。时钟不稳数据再准也白搭。一步步解码地址字节和数据字节对照协议核对内容。发出去的地址对不对、读写方向对不对波形上一目了然。检查ACK每个字节后从机有没有拉低SDA应答。没有ACK是排查重点需要从设备供电、地址匹配、通信速率这几个方向找原因。最后看信号质量上升沿时间、低电平幅值、毛刺情况。这一步最容易忽略但也最容易解释间歇性故障。我在实际调试中没少走过弯路印象最深的一次是在一个凌晨为了查一个I2C偶发故障反复换代码、反复刷固件折腾了三个小时。后来冷静下来老老实实把示波器接上只看波形没花二十分钟就把问题定位到了——是某颗器件在上电时序未完成时就收到了通信请求导致它错误地拉低了SDA从而阻塞了整条总线。从那以后我调试任何I2C问题都先把波形抓到手里再谈其他。记住波形不会骗你它只会忠实反映总线上真实发生的一切。
返回列表