ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

I2C总线从开漏到多主仲裁:嵌入式工程师踩坑与实战指南

I2C总线从开漏到多主仲裁:嵌入式工程师踩坑与实战指南 I2C这东西刚入行的时候觉得它简单得不行——两根线一根时钟一根数据挂一堆从机地址一喊谁应答谁说话能有多难结果真到了项目里SCL被拉死、总线锁死、多主机打架、上拉电阻选错导致波形爬不起来、逻辑分析仪抓出来一堆莫名其妙的START才发现这两根线背后藏着的门道比很多协议都深。这篇就把我这些年踩过的坑、翻过的数据手册、用逻辑分析仪一帧一帧抠出来的经验从开漏物理层一路讲到多主仲裁尽量把I2C彻底讲透。不管你是刚接触单片机的学生还是被I2C总线锁死折磨过的嵌入式工程师看完应该都能对这两根线有个全新的认识。1. 为什么I2C非得用开漏输出推挽不行吗很多人学I2C的第一反应是既然SCL和SDA都是输出高低电平那用普通推挽输出不就行了我一开始也这么想过直到有一次用推挽驱动I2C两个设备同时想拉低总线一个输出高一个输出低直接短路芯片烫得能煎鸡蛋。从那以后我才真正理解开漏的意义。1.1 开漏输出的物理本质开漏Open-Drain在CMOS工艺里叫开漏在TTL工艺里叫开集Open-Collector本质是一回事输出级的MOS管只有下拉能力没有上拉能力。也就是说这个引脚只能主动把线拉到地逻辑0没法主动把线拉到VCC逻辑1。想要高电平必须靠外部的上拉电阻把线拉上去。这个设计乍看很反直觉——为什么要把输出能力阉割掉一半答案就在I2C的核心需求上多设备共享总线。想象一条走廊两边有很多房间每个房间的人都只能关门拉低不能开门拉高。门默认是弹簧开着的上拉电阻只要没人关门就是开的高电平。任何一个人关门门就关上了低电平。这样无论多少人同时想关门结果都只是门关着不会出现一个人想开一个人想关的冲突。这就是开漏的精髓——线与逻辑。如果换成推挽每个房间的人既能开门又能关门那一个人想开、一个人想关门就被硬生生掰断了对应到电路上就是两个MOS管一个导通到VCC一个导通到GND形成低阻通路大电流烧毁器件。1.2 上拉电阻到底怎么选开漏输出必须配上拉电阻这个电阻的取值不是随便拍脑袋的它直接决定了波形的上升沿质量和总线能否正常工作。选大了上升沿爬不上去高速通信直接失败选小了低电平灌电流太大器件可能扛不住。上拉电阻的最小值由灌电流决定。I2C标准规定标准模式100kHz和快速模式400kHz下器件拉低时灌电流一般不超过3mA快速模式1MHz和高速模式3.4MHz另有规定。假设VCC是3.3VVOL低电平输出电压最大0.4V那么Rmin (VCC - VOL) / IOL (3.3 - 0.4) / 0.003 ≈ 967Ω所以3.3V系统下上拉电阻一般不小于1kΩ。上拉电阻的最大值由上升时间决定。I2C的上升时间有明确上限标准模式1000ns快速模式300ns快速模式120ns。上升时间由RC充电决定公式是tr ≈ 0.847 × R × C其中C是总线总电容包括走线电容、引脚电容、器件电容标准规定总线电容不超过400pF。假设C200pF快速模式要求tr≤300nsRmax tr / (0.847 × C) 300ns / (0.847 × 200pF) ≈ 1771Ω所以这个场景下上拉电阻要在1kΩ到1.77kΩ之间选通常取1.5kΩ或1.8kΩ。实际工程里我一般这么选模式速率典型上拉总线电容上限标准模式100kHz4.7kΩ400pF快速模式400kHz2.2kΩ400pF快速模式1MHz1kΩ550pF高速模式3.4MHz300Ω左右100pF注意上拉电阻不是越小越好。我曾经为了追求上升沿陡峭把上拉降到470Ω结果从机拉低时灌电流超过10mA用了半年后从机引脚出现间歇性失效。后来老老实实按灌电流上限反推才稳定下来。1.3 总线电容这个隐形杀手总线电容是I2C设计里最容易被忽略的参数。每挂一个器件引脚电容大概5到10pF每厘米PCB走线大概1到2pF如果用了排线或者飞线电容更大。挂十个器件加上走线轻松超过100pF。总线电容大了会怎样上升沿变缓波形变成圆肩逻辑分析仪上看就是上升沿拖泥带水。速率低的时候还能凑合一旦上到400kHz上升时间超过300ns从机可能还没采到高电平主机已经开始下一个时钟了通信直接崩。解决办法有几个一是减少挂载器件用I2C多路复用器比如TCA9548A把总线分成几段每段单独上拉二是缩短走线把器件尽量靠近三是降低速率用100kHz换稳定性。我做过一个项目总线上挂了12个传感器400kHz死活跑不通换成100kHz立刻稳定后来加了多路复用器才把速率提回去。2. SCL和SDA的时序到底谁说了算I2C的时序规则看起来简单但真正理解谁在什么时候控制哪根线是写出稳定驱动和快速定位问题的关键。很多人调I2C调不通根本原因就是没搞清楚SCL和SDA的控制权在主机和从机之间是怎么切换的。2.1 起始条件和停止条件的本质起始条件START的定义是SCL为高时SDA由高变低。停止条件STOP的定义是SCL为高时SDA由低变高。为什么这么定义因为正常传数据的时候SDA只在SCL为低的时候变化SCL为高的时候SDA必须稳定这样接收方才能在SCL高电平期间采样到有效数据。起始和停止条件故意违反这个规则就是为了在不占用额外信号线的情况下标记一帧数据的开始和结束。这里有个细节很多人不知道起始和停止条件永远由主机产生。从机只能被动响应不能主动发起或终止传输。这也是为什么I2C是多主总线但实际应用中绝大多数场景都是单主机——多主机仲裁机制虽然存在但实现复杂一般项目用不上。2.2 数据位的采样时机数据位的传输规则是SDA在SCL低电平期间改变在SCL高电平期间保持稳定。接收方在SCL高电平期间采样SDA。这个规则决定了主机和从机的操作节奏主机发送数据时主机在SCL拉低后改变SDA然后拉高SCL从机在高电平期间采样。从机发送数据时从机在SCL拉低后改变SDA主机在SCL拉高后采样。注意SCL始终由主机控制除了时钟拉伸的情况从机只是借用SCL低电平的窗口来改变SDA。2.3 时钟拉伸从机唯一的反抗手段时钟拉伸Clock Stretching是从机唯一能主动干预总线节奏的机制。当从机需要更多时间处理数据时它可以在主机释放SCL后继续把SCL拉低主机检测到SCL没有按预期变高就知道从机还没准备好于是等待。这个机制在EEPROM写操作、传感器转换等待等场景很常见。比如AT24C系列EEPROM写一个字节后需要5ms左右的内部写周期期间从机就会拉低SCL主机必须等它释放才能继续。但时钟拉伸也是坑最多的地方。有些主机的I2C外设不支持时钟拉伸或者支持得不完整遇到从机拉低SCL就报超时错误。我遇到过STM32的硬件I2C在某些情况下处理时钟拉伸有问题最后改用软件模拟I2C才解决。所以选型的时候一定要确认主机的I2C控制器是否完整支持时钟拉伸。提示如果你的从机需要时钟拉伸但主机不支持可以考虑降低通信速率给从机留足处理时间或者改用软件模拟I2C自己控制时序。2.4 建立时间和保持时间的实际约束I2C标准对建立时间tSU和保持时间tHD有明确规定参数标准模式快速模式快速模式数据建立时间 tSU:DAT250ns100ns50ns数据保持时间 tHD:DAT0ns0ns0ns起始条件建立时间 tSU:STA4.7μs0.6μs0.26μs起始条件保持时间 tHD:STA4.0μs0.6μs0.26μs注意tHD:DAT是0ns意思是数据在SCL下降沿之后可以立即改变不需要额外保持时间。但tSU:DAT要求数据在SCL上升沿之前必须稳定足够长时间标准模式是250ns。这些参数在低速的时候很容易满足但速率一上去就紧张了。特别是用软件模拟I2C的时候如果GPIO翻转速度不够快或者中断打断了时序很容易违反这些约束。我的经验是软件模拟I2C在100kHz下比较稳400kHz就要小心了1MHz基本别想。3. 多主仲裁两根线怎么做到不打架多主仲裁是I2C最精妙的设计之一也是很多人觉得这也能行的地方。多个主机同时想通信怎么保证不冲突答案是靠开漏的线与特性和一套逐位仲裁规则。3.1 仲裁的基本规则仲裁发生在SCL为高的时候。每个主机在发送每一位数据后都会回读SDA的实际电平和自己发送的电平比较如果自己发的是高但读回来是低说明有别的设备把它拉低了自己仲裁失败立即退出转为从机模式。如果自己发的是低读回来也是低说明要么没人竞争要么别人也发了低继续。如果自己发的是高读回来也是高继续。关键点仲裁失败的主机不会破坏总线上的数据。因为开漏的线与特性多个主机同时拉低结果还是低不会短路。仲裁失败的主机只是停止驱动SDA和SCL让获胜的主机继续。3.2 仲裁为什么不会丢数据仲裁是逐位进行的而且是在数据位和地址位上同时进行。假设主机A发送地址0x50主机B发送地址0x52二进制分别是0x50 0101 0000 0x52 0101 0010前六位完全一样第七位A发0B发1。当SCL为高时A拉低SDAB释放SDA想发1。B回读SDA发现是低被A拉低了B就知道自己仲裁失败退出。A继续发送不受影响。整个过程B没有破坏A的任何数据位因为B在发现自己失败的那一刻就停止驱动了。这就是为什么仲裁不会丢数据——失败方在造成冲突之前就退出了。3.3 仲裁和时钟同步的区别很多人把仲裁和时钟同步搞混。时钟同步是多个主机在SCL上协商出一个共同的时钟规则是SCL的实际电平是所有主机SCL输出的线与结果。任何一个主机拉低SCLSCL就是低所有主机都释放SCLSCL才变高。时钟同步保证了即使多个主机的时钟频率不同也能在SCL上达成一致。仲裁则是在数据线上决定谁获胜。两者配合才能实现多主总线的无冲突通信。实际项目中多主仲裁用得很少因为大多数系统只有一个主机。但理解这个机制对理解I2C为什么这么设计、为什么开漏是必须的非常有帮助。3.4 多主场景下的实际坑虽然多主仲裁理论上很完美但实际用起来坑不少时钟同步对速率的影响多个主机时钟频率不同同步后的时钟频率由最慢的主机决定。如果有一个主机时钟特别慢整个总线都被拖慢。仲裁失败后的处理仲裁失败的主机需要能够正确切换到从机模式并重新发起通信。很多硬件I2C控制器对仲裁失败的处理不完善需要软件介入。总线锁死如果某个主机在仲裁过程中异常复位可能留下SCL或SDA被拉低的状态导致总线锁死。我做过一个双主机的项目两个MCU共享一条I2C总线结果经常出现总线锁死。后来发现是其中一个MCU复位时I2C引脚状态不确定把SDA拉低了。解决办法是在复位后先手动发送9个时钟脉冲把总线敲醒再初始化I2C。4. 总线锁死I2C最让人头疼的故障总线锁死是I2C最经典的故障几乎每个用I2C的人都遇到过。现象是SCL或SDA被某个设备一直拉低主机无法发起新的通信整个总线瘫痪。4.1 锁死的根本原因锁死通常发生在以下场景主机在发送数据过程中被复位从机还在等待下一个时钟但主机已经不发了从机把SDA拉低等待导致SDA一直低。从机在发送数据过程中主机突然停止时钟从机正在输出低电平SDA被卡住。电源上电顺序问题某个设备先上电把总线拉低主机后上电检测到总线忙一直等待。根本原因是I2C的状态机在异常中断后无法自动恢复。从机不知道主机已经复位还在等时钟主机不知道从机在等什么无法继续。4.2 用时钟脉冲解锁总线最常用的解锁方法是在SCL上手动发送9个时钟脉冲。原理是从机在等待时钟时每来一个时钟就移出一位数据最多9个时钟后从机的数据移位寄存器会全部移出SDA被释放。具体操作把SCL配置为推挽输出SDA配置为输入。发送9个SCL脉冲每个脉冲高电平至少1.3μs100kHz。检查SDA是否变高如果变高说明解锁成功。发送一个STOP条件SCL高时SDA由低变高让总线回到空闲状态。重新初始化I2C。代码示例伪代码void i2c_bus_recovery(void) { gpio_set_output(SCL_PIN); gpio_set_input(SDA_PIN); for (int i 0; i 9; i) { gpio_write(SCL_PIN, 0); delay_us(5); gpio_write(SCL_PIN, 1); delay_us(5); if (gpio_read(SDA_PIN) 1) { break; // SDA释放了 } } // 发送STOP条件 gpio_write(SDA_PIN, 0); delay_us(5); gpio_write(SCL_PIN, 1); delay_us(5); gpio_write(SDA_PIN, 1); delay_us(5); // 重新初始化I2C i2c_init(); }注意发送时钟脉冲时SCL必须用推挽输出因为此时总线可能被从机拉低开漏输出可能无法产生有效的上升沿。但发送完脉冲后一定要把SCL恢复为开漏模式否则会破坏I2C的线与特性。4.3 硬件层面的预防措施软件解锁是事后补救更好的做法是硬件层面预防串联电阻在SCL和SDA上串联100Ω左右的电阻限制异常情况下的电流保护器件。总线缓冲器用PCA9515之类的I2C缓冲器隔离总线段一段锁死不影响另一段。电源监控用复位芯片确保所有设备在电源稳定后才开始工作避免上电顺序问题。看门狗主机加看门狗异常时复位并执行总线恢复流程。我现在的项目里I2C总线上都会预留串联电阻的位置虽然大部分时候不焊但遇到问题可以焊上试试。另外主机固件里一定会包含总线恢复函数在I2C通信超时后自动调用。4.4 逻辑分析仪在锁死排查中的作用逻辑分析仪是排查I2C问题的神器。抓一帧波形看SCL和SDA的状态基本就能定位问题SCL一直低某个从机在时钟拉伸或者SCL被短路。SDA一直低从机在等待时钟或者SDA被短路。起始条件后没有地址主机发送有问题。地址后没有ACK从机没响应地址错了或者从机没上电。我用的是Saleae Logic系列配合I2C协议解码能直接看到地址、数据、ACK/NACK非常直观。便宜的可以用逻辑分析仪模块配合开源软件也能满足基本需求。5. 从地址到数据帧I2C通信的完整拆解理解了物理层和仲裁机制接下来把一帧完整的I2C通信拆开看。这部分是实际写驱动、调通信的基础每个细节都可能成为通信失败的原因。5.1 7位地址和10位地址的区别I2C支持7位和10位两种地址格式。7位地址是主流10位地址用于地址空间不足的场景但实际用得很少。7位地址帧格式起始条件 7位地址 1位读写位 ACK/NACK。读写位0表示写1表示读。所以一个7位地址0x50的设备写操作时发送0xA0读操作时发送0xA1。10位地址帧格式起始条件 11110xx 10位地址的高2位 读写位 ACK 10位地址的低8位 ACK。10位地址兼容7位地址因为11110xx是保留地址段不会和7位地址冲突。但10位地址的通信流程更复杂一般项目用不上。5.2 ACK和NACK的时机与含义ACK/NACK是I2C通信的确认机制。每传输8位数据后接收方需要发送1位ACK拉低SDA或NACK释放SDA。ACK/NACK出现的时机主机发送地址后从机如果地址匹配发送ACK。主机发送数据后从机发送ACK。从机发送数据后主机发送ACK继续读或NACK停止读。NACK的几种含义主机读操作最后一个字节后发NACK告诉从机停止发送。从机地址不匹配发NACK主机收到后发送STOP或重新START。从机忙无法响应发NACK。很多通信失败就是ACK没收到。用逻辑分析仪看如果地址后是NACK说明从机没响应检查地址、电源、上拉电阻。5.3 重复起始条件的使用场景重复起始条件Repeated START是在不发送STOP的情况下重新发送START。用于以下场景读操作先写寄存器地址然后重复START再读数据。多主机环境下不想释放总线。以读EEPROM为例START 写地址(0xA0) ACK 寄存器地址 ACK Repeated START 读地址(0xA1) ACK 数据 NACK STOP注意最后是NACK因为主机只读一个字节读完发NACK告诉从机停止。5.4 数据帧格式的常见误解很多人以为I2C的数据帧是固定长度的其实不是。I2C只定义了字节传输的规则具体的数据格式由设备决定。比如EEPROM地址 数据地址自动递增。传感器寄存器地址 数据。OLED命令 数据用控制字节区分。所以调一个新器件第一件事是看它的数据手册搞清楚它的数据帧格式而不是套用其他器件的代码。6. 逻辑分析仪实战抓一帧I2C看看到底发生了什么理论讲再多不如抓一帧波形看。这部分用一个实际案例演示怎么用逻辑分析仪分析I2C通信定位问题。6.1 抓取前的准备工作抓I2C波形需要逻辑分析仪至少2通道采样率至少4倍于SCL频率400kHz SCL需要至少1.6MHz采样率建议10MHz以上。探头接SCL和SDA地线接GND。协议解码器Saleae Logic自带I2C解码开源软件PulseView也有。设置触发条件一般用SCL下降沿触发或者SDA下降沿触发起始条件。如果想抓特定地址可以设置地址匹配触发。6.2 一帧正常通信的波形解读假设读一个AT24C02的EEPROM地址0xA0读寄存器0x00波形上会看到STARTSCL高时SDA下降。地址0xA08位数据最后一位0写。ACK从机拉低SDA。寄存器地址0x008位数据。ACK从机拉低SDA。Repeated STARTSCL高时SDA下降。地址0xA18位数据最后一位1读。ACK从机拉低SDA。数据8位数据。NACK主机释放SDA。STOPSCL高时SDA上升。逻辑分析仪的协议解码器会直接把这些解析成可读的地址、数据、ACK/NACK非常直观。6.3 常见异常波形分析现象可能原因排查方向地址后NACK从机没响应检查地址、电源、上拉SCL一直低时钟拉伸或短路检查从机、断开总线分段排查SDA一直低从机等待或短路执行总线恢复、检查器件起始条件后无数据主机问题检查主机I2C配置、GPIO模式数据位错误时序问题检查上拉、总线电容、速率上升沿过缓上拉过大或电容过大减小上拉、缩短走线6.4 用逻辑分析仪定位GT911触摸屏通信失败GT911是一款常见的电容触摸屏控制器I2C接口。我遇到过GT911通信失败的情况用逻辑分析仪抓波形发现地址0x5D发送后GT911没有ACK。检查电源发现GT911的复位时序不对复位引脚释放太早芯片还没准备好。调整复位时序延时100ms后再通信问题解决。这个案例说明I2C通信失败不一定是I2C本身的问题可能是从机的初始化时序不对。逻辑分析仪能帮你排除I2C层面的问题把注意力引到正确的方向。7. 软件模拟I2C vs 硬件I2C怎么选怎么用实际项目中I2C的实现方式有两种用MCU自带的硬件I2C外设或者用GPIO软件模拟。两者各有优劣选错了会带来很多麻烦。7.1 硬件I2C的优势与坑硬件I2C的优势不占用CPU通信过程由硬件完成。时序精确速率高。支持中断和DMA。硬件I2C的坑不同MCU的硬件I2C行为不一致移植麻烦。某些硬件I2C对时钟拉伸、仲裁失败处理不完善。调试困难出问题不好定位。引脚固定布线不灵活。我用过STM32、ESP32、NXP的硬件I2C各有各的脾气。STM32的硬件I2C在早期型号上有著名的死锁问题后来用软件模拟才稳定。ESP32的硬件I2C相对好用但时钟拉伸支持有限。7.2 软件模拟I2C的适用场景软件模拟I2C的优势引脚任意布线灵活。时序完全可控方便调试。移植性好换MCU基本不用改代码。可以处理硬件I2C处理不了的异常情况。软件模拟I2C的劣势占用CPU高速通信时CPU负载高。速率受限一般100kHz比较稳400kHz勉强。中断打断可能导致时序错误。我的经验是低速、少量数据、引脚受限的场景用软件模拟高速、大量数据、CPU负载敏感的场景用硬件I2C。如果硬件I2C有问题先尝试软件模拟往往能快速绕过问题。7.3 软件模拟I2C的时序控制要点软件模拟I2C的核心是精确控制SCL和SDA的翻转时序。关键点延时函数要准确用示波器或逻辑分析仪校准。关中断或者用高优先级任务保证时序不被打断。SCL和SDA的GPIO模式要正确输出时开漏输入时浮空或上拉。起始、停止、数据位的时序要符合I2C标准。一个典型的软件I2C延时#define I2C_DELAY() do { \ for (volatile int i 0; i 10; i); \ } while(0) void i2c_start(void) { SDA_HIGH(); SCL_HIGH(); I2C_DELAY(); SDA_LOW(); I2C_DELAY(); SCL_LOW(); I2C_DELAY(); }延时长度需要根据MCU主频调整用逻辑分析仪确认SCL频率在目标范围内。7.4 混合方案硬件I2C加软件恢复实际项目中我常用一种混合方案正常通信用硬件I2C检测到超时或异常后切换到软件模拟执行总线恢复然后切回硬件I2C。这样兼顾了硬件I2C的效率和软件模拟的灵活性。实现要点硬件I2C和软件模拟共用同一组GPIO。切换时重新配置GPIO模式。恢复流程发送9个时钟脉冲 STOP条件 重新初始化硬件I2C。8. 那些年我踩过的I2C坑最后这部分分享一些具体的踩坑经历都是实际项目中遇到的希望能帮你少走弯路。8.1 上拉电阻漏焊导致通信不稳定有一次画板子I2C上拉电阻忘了焊调试的时候通信时好时坏。用逻辑分析仪看上升沿非常缓因为MCU内部有弱上拉勉强能拉高但速率一快就不行。焊上4.7kΩ上拉后立刻稳定。教训I2C上拉电阻是必须的不能依赖MCU内部上拉。内部上拉通常几十kΩ只适合极低速场景。8.2 地址冲突导致通信失败一个项目里挂了两个同型号的传感器地址都是0x68结果通信混乱。后来发现其中一个传感器的地址引脚可以配置改成0x69后解决。教训挂多个同型号器件时一定要确认地址是否可配置避免地址冲突。8.3 电源域不同导致电平不匹配一个系统里主机是3.3V从机是5VI2C直接连结果从机的5V电平灌到主机引脚长期运行后主机引脚损坏。后来加了电平转换芯片才解决。教训不同电源域的I2C设备之间必须加电平转换不能直接连。8.4 长走线导致信号完整性差一个项目里I2C走线长达30cm400kHz通信失败。用示波器看上升沿有振铃下降沿有毛刺。后来降低到100kHz并加了串联电阻才稳定。教训I2C走线尽量短长走线要加缓冲器或降低速率。8.5 中断打断导致时序错误软件模拟I2C时没关中断结果一个高优先级中断打断了SCL高电平期间导致从机采样错误。后来在I2C操作期间关中断问题解决。教训软件模拟I2C的时序敏感操作要关中断或者用硬件I2C。8.6 从机时钟拉伸导致主机超时一个传感器需要时钟拉伸但主机的硬件I2C不支持通信总是超时。后来改用软件模拟I2C手动处理时钟拉伸问题解决。教训选型时要确认主机的I2C控制器是否支持从机的所有特性特别是时钟拉伸。8.7 EEPROM写周期导致的通信失败AT24C02写一个字节后需要5ms内部写周期期间不响应任何通信。我一开始没加延时连续写导致后面的写操作全部失败。后来在每次写后加5ms延时或者用ACK轮询问题解决。教训EEPROM写操作后必须等待写周期完成可以用固定延时或ACK轮询。8.8 逻辑分析仪采样率不足导致误判用低采样率的逻辑分析仪抓400kHz I2C波形失真误判为时序问题。后来换高采样率分析仪发现波形正常问题在别处。教训逻辑分析仪的采样率至少是SCL频率的4倍建议10倍以上。9. 把I2C彻底讲透之后的一些体会I2C这两根线表面上简单实际上从物理层到协议层每一层都有讲究。开漏输出决定了多设备共享的可行性上拉电阻决定了波形的质量仲裁机制决定了多主总线的无冲突时钟拉伸给了从机喘息的空间ACK/NACK保证了数据的可靠传输。每一个设计都有其存在的理由理解了这些理由遇到问题才能快速定位。我现在的习惯是拿到一个新的I2C器件先看数据手册的时序图确认地址、速率、时钟拉伸支持情况然后用逻辑分析仪抓一帧实际波形确认通信正常再开始写驱动。这个流程看起来麻烦但能避免很多后期调试的痛苦。最后分享一个小技巧如果你怀疑I2C通信有问题但不确定是硬件还是软件先用逻辑分析仪抓波形。波形不会骗人SCL和SDA的状态一目了然。如果波形正常但通信失败问题在软件如果波形异常问题在硬件或时序。这个判断方法帮我节省了大量排查时间。
返回列表