USB转I2C扫描与100KHz时序测试:嵌入式总线排查的Excel留存方案
最近在调一块多传感器板子按老规矩先做一轮 USB 转 I2C 的总线扫描顺便在 100KHz 速率档位上把时序基线测一遍结果直接归档进 Excel。标题里这行 “USB TO I2C_(Excel)_Scan —— 100KHz总线速率测试_A”就是我们内部测试记录里的编号A 代表首轮常温批次。别看这名字长得像文件名拼接它其实覆盖了一整套可复用的 I2C 总线健康检查流程用 USB 转 I2C 适配器把电脑接到目标板以标准模式 100KHz 跑一遍地址扫描确认哪些从设备在线再把实测时序、应答情况、环境参数写进 Excel 留档。这套流程最适合三类人一是嵌入式工程师新板或新物料回来要快速确认 I2C 地址没冲突、器件能正常通信二是产线测试或硬件验收的同学需要把总线检查变成可追溯的记录而不是靠肉眼和示波器截图三是刚接触 I2C、想搞明白“扫描到底在扫什么”的学习者。看完这篇文章你可以直接照着搭一套自己的 I2C 总线基线测试方案。1. 任务拆解与方案选型1.1 标题背后到底藏了哪些需求先把标题拆开看。“USB TO I2C”定义的是接入方式也就是用 PC 通过 USB 转 I2C 适配器去控制目标总线“Excel”定义了结果呈现方式扫描结果要落到表格里方便存档和对比“Scan”是核心动作遍历 I2C 地址空间找出哪些地址有设备应答“100KHz总线速率测试”定义了测试条件SCL 时钟设定在标准模式最高的 100kHz并验证时序是否达标最后的 “_A” 则是我们内部约定俗成的批次后缀代表这次测试属于首轮常温组后面可能还有 _B、_C 对应不同板卡或不同温度条件。这个任务要解决的实际上有两个问题。第一个是“有没有设备在线、地址是多少”也就是扫描。第二个是“总线在 100KHz 下是不是真的稳”这就涉及 SCL 频率、上升下降沿、建立保持时间这些时序参数。很多人做完扫描就收工了其实漏了后半段扫描只能证明“某个地址回应了 ACK”不能证明“这个地址在 100KHz 下能稳定工作”。有些板子低速下一切正常一提到 100KHz 就丢 ACK、卡总线所以速率测试必须和扫描绑在一起做。1.2 为什么选 USB 转 I2C、100KHz 和 Excel 这个组合先说接入方式。MCU 原生 I2C 调试当然可以但每次改代码、烧固件、看日志太绕。USB 转 I2C 适配器把 I2C 总线直接暴露给 PC 端脚本扫描一个地址只要几毫秒遍历完整个地址空间也就一两秒改频率、改探测方式都特别快。调试阶段我基本不用 MCU 自己扫因为固件里写扫描代码还得考虑 Flash 占用、打印缓冲、看门狗超时这些问题实在没必要。再说 100KHz。I2C 标准模式的上限就是 100kHz所有符合规范的从设备都必须在 100KHz 下工作。先在这个档位做基线测试是因为它兼容性最广、时序容限最大一旦 100KHz 都跑不稳那 400KHz 快速模式想都不要想。另一个原因是排查问题时有余量示波器或逻辑分析仪抓波形100KHz 的周期是 10us哪怕采样率不高也能看得比较清楚。新板、新物料、换 PCB 批次后我最先跑的就是 100KHz 基线。Excel 则是为了把“感觉没问题”变成“数据证明没问题”。纯文本日志也能记录但你要对比二十块板卡的扫描结果或者统计这批板子有几个地址异常Excel 的筛选、条件格式、透视表就方便太多了。热词里还有人提到 markdown 表格转换 Excel说明大家确实有“先把结果整理成文本表、再转成 Excel”的习惯。我的建议是别走这步弯路脚本直接生成 xlsx字段格式一次定好后面批次直接复用模板。2. 测试环境搭建与基础准备2.1 硬件选型与连接要点USB 转 I2C 适配器市面上方案很多我实际用下来主要看三个东西频率精度、软件生态、是否支持协议级抓包。点名几个常见方案芯片/方案优点缺点适合场景FT232H频率可控、pyftdi 库成熟、支持多协议价格稍高自动化脚本、批量测试CH341A便宜、工具多Windows 驱动签名麻烦、频率精度一般临时验证、简单读写CP2112HID 免驱、官方有 Excel 插件可定制性弱快速扫描、记录到表格总线分析仪抓包深度强、时序测量准贵疑难问题定位我这次用的是 FT232H 方案主要看中 pyftdi 库可以直接在 Python 里配置频率和探测地址方便后面生成 Excel。如果你是第一次玩CH341A 也能用但如果你打算把流程固化下来反复跑建议直接上 FT232H 或同级别方案省下的时间比差价值钱。连接上要注意四根线SCL、SDA、GND还有一个电源轨。I2C 是开漏结构SCL 和 SDA 必须接上拉电阻到电源不能只接两根信号线就指望通信。上拉电阻阻值的选择有个简单估算以 3.3V 系统、总线电容约 100pF 为例上升时间约等于 0.85 乘以电阻再乘以电容要保证 100KHz 下上升沿不超过 1us电阻取 4.7k 左右是安全值。总线长了或挂的设备多了电容变大电阻就适当往小了选比如 2.2k。还有一个容易忽略的点如果你的适配器输出电平是 5V而板子是 3.3V 器件最好确认适配器有没有电平转换或者用外部电平转换模块别直接硬怼。还有一个反直觉的经验SCL 和 SDA 两根信号线尽量短、尽量等长。杜邦线超过 20cm 在 400KHz 下基本会出问题100KHz 虽然容限大但线太长会让边沿变缓导致适配器采样到错误的电平。我测试时习惯把杜邦线控制在 10cm 以内实在要延长就换双绞线或者加总线缓冲器。2.2 软件工具链与驱动准备先说一个常见的坑USB 转 I2C 和 USB 转串口并不是一回事。FT231X 是 USB 转 UART 的芯片驱动名字里带 UART而 FT232H 这类支持 I2C/SPI/JTAG 的是靠 MPSSE 引擎功能完全不同。别看到 USB 相关就去找 UART 驱动很多新手卡在这一步。Windows 下用 FT232H需要装 FTDI 的 D2XX 驱动或 VCP 驱动推荐 D2XX。Linux 下一般不用额外装驱动内核自带 ftdi_sio配合 pyftdi 直接访问即可。需要提醒的是如果你在虚拟机里调试USB 设备透传经常会出幺蛾子比如设备枚举不稳定、驱动加载失败。我的习惯是物理机上跑调试脚本虚拟机只用来写文档。软件这边我主要用 Python 加两个库pyftdi 负责 USB 转 I2C 通信openpyxl 负责生成 Excel 报告。安装很简单pip install pyftdi openpyxl装完先跑一个最简单的连接测试确认适配器能被系统识别from pyftdi.ftdi import Ftdi print(Ftdi().list_devices())能看到类似ftdi://ftdi:232h/1的设备路径说明环境已经通了。这个步骤一定要先做不然后面所有代码都会卡在设备识别上你还以为是接线问题。3. 100KHz 速率时序验证参数规格与实测方法3.1 标准模式时序参数速查说 100KHz 测试不能只把频率设成 100000 就完事。I2C 标准模式除了 SCL 频率上限还规定了一堆时序参数我在测试记录里固定了几个必须看的参数标准模式要求含义fSCL最高 100kHzSCL 时钟频率tHIGH最小 4.0usSCL 高电平时间tLOW最小 4.7usSCL 低电平时间tr最大 1usSCL/SDA 上升沿时间tf最大 0.3usSCL/SDA 下降沿时间tSU;DAT最小 250nsSDA 数据建立时间tHD;DAT最小 0nsSDA 数据保持时间tSU;STO最小 4.0us停止条件建立时间很多适配器标称 100kHz实测可能只有 96kHz或者高电平时间偏短。频率差几个 kHz 通常不影响通信但如果 SCL 高电平时间不够 4us那就是硬性违规某些要求严格的从设备会直接不响应。所以速率测试不只是把频率参数填上还要用逻辑分析仪或示波器实际抓波形逐项对照这张表。3.2 用逻辑分析仪实测 SCL 频率与边沿抓波形时逻辑分析仪采样率建议至少 25M最好 50M。采样率太低会看到很多假毛刺影响判断。接好通道后让脚本对一个已知设备重复读写比如我常用 0x50 地址的 EEPROM 做目标循环读它的状态寄存器。抓到的波形上重点看三件事SCL 实际频率是多少、高电平低电平分别多长、上升沿有没有明显变缓。实测记录里一个重要心得SCL 频率是从一个上升沿到下一个上升沿算周期再换算成频率不要只看一个脉冲的宽度。占空比也要留意标准模式没规定占空比要 50%但如果看到明显不对称比如高电平只有 2us、低电平有 8us说明适配器要么是软件模拟时序要么频率配置有问题。边沿缓是最容易被忽略的问题。上升沿如果超过 1us在长总线、大电容的条件下很容易出现表现是设备偶发不应答、或者某个地址扫描时有时无。如果你抓波形看到梯形波而不是方波优先怀疑上拉电阻太大或总线上电容太大而不是怀疑适配器。3.3 时序参数不合格怎么调实测发现时序不合格排查顺序很固定。频率整体偏低先看适配器配置是不是真的生效了pyftdi 里 frequency 参数设置后可以用工具读回有些型号标称和实际差 10%换一个品牌适配器往往就好了。高电平时间不够通常是适配器时序引擎的问题比较多见于软件模拟 I2C 的方案解决方法是换带硬件 I2C 控制器的适配器芯片或者降低目标频率到 90kHz。上升沿太缓这是硬件问题减上拉电阻阻值、缩短线缆、减少挂载设备数量三选一或三选二。下降沿缓少见通常是被测板上的地线阻抗问题检查共地是否可靠。我的习惯是每调一次参数就重新抓一次波形并把前后两组数据并排写进 Excel。这样调完心里有数到底是频率配置的偏差还是板子布线的问题查记录一眼就能看出来。4. 地址扫描与 Excel 记录实现4.1 I2C 地址扫描的原理与扫描算法扫描的原理说白了就是“试探”。I2C 通信的第一步是主控发出起始条件然后发送 7 位从设备地址加 1 位读写标志。如果总线上有设备匹配这个地址它会在第 9 个时钟周期把 SDA 拉低也就是回应 ACK如果没人认领这个地址SDA 保持高电平即 NACK。扫描就是遍历所有合法地址看哪个地址收到 ACK。合法地址范围要注意一下。7 位地址理论上有 128 个但 0x00 到 0x07 和 0x78 到 0x7F 是保留地址分别用于广播、起始字节、HS 模式前缀、10 位寻址扩展等普通扫描直接跳过。实用范围是 0x03 到 0x77共 117 个地址。还有一个细节有的从设备只对读方向应答有的只对写方向应答。比如某些传感器你发“地址写位”它不鸟你发“地址读位”才应答。所以完整的扫描要对每个地址都做一次读探测和一次写探测。这也是为什么 I2C 扫描工具的菜单里通常有 Read mode 和 Write mode 的选项。4.2 用 Python 快速实现 100KHz 扫描基于 pyftdi完整的扫描脚本可以这样写from pyftdi.i2c import I2cController, I2cIOError CTRL I2cController() CTRL.configure(ftdi://ftdi:232h/1, frequency100_000) hits [] for addr in range(0x03, 0x78): for direction, read_flag in ((R, True), (W, False)): try: ack CTRL.probe(addr, readread_flag, writenot read_flag) if ack: print(f0x{addr:02X} {direction} ACK) hits.append((addr, direction)) except I2cIOError: continue print(ftotal ACK: {len(hits)})说明几个要点。frequency 参数直接设 100000pyftdi 会按这个目标频率初始化。probe 方法内部实现了完整的起始、地址发送、等待 ACK、停止流程比自己用 exchange 拼字节省心。循环里读和写分开探测避免漏掉单方向应答的设备。每个地址探测之间会有微秒级延时整体遍历 117 个地址、两个方向大概两三秒。跑完扫描你不仅知道哪些地址在线还能初步判断有没有地址冲突。正常情况下总线上 0x50 有设备就只该出现 0x50如果 0x50 和 0x51 都响应而且你明明只挂了一片 EEPROM那就要怀疑地址引脚配置错了或者芯片本身有问题。4.3 Excel 记录格式设计与多批次对比扫描结果如果只是打印到屏幕那就失去了一半价值。我的 Excel 表结构固定成这样字段示例说明批次A对应标题里的 _A测试时间2025-01-18 14:30精确到分钟板卡编号BRD-003被测板号适配器型号FT232H记录测试环境设定频率100000 Hz脚本参数实测SCL频率98.5 kHz逻辑分析仪读数SCL高电平4.3 us逻辑分析仪读数SCL低电平5.1 us逻辑分析仪读数上拉电阻4.7 kOhm板上实测值供电电压3.3 V测量点电压应答地址列表0x50(W),0x50(R)扫描结果汇总异常说明无异常才填判定PASS条件格式判断写入 Excel 用 openpyxl核心思路是先把所有结果整理成列表再一次性写入避免逐格操作浪费时间。顺带做一个条件格式判定为 FAIL 的行自动标红没有应答设备时把应答地址列表标黄。这样后面堆了几十行数据扫一眼颜色就能发现问题。具体代码可以这样from openpyxl import Workbook from openpyxl.styles import PatternFill RED PatternFill(solid, start_colorFFC7CE) YELLOW PatternFill(solid, start_colorFFEB9C) wb Workbook() ws wb.active ws.append([批次, 测试时间, 板卡编号, 应答地址列表, 判定]) # 假设 scan_data 是已整理好的字典列表 for row in scan_data: ws.append(list(row.values())) for r in ws.iter_rows(min_row2): if r[4].value FAIL: for cell in r: cell.fill RED elif r[3].value : r[3].fill YELLOW wb.save(i2c_scan_100k_A.xlsx)一个容易踩的坑是地址列表写入 Excel 后变成科学计数法或数字格式比如 0x50 被解释成 80。解决办法是地址以字符串形式写入比如0x50而不是0x50这个整数openpyxl 写入字符串就不会被转换。5. 常见问题与排查经验实录5.1 全扫无应答的排查顺序这是最打击人的情况代码没问题适配器也识别了但扫描结果一个 ACK 都没有。排查顺序我建议固定下来能省大量时间。第一步量静态电平用万用表量 SCL 和 SDA 对地电压正常空闲状态应该都是高电平接近电源电压。如果 SDA 是低电平大概率是总线上某个设备把总线拉死了常见原因是设备地址冲突或者从机锁死。如果两根线都是低电平大概率是没接上拉或者上拉接到了没有供电的电源轨。第二步检查接线顺序SCL 和 SDA 接反在杜邦线场景下极其常见。我踩过一次坑两根线颜色太接近插反之后扫了十分钟全空最后量电平才发现问题。后来习惯用固定配色SDA 用橙色、SCL 用黄色写进测试规范里。第三步确认共地。适配器的 GND 和板子的 GND 必须连在一起否则 I2C 信号参考地不一致什么诡异现象都可能出。最后再怀疑驱动和设备枚举用前面提到的Ftdi().list_devices()确认设备路径还在有时候 USB 线接触不良导致设备掉线脚本报错提示会让人误以为是总线问题。5.2 扫描结果时有时无与数据粘连问题扫描地址列表和上一次不一样或者同一个地址这次能扫到、下次又没了这类问题最烦。先说软件层面的原因如果适配器是软件模拟 I2C系统调度抖动会导致时序不稳定某个地址正好卡在 ACK 判定边缘就会时有时无。解决方法是换硬件 I2C 引擎的适配器比如 FT232H 的 MPSSE 就是硬件状态机时序稳定很多。再说硬件层面的原因总线过长或者上拉电阻偏大导致上升沿太缓从设备发出的 ACK 信号还没抬到高电平阈值适配器就采样了于是误判成 NACK。这种问题在 100KHz 下也能出现只是概率低一些。排查时用逻辑分析仪抓那个“时有时无”的地址观察 ACK 位的波形如果 SDA 在 ACK 窗口内呈现缓慢上升的形态就可以确定是边沿问题。还有一种情况是 SDA 数据粘连。现象是所有地址都显示 ACK密密麻麻一大片。这通常是探针逻辑写得不严谨设备 NACK 之后没有正确释放总线或者适配器驱动在异常后没有做总线恢复。做法很简单每个地址探测之间加一个小的总线空闲延时另外设置总超时时间超时就强制停止条件。若某次扫描发现 0x00 或者 0x7F 这种保留地址也出现 ACK先检查扫描范围再检查是不是总线被异常拉低了。5.3 与驱动、线缆相关的隐性坑驱动问题上常见的是用户把 USB 转 UART 驱动和 USB 转 I2C 驱动搞混。FT231X 是单路 UART 芯片FT232H 是带 MPSSE 的多协议芯片两者驱动不通用。装错驱动之后设备管理器里能看到设备名但 pyftdi 打开时会报设备忙或功能不支持这时候先别怀疑代码去看看驱动对不对。线缆方面USB 延长线太长会导致适配器供电不足适配器工作不稳定。我测试时如果用了 USB 延长线会优先插在主板的背板 USB 口而不是前置面板前置口供电质量和主板口差不少。还有一次问题是 USB 线本身是充电线只接了电源线没接数据线设备管理器里压根看不到设备。这种低级错误现在回想起来都好笑但确实会浪费半小时。虚拟机透传 USB 设备也是一类坑点。Windows 主机里跑 VirtualBox 或 VMware把 FT232H 透传给虚拟机系统常见现象是透传后设备正常但过几分钟设备掉了或者说 Adapter busy。这不是适配器问题是虚拟机的 USB 控制器 interrupt 处理不及时。调试 I2C 这类对实时性有一定要求的场景我不建议在虚拟机里跑。6. 这套流程的扩展场景与个人体会6.1 从单板调试延伸到产线批量测试这个 Excel 扫描流程如果只是自己调试用其实有点浪费。我后来把它扩展成了产线工装每个板卡插上之后脚本自动跑扫描、自动测 SCL 频率、自动判定 PASS/FAIL结果按板卡编号写入 Excel月底汇总一下就能看出这批物料的一致性。因为是基线测试我不需要每个板卡都做复杂读写只需要确认设备在线、地址对、时序达标这三项能过滤掉绝大多数虚焊、贴错料、地址引脚搭锡的问题。批量测试时Excel 的价值会更明显。我可以按批次筛选看某一批板卡的应答地址分布如果正常板子都是 0x50、0x68 两个地址某一批突然多出一个 0x51那就说明 EEPROM 的地址引脚有异常。没这种表格你只能一块块板翻日志。6.2 给新人的三点实操建议如果这篇文章你只记住三件事我希望是这三条。第一条动手前先量电平再谈扫描。SCL 和 SDA 空闲必须为高这是判断接线和上拉是否正确的最快方式别一上来就跑代码排错半天才发现线没接对。第二条设置完 100KHz 之后一定要用逻辑分析仪实测一遍不要信“我设了 100K”这句话。我测过不少适配器标称 100K 实际只有 70K 的都有这种系统性偏差平时不明显一旦到了协议边界就会暴露。第三条地址列表统一用两位十六进制字符串记录不要裸存整数不然到 Excel 里就变成十进制数字了看起来极不直观。最后再分享一个小技巧。我每次拿到新板子第一件事就是跑一遍 Scan 加 100KHz 基线把通过的那次结果单独存成一个“黄金模板”。之后每批板子扫描完脚本自动和黄金模板做对比只要应答地址列表有差异哪怕差一个地址都标记为 FAIL。这样做的效果是你不需要记住每块板子上该有哪些器件也不需要每次对着原理图数地址异常会在对比的瞬间自己跳出来。这套流程跑顺之后I2C 总线检查从“抓瞎式调试”变成了“填表式验收”省下来的时间足够你多调几个真问题。