刚拿到这块新板子的时候,我做的最重要的一步不是上电跑固件,而是先把I2C总线上的从机地址全部摸清楚。PCB上挂了EEPROM、温度传感器、还有一颗RTC,地址从原理图上看都对得上,但实际贴片下来有没有贴错、有没有虚焊,原理图说了不算,得用USB转I2C工具配Excel扫描一版才算数。今天的记录就是这次在100KHz总线速率下执行的"I2C Scan"测试,测试编号A,也是整块板子第一轮总线摸底。
这套流程对经常调硬件的人来说应该很亲切:宿主PC通过USB转I2C适配器接到目标板的SCL/SDA,上位机这边用Excel模板配合宏来发起地址扫描,把0x03到0x77范围内的所有从机地址逐个写地址字节、等ACK、记录响应。扫描结果最终落到Excel表格里,一眼就能看出总线上哪些地址有设备、哪些是空的、哪些出现了本不该有的响应。它能帮你解决的核心问题就一个:在写驱动之前,先把物理层的通信基础确认掉。文章面向的对象是嵌入式工程师、硬件调试人员,以及正在学习I2C协议、想搞懂地址扫描机制的同学。
1. 项目核心拆解:USB转I2C、Excel与Scan到底拼出了什么
1.1 为什么这个测试任务会被命名为"A"
文件名后缀那个"A",我这边是指第一轮完整测试,对应的是常温、默认上拉、100KHz标准速率下的基础摸底。后面通常还跟B、C甚至D,比如换一组上拉电阻再测、或者把速率拉到400KHz快速模式再测一遍。这种命名方式在硬件调试记录里很常见,它能保证每一次测试的条件可追溯,不然过了两周再看数据,你可能连当初用的什么速率、哪块板子都记不清。所以别小看这个后缀,它是整个测试记录的索引锚点。
1.2 方案选型:为什么偏偏是USB转I2C加Excel这套组合
调试I2C总线有三种常见路子。第一种是拿MCU开发板写个扫描固件,通过串口打印结果,这套方案的痛点是MCU本身得先能跑起来,环境变量太多,板子上电时序不对或者晶振不起振,你根本分不清是总线问题还是MCU问题。第二种是逻辑分析仪直接抓波形,这个能看到细节,但分析地址响应这种事用它属于杀鸡用牛刀,而且批量看设备列表时效率很低。第三种就是标题里这个方案:PC端用USB转I2C适配器做主控,上位机软件发指令,目标板只是个被动响应方。这样做的好处是目标板不需要跑任何代码,哪怕MCU还没焊、没烧程序,只要EEPROM这些从机有供电、有上拉,扫描就能进行。这刚好符合"裸板调试"的需求。
Excel在这个场景里不是用来画图表的,它是上位机软件的宿主。很多USB转I2C工具(比如基于FTDI MPSSE方案的调试器)都提供Excel宏模板,把I2C的读写操作封装成表格里的函数,比如在单元格里填上从机地址、寄存器地址、数据长度,一跑宏,就能通过USB把指令发到适配器上,再把回读数据填回表格。对产线测试和快速验证来说,这种形式比专门写一套GUI更轻量,测试记录还能直接复用Excel的公式、筛选和格式功能,生成报告也方便。标题里的"Scan"就是这类模板里最常见的一个功能,专门用来扫描总线上存在的从机地址。
1.3 这套流程解决的问题边界
用过的人会知道,I2C扫描能确认的是"哪些地址在总线上有设备响应",但扫不出来设备的型号、寄存器布局,也测不了通信时序质量。它更像是个准入测试:先确认连接和地址正确,再进入下一步的寄存器读写验证。所以在做这个测试的同时,我还有一份完整的预期地址表——原理图里每一颗从机的地址引脚配置、7位地址推算结果、对应型号都列了出来。扫描结果要和这张表对比,而不是只看"扫到了几个设备"就觉得万事大吉。
2. 100KHz地址扫描背后的协议细节
2.1 地址扫描是怎么做到"扫一遍"的
I2C总线是半双工、漏极开路的双线制,一根SCL时钟线、一根SDA数据线。主机发起通信时,先产生一个START条件,然后发送8位数据,前7位是从机地址,第8位是读写方向——实际上读操作是1,写操作是0。从机如果地址匹配,会在第9个时钟周期把SDA拉低,回一个ACK;不匹配或者不存在这个地址,SDA保持高电平,也就是NACK。扫描程序就是利用这个机制,对合法的7位地址范围逐个执行"发START + 发地址字节 + 等ACK + 发STOP"的流程,把能收到ACK的地址记录下来。
这里有个容易被忽略的点:7位地址范围是0x00到0x7F,但不是每个地址都能用来扫描。0x00是广播呼叫地址(general call),一般不能当普通设备地址用;0x01到0x07是保留地址,比如0x01是Subadress寻址、0x02到0x07留给其它总线协议;0x78到0x7B是10位寻址的标志区段,跟7位寻址有重叠;0x7C到0x7F也是保留地址。所以实操中合理的扫描范围是0x08到0x77,这范围内的地址如果总线电容和上拉合理,都应该能在第9个时钟周期给出明确响应。常见的EEPROM芯片比如AT24C系列,地址往往是0x50、0x51这些,也就是1010xxx的结构,因为硬件上A0、A1、A2引脚可以配置,最多扩展出8个地址,扫描结果很容易和这个特征对上。
伪代码层面,扫描一轮的核心逻辑并不复杂:
for addr in range(0x08, 0x78): i2c.start() ack = i2c.write(addr << 1) # 发送地址字节,写位为0,等待ACK/NACK if ack: found.append(addr) i2c.stop()这里地址字节是"从机地址左移一位,最低位是写标志"。比如7位地址0x50,实际发送的字节就是0xA0。扫描工具内部处理了这个转换,Excel里显示的通常还是7位地址,不用自己换算,但理解这个机制有助于你判断扫描结果是否可信。
2.2 100KHz标准模式下时序余量为什么要较真
I2C标准模式(Standard Mode)的标称速率是100Kbps,这是I2C总线最初定义的速度档位,兼容性最好,几乎所有从机都支持。但"标称速率"只是上限,真正的通信时序约束在于各阶段的边沿时间参数。在100KHz下,SCL低电平时间不得小于4.7微秒,SCL高电平时间不得小于4.0微秒,数据建立时间不得小于250纳秒,上升沿时间不得超过1000纳秒,下降沿时间不得超过300纳秒。低速下这些参数相对宽裕,但正因为宽裕,很多人反而忽略了计算,等出了问题才回头查时序。
以扫描动作本身为例,整个地址探测过程包含了START条件、地址字节、ACK位、STOP条件,其中最关键的边沿参数是SDA和SCL的上升时间。因为I2C总线是开漏结构,上拉电阻和总线寄生电容共同决定上升沿斜率——电容越大、上拉电阻越大,上升沿越慢。如果上升沿超过1000纳秒,从机很可能识别不到合法的START或STOP条件,扫描就会出现漏设备或者干脆报错。这也是在新板子上做总线测试时,我习惯先看一眼上拉电阻阻值的原因。100KHz模式下,常见的4.7千欧上拉电阻在100到200皮法拉总线电容范围内是可以满足要求的,但如果是长排线、转接板叠叠乐,总线电容翻倍,上升沿可能就到了边缘。
2.3 上拉电阻怎么选,算一下就有数
上拉电阻的选择其实就两个约束在打架。一个是上升沿要足够快,保证时序合规;另一个是灌电流不能超过从机和主机的极限,否则低电平会被拉不到规定的阈值。设计时通常这样估算:总线上升时间近似等于0.8473乘以上拉电阻乘总线电容,即tr = 0.8473 × Rp × Cb。假设总线电容是200皮法,要求tr不超过1000纳秒,反推上拉电阻上限大概是1000纳秒除以0.8473再除以200皮法,算出来约等于5.9千欧,所以4.7千欧是合适的标配。如果总线电容只有50皮法,那上拉电阻可以放宽到十几千欧,但也没必要,4.7千欧在低速下完全够用。
下限方面,假设VCC是3.3V,输出低电平最大允许0.4V,灌电流能力按3毫安算,那么上拉电阻最小是(3.3-0.4)伏除以3毫安,约等于967欧姆,所以1千欧附近是下限。这个算法只是粗略估算,实际还要加上串阻、引脚本身的能力和总线噪音余量。我个人的经验是:100KHz扫描场景,上拉电阻在2.2千欧到4.7千欧之间最省心,既能保证边沿干净,又不会因为电流太大导致主从双方都吃力。测试A用的就是板上自带的4.7千欧标准上拉,总线挂载了三个从机,总线上拉等效电阻大约1.6千欧,算下来上升沿余量充足,扫描的理论成功率本来就是100%。
3. 实操记录:从接线到Excel扫描出结果的全过程
3.1 硬件连接和驱动确认,别急着开软件
动手之前先把设备和被测板子的连接理清楚。USB转I2C适配器这端至少引出SCL、SDA、GND三根线,目标板如果是自供电的,VCC可以不接,只要两者的逻辑电平能对上就行。这里要特别留意电平匹配:适配器如果输出1.8V逻辑,而目标板是3.3V系统,就需要电平转换,直接硬接轻则通信不稳定,重则烧引脚。我这次用的适配器是FTDI方案的MPSSE调试器,默认3.3V逻辑,与目标板供电电压一致,所以直连就完事。SCL对SCL、SDA对SDA、GND共地,顺序不能错,接反了扫描结果往往就是一片空白或者出现乱码设备,回头排查很浪费时间。
接线完毕后,在PC端确认USB设备是否被正确识别。这类设备通常会在系统里枚举成COM口或者USB串行设备。FTDI方案需要装FTDI的USB UART驱动,装好后设备管理器里能看到对应端口;CP2112这类HID方案的则免驱,直接显示为HID设备。之前网上搜"ft231x usb uart驱动"、"ft232r usb uart驱动安装"的人很多,说明这个环节确实容易卡住。我的建议是:装驱动时关掉杀毒软件和系统的驱动签名强制校验,装完重启一次系统再插设备,大多数识别问题都能解决。设备管理器里看到感叹号,先右键更新驱动,再不行就查一下是不是USB线只能充电不能传数据。
3.2 Excel扫描模板的操作顺序
打开Excel扫描模板后,第一件事不是点扫描按钮,而是确认模板里的设备端口号和从机地址扫描范围。端口号要根据设备管理器里的实际编号改,很多人扫不到设备就是因为这里还停留在上一次使用的COM口。扫描范围按上一节说的,一般填0x08到0x77,如果你只想针对性确认某一个地址,也可以缩小范围只填一个。模板里还有个速率设置项,下拉选择Standard Mode(100KHz),这个项目名称里已经明确了,就按100KHz来。速率设置不仅影响SCL频率,也影响工具内部的延时设计,有些工具在更高速率下会自动压缩时序参数,低速下更稳妥。
然后启用宏并执行扫描。Excel宏如果被安全策略拦截,需要在"文件-选项-信任中心-宏设置"里开启"启用所有宏"或者"启用VBA宏",这一步属于常规操作。扫描执行过程中,工具会一个地址一个地址地发探测帧,整个过程很快,几十个地址也就是一两秒的事。扫描结束后,模板会把结果写到预定义的单元格区域,有响应的地址标记出来,通常还会附带设备类型猜测,比如识别到0x50就打上"EEPROM"标签。为了保险,我一般会连续扫三遍,确认每一遍结果都稳定,避免某一次误触发导致判断失真。
3.3 扫描结果判读和Excel处理
测试A的实际扫描结果如表所示,注意我这里用的是7位地址表示法,总线频率100KHz,供电3.3V。
| 7位地址 | 写字节(8bit) | 扫描响应 | 预期设备 | 实际判断 |
|---|---|---|---|---|
| 0x50 | 0xA0 | ACK | AT24C32 EEPROM | 符合预期 |
| 0x68 | 0xD0 | ACK | RTC PCF85063 | 符合预期 |
| 0x48 | 0x90 | ACK | 温度传感器TMP117 | 符合预期 |
| 0x3C | 0x78 | NACK | 无设备 | 空地址 |
| 0x30 | 0x60 | NACK | 无设备 | 空地址 |
| 0x0F | 0x1E | ACK | 未知 | 需要重点排查 |
前三个设备的地址跟原理图完全吻合,属于正常命中。0x3C和0x30没有响应,也正常,说明这些地址上确实没有挂东西。但0x0F这个地址出现了ACK,而原理图上没有任何设备应该在这里,这就触发了问题排查流程——后面详细展开。拿到Excel结果后,我做了几步处理:先把扫描结果用条件格式标色,ACK的标绿,NACK的标灰,一眼扫过去就知道总线整体情况;然后把结果和原理图器件表做了VLOOKUP匹配,把预期设备、封装、原理图页码都关联到同一张表里。这样输出给硬件同事做分析时,他们不用再去翻图纸,Excel文件本身就是一份完整的测试记录。
4. 坑和排查:扫描异常、地址冲突、总线锁死
4.1 扫描结果全是"无响应",先查这三个地方
第一轮扫描如果所有地址都NACK,说明总线数据通路本身有问题,不用急着怀疑从机地址。优先级最高的排查点依次是:SCL和SDA是否接反、共地是否良好、上拉电阻是否生效。我曾经遇到过一次全程无响应的状况,用万用表量SCL和SDA对地电压才发现SDA一直被拉低到0.1V左右,这是典型的从机处于异常状态或者总线锁死。I2C协议里有个概念叫总线阻塞:某个从机在通信中途掉电或在错误时序下进入异常状态,可能一直拉住SDA不放,导致主机无法启动通信。处理方法是用示波器看SDA是不是恒低,如果是,给目标板彻底断电重启,或者把适配器这边的SCL手动翻转九次以上,给总线一个释放的机会。这个技巧在调试中非常实用,比反复插拔USB线有效得多。
还有一种情况下扫描结果不是"全无",而是"全有"——每一个地址都有ACK,这同样不正常。常见原因是SDA线没接好,悬空状态被上拉电阻抬成了高电平,于是不管发什么地址,第9个时钟脉冲总能看到高电平NACK被误判,或者反过来因为干扰导致误判成ACK。判断标准很简单:正常设备列表很稀疏,不可能0x08到0x77全响应。如果扫描出一大串连续地址,基本可以确认是接线或工具配置问题,而不是总线上真的挂了上百个设备。
4.2 地址冲突和0x0F异常响应的排查思路
表里扫描到的0x0F地址,虽然不在预期表里,但也不能直接断定是幽灵设备。I2C从机地址如果是7位,它的响应字节还会受到读写位和10位寻址标志的影响。0x0F这个地址实际发送字节是0x1E,二进制是0011110,正好落在保留地址区域之外,属于合法可扫描的普通地址。出现异常ACK的原因通常就两类:一类是从机地址配置引脚焊接错误,比如EEPROM的A0、A1、A2被错拉到某个组合,导致响应地址偏移到0x0F;另一类是总线信号质量太差,比如上升沿过缓导致从机在地址匹配判断时出错,把不该响应的地址也响应了。为了区分这两种可能,我用示波器抓了0x0F探测帧的波形,确认第9个时钟周期SDA是被从机主动拉低,而不是毛刺造成的假信号。从机主动拉低意味着确实有设备认为自己在地址0x0F上,后来排查确认是板上某颗新加入的传感器默认地址就是0x0F,原理图器件表没更新,算是人手上的疏漏,不是硬件故障。
地址冲突的典型场景则是另一番景象:比如总线上两颗EEPROM的A0、A1、A2全部接地,那么它们默认地址都是0x50,扫描时0x50会出现ACK,但后续读写时两个设备同时响应、数据互相打架,表现就是读出的数据时而正确时而错乱。处理办法是给其中一颗芯片的地址引脚改成不同的电平组合,让它偏移到0x51或者0x52。这里要注意,地址偏移不是任意的,必须符合芯片数据手册里A0A1A2的映射逻辑,改完再扫描一遍确认两个地址都变成了独立响应,才算真正解决冲突。
4.3 100KHz下行通信异常的定位手段
低速率下通信不稳定,往住不是频率本身的问题,而是边沿参数和外部干扰在作怪。我遇到过一个典型案例:单独用USB转I2C工具和板子直连,扫描和读写都很正常,一旦把板子通过排线连到另一个模块,扫描就开始丢设备。用示波器看波形,排线引入的电容让SCL上升沿从400纳秒被拖到了接近1100纳秒,已经超过标准模式1000纳秒的上限。这就是100KHz速率下也要关注时序的原因。解决方向有三个:减小总电容(缩短排线长度)、减小上拉电阻(比如从4.7千欧换到2.2千欧)、降低速率(比如再往下降当然不行,这个测试规定就是100KHz,所以只能从硬件上收敛)。最终我把上拉电阻调整到2.2千欧,上升沿回到600纳秒左右,扫描恢复稳定。这类经验说明:I2C调试,尤其在低速下,很多"玄学问题"的本质都是RC时间常数超标。
另外,如果扫描时稳定、但批量读写时出现偶发字节错乱,就要检查时钟拉伸(clock stretching)处理。某些从机比如传感器或EEPROM在内部忙时,会把SCL拉低来暂缓主机的时钟,主机必须支持这个机制才能正常工作。USB转I2C工具对时钟拉伸的支持参差不齐,有的工具在软件层根本不处理,就会导致读数据超时或错位。遇到这种情况,可以先确认从机数据手册里的最大拉伸时间,再换一个更专业的调试器。FTDI MPSSE方案在这块做得相对成熟,国产的一些低成本USB转I2C小工具就不一定了。
4.4 Excel侧的几个小坑
这里补几个实操体会,看起来都是小事,但都很容易让人卡住。第一个是宏被禁用。模板打开后扫描按钮是灰的,多半是宏被Excel安全策略拦住了。除了在信任中心开启宏,还建议把模板文件所在文件夹加到"受信任位置",这样以后每次打开都不会再问。第二个是"Excel加载项被禁用"的问题,如果模板依赖特定的加载项或COM组件,需要去"COM加载项"里手动勾选启用;有些旧模板还依赖32位Excel的ActiveX控件,64位Office下控件会加载失败,这个比较无解,只能装32位Office或者改用工具自带的独立上位机。第三个是结果表格复制粘贴异常,扫描完想复制结果到别的表格却卡住或者格式错乱,通常是模板里设置了受保护的单元格,先取消保护工作表再操作。第四个是有时候扫描结果明明更新了,但表格里的旧设备列表还残留,筛选或排序时把旧数据混进来,所以每次重新扫描前建议先清空结果区域,或者把扫描起始行固定,避免新旧数据混存。
5. 我个人经验里的几条心得
先说一个容易被忽视的点:扫描之前,把目标板上的从机芯片供电确认好。I2C总线上的设备如果有没上电的,它的IO口通常处于高阻态,不影响扫描;但如果是半上电、电源电压不稳的状态,它可能会把SDA拉到一个中间电位,导致整个总线通信异常。所以每次扫描前我都会顺手用万用表量一下各从机电源引脚的对地电压,确认都在正常范围内,这个习惯帮我排除过好几次"明明接线没问题却扫不到设备"的疑难杂症。
再说一个关于记录习惯的建议:Excel扫描结果不只是一次性的调试数据,它完全可以沉淀成一份可复用的总线清单。我把每次扫描的地址表、设备型号、固件寄存器初始化值、备注说明都维护在一个工作簿里,后续画驱动、写设备树、做产线测试都能直接借用。这次测试A的数据后来也被拿去做成了产线的首件检测模板,新板子贴片完不用接MCU就能快速验证I2C总线设备有没有焊好。一次调试投入的成本,换来的是后续产线多环节的复用价值。
最后分享一个小技巧:扫描如果遇到偶发性失败,不要反复点鼠标重试,而是先用示波器或者逻辑分析仪抓一轮完整波形保存下来,对照数据手册里的时序图逐段看。很多疑难问题,肉眼看到波形的那一刻基本就有答案了。USB转I2C配合Excel这套组合虽然不是什么新鲜方案,但只要你能把协议原理、物理参数和工具特性都吃透,它在日常调试和产测里的价值会比你想象的大得多。