ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

USB转I2C适配器1MHz扫描实操:上拉、时序与Excel总线地图

2026/9/25 7:44:56 拓冰建站 浏览量
USB转I2C适配器1MHz扫描实操:上拉、时序与Excel总线地图 干嵌入式这几年I2C 总线调试是我最常打交道的事。上个月碰到一块测试板总线上一共挂了七八个从机有 EEPROM、触摸屏、温湿度传感器还有一个 IO 扩展芯片。每次新板回来我最先做的事不是翻原理图而是拿 USB 转 I2C 适配器把整条总线扫一遍看哪些地址有应答、哪些地址是空的、上拉是否正常。最近触摸屏那边要求把总线速率提到 1000KHz 跑数据我就把“USB 转 I2C 适配器 Excel 扫描记录”这套流程重新捋了一遍顺带把 1MHz 下的时序和信号完整性排查也做完了。如果你手里也有适配器想快速扫总线或者想在 1MHz 下验证 I2C 稳定性这篇实操记录应该能用得上。1. 项目整体设计与思路拆解1.1 为什么优先选 USB 转 I2C 适配器调试 I2C 总线方案其实不少焊根线用单片机板子去读、用逻辑分析仪抓波形、或者直接用带 I2C 功能的 USB 调试器。我的习惯是优先用 USB 转 I2C 适配器原因很简单它不占用目标板的 CPU不需要在目标板上烧额外固件连接即用而且能主动发起通信去枚举总线上的设备。市面上这类适配器常见的架构有三种。一种是 CH341 系列便宜、普及率高但长时间高速跑的时候波形边沿不算干净时序参数也往往锁在固件里想插入自定义延时很费劲。另一种是 FTDI 的 FT260纯硬件 USB 转 I2C稳定但同样存在时序参数不可自由调整的问题。我这次用的是 FT231X MCU 组合的方案FT231X 负责把 USB 转成虚拟串口MCU 用 GPIO 模拟 I2C 主控时序。看起来绕了一圈实际最可控因为总线速率、上下沿延时间隔、地址范围全都可以自己改而且 FT231X 的 VCP 驱动在 Windows、Linux 下都成熟基本不会在驱动层翻车。1.2 1000KHz 总线速率测试到底要解决什么问题I2C 的速率等级里标准模式是 100KHz快速模式是 400KHz快速模式Fm最高到 1MHz。1000KHz 这个名字听起来唬人其实就是 Fm 的上限。那为什么非要去摸这个上限因为项目里触摸屏上报坐标数据、传感器批量读缓存在 400KHz 下会有明显的等待感。把总线提到 1000KHz单次读取时间直接砍一半以上。当然总线上不是所有器件都支持 1MHz。有的 EEPROM 手册只写到 400KHz有的老传感器标准模式都费劲。所以这次测试的目的不是让每颗芯片都跑到 1000KHz而是想用一个统一的扫描工具把所有设备在 1MHz 下的 ACK 情况、时序余量、上拉是否匹配一次测出来再把结果整理成一个可留档、可对比的报告。1.3 Excel 不是摆设是扫描结果的报告层很多人做总线扫描习惯在终端里看一串十六进制地址就完事。但我盯上 Excel 是有原因的调试过程中真正有用的不是“当前哪几个地址有 ACK”而是“上一版固件和这一版固件相比总线设备地图发生了什么变化”。Excel 天然适合做这种数据对比配合条件格式能快速标出新增设备和消失设备。另外扫描结果是典型的结构化数据时间、总线速率、地址、ACK、设备类型。这种数据没有比 Excel 更适合做台账的。我自己一般是让适配器扫完后自动输出 CSV再用 Python 脚本转成 Excel 报告顺便生成一个 16×8 的地址热力图。后面调硬件、换芯片、改上拉电阻每次扫描都留一份报告几轮下来问题定位会变得非常直观。2. 环境搭建与工具链准备2.1 硬件接线与 FT231X 驱动安装先说接线。USB 转 I2C 适配器引出四根关键线SCL、SDA、GND还有一个电源脚。绝大多数情况下接三根就能扫描但 GND 必须共地否则 SDA 和 SCL 的参考电平不一致扫描结果会全是乱码。电源脚我一般用 3.3V除非目标板明确是 5V 系统。如果目标器件是 1.8V 供电就不能直接接适配器的电源必须加电平转换。驱动方面FT231X 在 Windows 下会被识别成一个 COM 口。安装 VCP 驱动后设备管理器里能看到“USB Serial Port (COMx)”。如果第一次插上识别成未知设备或者带黄色感叹号建议先卸载旧驱动再重装别直接在老驱动上覆盖。在 Windows 7 这种老系统上装新版本驱动时我遇到过签名问题处理办法是去设备管理器里手动指定驱动目录搜索安装。驱动装好之后适配器在串口层跑私有协议上位机只需要打开对应 COM 口、设置波特率然后发扫描指令。2.2 配套工具和抓包手段除了适配器这次测试我还用了三样东西逻辑分析仪、示波器、USB 抓包工具。逻辑分析仪采样率至少要 100MHz测 1MHz 总线时建议上 200MHz 以上否则根本看不到上升沿的细节。示波器带宽 50MHz 以上就够用主要用来量 SCL/SDA 的波形上升时间和电平摆幅。USB 抓包工具在排查适配器本身的问题时特别有用。比如上位机发了一条扫描命令但适配器没有执行这时候单纯量 I2C 引脚是看不出来的需要抓 USB 包判断命令有没有从主机发出来、适配器有没有回 ACK。我习惯用 Wireshark 配合 USBPcap 抓 USB 传输虽然看 USB 协议栈比看串口日志费劲但在“设备代码 12”“驱动异常”这类问题上它能直接给出根因。3. 1000KHz 速率下 USB 转 I2C 扫描的完整实践3.1 扫描范围和保留地址的处理I2C 地址是 7 位8 位地址字节由“7 位地址 1 位读写位”组成。举个例子某颗从机地址是 0x50那么它的写地址字节就是 0xA00x50 1读地址字节就是 0xA1。总线扫描要做的就是挨个发送地址并检测从机是否回 ACK。扫描范围不能盲扫 0x00~0x7F因为协议里有一堆保留地址。0x00 是通用呼叫地址0x01 是 CBUS 地址0x02、0x03 以及 0x04~0x07 也属于保留区域高位的 0x78~0x7B 是 10 位寻址相关的保留区0x7C~0x7F 同样是保留。实际扫 0x03 到 0x77 就够了避开这些特殊地址避免误报。7 位地址用途是否扫描0x00通用呼叫地址否0x01CBUS 地址否0x02~0x07保留地址否0x03~0x77正常从机地址区是0x78~0x7B10 位寻址相关否0x7C~0x7F保留否扫描逻辑本身不复杂核心就是“发 Start发地址字节等 ACK发 Stop”。为避免从机误动作我一般只发一个地址字节而不带数据然后立刻 Stop。伪代码如下for (uint8_t addr 0x03; addr 0x77; addr) { i2c_start(); uint8_t ack i2c_write_byte((addr 1) | 0x00); if (ack I2C_ACK) { uart_send_scan_result(addr, 1); } else { uart_send_scan_result(addr, 0); } i2c_stop(); }在 1000KHz 下每一轮扫描也就一百多次通信几十毫秒就能跑完。真正花时间的是后面的波形确认和结果整理。3.2 1000KHz 的时序参数怎么换算1MHz 的时钟周期是 1 微秒。I2C 协议要求的不是单一占空比而是 SCL 高电平和低电平各自的最小时间。快速模式Fm下SCL 低电平最小 0.5 微秒高电平最小 0.26 微秒建立时间、保持时间也都是纳秒级。如果用的是 MCU 的硬件 I2C 外设直接按数据手册配置速率寄存器即可如果用 GPIO 模拟就必须在某一个确定的时钟频率下计算延时。速率模式SCL 频率tLOW 最小值tHIGH 最小值标准模式100KHz4.7µs4.0µs快速模式400KHz1.3µs0.6µs快速模式1MHz0.5µs0.26µsGPIO 模拟时我给 SCL 高电平和低电平各分配了约 500ns这样组合起来正好 1MHz。但 MCU 的中断响应不稳定所以延时不能用 delay 循环加塞最好用定时器输出比较翻转或者 PWM 模式来生成 SCL 波形。如果只用普通 delayIRQ 一进来波形就会拉伸逻辑分析仪上看到的 SCL 频率会忽高忽低。还有一个容易被忽略的点时钟拉伸Clock Stretching。高速从机在内部处理时会把 SCL 拉低主机必须检测这个状态并且等待否则后续数据位会踩到从机的内部时序上。所以扫描时每一笔通信都要带上超时判断超时时间设 1ms 左右就行太长会让整个扫描过程卡住太短又可能在低速从机上误报 NACK。3.3 上拉电阻计算与信号完整性调优I2C 是开漏拓扑SDA 和 SCL 必须靠上拉电阻把电平拉高。速率越高对上升沿的要求越苛刻。总线上电容包括芯片引脚电容、PCB 走线电容、连接线电容频率越高允许的上升时间越短能用的上拉电阻上限就越小。上拉电阻最小值和最大值分别由灌电流和上升时间决定。先看最小值VCC 取 3.3VVOL 按 0.4V 算快速模式下 IOL 按 3mA 算Rp(min)≈(3.3-0.4)/0.003≈967Ω。再看最大值用简化公式 Rp(max)tr/(0.8473×Cbus)。快速模式要求的上升沿约 120ns如果总线电容是 100pF算下来 Rp(max)≈1.4kΩ如果电容达到 200pF就只能用 700Ω 左右的上拉。总线总电容允许的最大上拉电阻约50pF2.8kΩ100pF1.4kΩ200pF0.7kΩ所以我这次测试直接在适配器和目标板上同时并上 1kΩ 左右的上拉。目标板原先默认是 4.7kΩ 上拉400KHz 下还凑合跑到 1MHz 时SCL/SDA 的上升沿明显变圆从机就开始随机 NACK。后来在适配器侧并了一个 1kΩ等效上拉降到 1kΩ 附近波形才干净。遇到这种问题不要一上来就怀疑芯片先把示波器或逻辑分析仪夹在 SCL/SDA 上看一眼上升沿比盲改固件快得多。4. Excel 扫描结果的数据化处理4.1 扫描结果落地为 CSV适配器扫描完成后上位机把结果以 CSV 格式输出。CSV 是 Excel 最友好的格式没有格式兼容问题。我通常会让脚本把原始地址、ACK 标志、读取到的设备 ID、注释全部写进同一行。scan_time,bus_rate_khz,addr_7bit,write_addr,ack,device_id,remark 2024-06-18 09:41:05,1000,0x18,0x30,1,0xA0,EEPROM 2024-06-18 09:41:05,1000,0x5D,0xBA,1,0xBA,Touch_GT911 2024-06-18 09:41:05,1000,0x77,0xEE,0,0x00,empty有人习惯直接把日志复制到 Excel但终端日志里混着错误提示和乱码清洗起来费劲。我的做法是扫描工具里直接写好 CSV 文件头每次扫描自动覆盖同名文件后面再接 Python 脚本转 Excel。这样既保留了原始数据又能快速生成带格式的报告。4.2 用 Python 生成 Excel 报告Python 这边用 pandas 加 openpyxl 就够了。先把 CSV 读进来然后写入 Excel顺手按 ACK 字段做筛选和排序。import pandas as pd df pd.read_csv(i2c_scan_1000k.csv) df_ack df[df[ack] 1].copy() df_ack df_ack.sort_values(addr_7bit) with pd.ExcelWriter(i2c_scan_report.xlsx, engineopenpyxl) as writer: df.to_excel(writer, sheet_name原始扫描, indexFalse) df_ack.to_excel(writer, sheet_name有效设备, indexFalse)如果不想装 pandas直接用 Python 标准库 csv 读入再用 openpyxl 逐行写入也行。关键在于列对齐和表格样式不要把地址当成数值去求和。Excel 里 7 位地址建议写成文本格式比如 0x18否则显示成 24 并且丢掉十六进制语义。4.3 Excel 条件格式做地址热力矩阵比起逐行看 CSV我更习惯在 Excel 里做一张 16×8 的地址热力矩阵。行为地址高四位 0x0~0xF列为地址低四位 0x0~0xF单元格填 1 表示扫描到 ACK0 表示没有。矩阵做出来后用条件格式选中区域新建规则把等于 1 的单元格填成深绿色等于 0 的填成浅灰色。这样整个总线上哪些地址被占用一眼就能看出来。如果要在 Excel 里快速生成矩阵可以用 INDEX 和 MATCH 从原始扫描表里提取数据也可以直接用 Python 把矩阵生成好再写入 Excel。我自己是把矩阵生成逻辑写进脚本扫描一结束就自动出图省去手工拉表的功夫。Markdown 表格转 Excel 也顺便提一句如果从调试日志里复制了 Markdown 表格Excel 往往不能直接粘贴识别。先把竖线分隔的文本存成 .csv再用 Excel 的文本导入向导按“|”拆分列就干净了。5. 常见问题与排查技巧实录5.1 设备明明在线但 1000KHz 下扫描不到这个现象我遇到很多次。设备在 100KHz 下能正常 ACK一到 1MHz 就消失。先别急着怀疑适配器按顺序做三件事第一把速率降到 400KHz 再扫一次确认设备本身支持快速模式第二用逻辑分析仪看 SCL/SDA 的上升沿如果 SDA 上升沿明显超过数据手册要求问题大概率在上拉第三确认接线长度。1MHz 下飞线超过 20cm 就开始有风险长线带来的电容和串扰会让边沿恶化。有的芯片本身只保证 400KHz比如某些老款 EEPROM强行跑 1MHz 就是会 NACK这不是故障是规格限制。如果对某个从机的最高速率没把握最可靠的办法是看数据手册的 AC 特性表再配合实际波形确认。5.2 GT911 触摸屏 I2C 通信失败排查GT911 是项目里最挑剔的从机。它常用 7 位地址 0x5D8 位写地址是 0xBA。第一次在 1MHz 下扫描时GT911 时常不 ACK或者在地址应答后读回来的数据全是 0xFF。排查时发现问题往往不是 I2C 总线速率本身而是复位和中断引脚的状态没处理好。GT911 上电后要先经历复位时序INT 引脚状态会决定芯片是否进入正常模式。如果单纯把 SCL/SDA 接好就开始扫描芯片可能还在复位或者休眠状态自然不回 ACK。处理办法是把触摸屏的 RST 和 INT 引脚也接到控制端严格按照数据手册的顺序完成上电初始化再开始 I2C 通信。初始化正常后GT911 在 1MHz 下能够稳定读写但如果 SCL 上升沿太缓还是偶发丢 ACK。把上拉调整到 1kΩ 级别后这个问题就基本消失了。5.3 Windows 下“代码 12”和 STM32 虚拟串口识别不了Windows 设备管理器里如果看到“该设备找不到足够资源可以使用 (代码 12)”本质是 USB 控制器或驱动层资源分配出了问题。常见原因有几个主板 USB 控制器资源冲突或者驱动版本和系统不匹配或者系统休眠后控制器的状态没恢复好。处理顺序一般是先拔掉设备禁用再启用 USB 根集线器换一个 USB 口再重装驱动。在电源管理里把“允许计算机关闭此设备以节约电源”关掉可以避免大量偶发掉设备问题。另外STM32 自己做 USB 虚拟串口时偶尔也会在 Windows 上识别不了。这种情况和 FT231X 这类成熟方案不一样通常要看 USB 描述符、DP 上拉电阻和晶振精度。比如晶振偏差太大枚举阶段就会失败。如果项目里真要用单片机自带 USB 虚拟串口建议先把枚举抓包看清楚再做稳定性测试。5.4 扫描出现大量虚假地址有时候总线上明明只挂了两颗设备扫描结果却一大片 ACK这种假象很坑人。常见原因包括SDA 被拉低且没有正常上拉、从机没上电但通过 IO 保护二极管偷电、适配器和目标板的地没连好。扫描前先量一下 SDA 和 SCL 的静态电平正常空闲状态下两根线都应该被上拉到高电平。如果 SDA 只有零点几伏那扫描结果再漂亮也没意义。还有一种情况是地址被误判。某些从机在上电默认状态下不完整支持 I2C 协议或者总线刚释放时残留毛刺可能导致适配器把噪声当成 ACK。所以扫描开始前最好连续发几个 Stop 信号让总线复位再开始枚举地址。总线释放干净后虚假地址会明显减少。现象可能原因处理办法1MHz 下设备丢失不支持高速模式 / 上拉太弱降速验证调整上拉GT911 随机 NACK复位时序不对 / 上升沿过缓处理 RST/INT降低等效电阻设备管理器代码 12USB 控制器资源冲突禁用启用根集线器更新驱动扫描出一堆假 ACKSDA 浮空 / 地没共量静态电平发总线释放序列6. 实操心得与后续扩展这次做完我最大的体会是凡是 1000KHz 下的 I2C 问题先处理上拉再查芯片。时序参数、寄存器配置都是次要的信号完整性不过关后面全白搭。另外一定要给扫描结果留 Excel 台账不要相信记忆力。上一版板的哪个地址有设备、上拉改了之后有没有新增 ACK这些数据过两星期再看比你想的有用得多。后续我打算在适配器这边加一个 PCA9306 电平转换板这样就能直接扫 1.8V 的 ARM 平台。再往后想把扫描脚本改成定期自动跑长时压测 1MHz 下的 ACK 成功率。我现在的习惯是每块新板子都先出这么一张 Excel 总线设备地图后续改硬件、加器件、调上拉再扫一次直接对比。很多看似诡异的总线问题其实在第一轮高速扫描的时候就埋下伏笔了。