1. 项目概述CircuitPython 开发中的那些“坎儿”玩嵌入式开发尤其是用 CircuitPython 这类对新手友好的平台最扫兴的莫过于代码写了一半板子突然“不听话”了。CIRCUITPY 盘符消失、文件无法保存、板载 LED 狂闪错误码……这些问题就像路上的小石子虽然不致命但足以让你停下脚步折腾半天。我接触过很多从 Arduino 转过来的朋友他们习惯了相对“直接”的烧录方式初次遇到 CircuitPython 的“软”驱动和文件系统管理时常常会感到困惑。其实这些问题背后都有清晰的逻辑和解决方法。这篇指南不会教你写代码而是聚焦于让开发环境“跑起来”和“稳定运行”的底层实操。无论你是在 macOS 上被缓慢的写入速度折磨还是在 Windows 上遭遇了杀毒软件的“误伤”亦或是搞不清如何进入安全模式救砖下面的内容都是我这些年踩过坑、填过土后总结出的经验希望能帮你把更多时间花在创造上而不是排错上。2. 核心问题分类与诊断思路遇到问题最忌无头苍蝇般乱试。首先得建立一个清晰的排查路径。CircuitPython 的问题大体可以归为三类连接与识别问题、文件系统与运行问题以及固件与库兼容性问题。每一类问题都有其典型症状和入口检查点。2.1 连接与识别问题电脑“看不见”板子这是最让人焦虑的问题表现为插入 USB 线后电脑没有任何反应或者预期的CIRCUITPY或BOOT驱动器没有出现。首要检查清单基础物理层换一条高质量的 USB 数据线很多充电线只能供电。尝试电脑上不同的 USB 端口特别是机身后面的主板原生接口前置接口可能供电不足。板子状态确认观察板载 RGB LED如果有。刚上电时多数 Express 板子会有一串黄色闪烁这是正常启动过程。如果 LED 毫无反应检查供电。驱动模式判断CircuitPython 板子通常有两种模式运行模式显示CIRCUITPY驱动器可像 U 盘一样访问。引导加载模式显示CPLAYBOOT、FEATHERBOOT等驱动器用于拖放.uf2固件文件。 通过双击板载RESET按钮可以在两者间切换。一个关键细节对于运行 MakeCode 程序的 Circuit Playground Express进入引导加载模式只需单击一次RESET双击反而无效。这是 MakeCode 固件的一个特性。操作系统特异性疑难杂症Windows 10/11现代 Windows 通常无需额外驱动。但如果之前安装过旧的 Adafruit Windows Drivers (v1.5)它可能会干扰系统自带的通用驱动。请到“设置 - 应用”中卸载所有名为 “Adafruit” 的驱动程序包。macOS某些硬盘工具如 DriveDx 及其配套的 SAT SMART Driver会劫持 USB 通信导致BOOT驱动器无法显示。临时退出或卸载这些工具通常可解决问题。第三方软件冲突Windows 重灾区这是最隐蔽的一类问题。当你尝试访问BOOT驱动器时如果 Windows 资源管理器卡死或无响应很可能是以下软件在作祟AIDA64停止该程序进程。卡巴斯基 (Kaspersky)、比特梵德 (BitDefender)、ESET NOD32等安全软件尝试完全禁用实时防护有时甚至需要临时卸载。它们可能将 UF2 驱动的枚举操作误判为恶意行为。硬盘哨兵 (Hard Disk Sentinel)、西部数据工具这些磁盘工具也可能干扰。实操心得在 Windows 上进行 CircuitPython 开发我养成了一个习惯遇到无法识别的板子首先打开任务管理器结束所有非必要的、特别是硬件监控和高级安全软件的进程这能解决至少一半的“玄学”问题。2.2 文件系统与运行问题CIRCUITPY 的“怪现象”当CIRCUITPY驱动器能出现但行为异常时问题就进入了文件系统层面。典型症状与排查CIRCUITPY 盘符时隐时现或显示为NO_NAME这几乎是文件系统损坏的明确信号。根本原因通常是未安全弹出就断电或复位。Windows 的快速删除策略、macOS 的写入缓存都可能加剧这一问题。文件无法保存提示“磁盘被写保护”或“空间不足”除了真满在 SAMD21 无外置闪存的板子上很常见更可能是文件系统处于只读模式。这可能是你在boot.py中设置了storage.remount(/, readonlyTrue)也可能是系统在检测到磁盘错误后自动挂载为只读。code.py 不断自动重启Auto-reload 失控CircuitPython 的自动重载功能本是为了方便但某些后台程序如 Acronis True Image 的备份服务、杀毒软件的实时扫描会频繁写入CIRCUITPY驱动器的元数据导致 CircuitPython 误以为代码被修改从而陷入“保存 - 重启 - 保存”的死循环。macOS 写入缓慢问题Sonoma 及之前版本这是一个经典的系统级 Bug。在 macOS Sonoma 14.4 之前向小容量 FAT 磁盘如 8MB 的CIRCUITPY写入文件时目录更新会延迟数十秒导致写入失败。14.4 至 15.2 之间的版本对 1GB 以下 FAT 盘的写入速度极慢。解决方案升级系统macOS 15.2 及以上版本已修复。重新挂载脚本如果无法升级可以使用一个 Shell 脚本在驱动器挂载后立即以noasync异步关闭模式重新挂载。将脚本保存为remount-CIRCUITPY.sh并赋予执行权限 (chmod x)。每次插入板子后运行一次即可。#!/bin/sh # 此脚本用于解决 macOS 14.x 在写入小容量 FAT 驱动器时的延迟问题 diskydf | grep CIRCUITPY | cut -d -f1 sudo umount /Volumes/CIRCUITPY sudo mkdir /Volumes/CIRCUITPY sleep 2 sudo mount -v -o noasync -t msdos $disky /Volumes/CIRCUITPY2.3 固件与库兼容性问题版本不匹配的“苦果”CircuitPython 生态更新活跃但也带来了兼容性挑战。.mpy文件不兼容错误这是最直接的版本冲突提示。.mpy是 CircuitPython 的预编译库文件其格式在主要版本间如 6.x 与 7.x不兼容。错误信息通常为ValueError: Incompatible .mpy file。这意味着你正在尝试在 CircuitPython 7.x 上使用为 6.x 编译的库或者反之。解决方法永远是前往 CircuitPython 库捆绑包页面 下载与你的CircuitPython 固件版本完全匹配的库文件。引导加载程序 (Bootloader) 差异并非所有 Adafruit 板都使用 UF2 引导程序。早期的 Feather M0 Basic、Feather Adalogger 等使用的是传统的 Arduino 兼容引导程序不会显示BOOT驱动器。对于这些板子你需要使用bossac命令行工具来刷新固件过程类似于给 Arduino 刷机。Cura 3D 打印软件的干扰一个非常隐蔽的问题。Cura 软件会向所有空闲的串口广播 3D 打印 GCODE 命令如M105查询温度来寻找打印机。如果你的 CircuitPython 板子恰好连接在一个被 Cura 探测的串口上这些无意义的数据可能会冲掉串行控制台的输出甚至导致程序崩溃。解决方法是在 Cura 的设置中禁用“USB 打印”功能或者直接卸载 Cura。3. 核心故障排除工具与操作详解掌握了问题分类我们来看具体的“手术刀”——几个核心的故障排除工具和操作模式。3.1 安全模式系统级的“安全伞”安全模式是 CircuitPython 提供的一个救命通道。在此模式下系统不运行用户代码跳过boot.py和code.py并禁用自动重载。这让你有机会修复一个因为错误代码而导致系统无法交互比如CIRCUITPY被设为只读或关闭的板子。进入方法因版本而异CircuitPython 7.x 及以后板子上电或复位后有1 秒钟的窗口期。此时状态 LED 会快速闪烁黄色。在此窗口期内按下RESET键对于 ESP32-S2/S3是按BOOT键即可进入安全模式。可以理解为“慢速双击”间隔约1秒。CircuitPython 6.x窗口期为0.7 秒期间状态 LED 常亮黄色。同样在此时间内按RESET。如何判断已进入安全模式视觉7.x 版本LED 会间歇性闪烁黄灯三次。6.x 版本LED 会缓慢脉冲黄色。串行控制台连接串行控制台如 Mu 编辑器你会看到明确的提示“Running in safe mode! Not running saved code.”在安全模式下你能做什么此时你可以安全地访问CIRCUITPY驱动器无论之前boot.py对它做了什么限制。你可以删除导致问题的code.py或boot.py文件。修复文件系统中的错误。完成修改后再次按下RESET或重新插拔 USB板子就会正常启动。3.2 UF2 引导加载程序固件更新的“快捷通道”对于大多数现代 Adafruit 板子UF2 是刷新固件最简单的方式。它的工作原理是板子进入引导加载模式后会将自己模拟成一个 USB 大容量存储设备即BOOT驱动器。你只需将.uf2格式的固件文件拖放到这个驱动器里引导加载程序会自动将其写入到板载闪存的正确位置然后重启。关键操作步骤让板子进入引导加载模式。对于大多数板子是快速双击RESET按钮。对于运行 MakeCode 的 Circuit Playground Express 是单击一次。电脑上会出现一个名为CPLAYBOOT、FEATHERBOOT等的驱动器。从 CircuitPython 官网 下载对应你板子的最新.uf2文件。将其拖入BOOT驱动器。驱动器会自动弹出在 macOS 上或刷新在 Windows 上板子重启后CIRCUITPY驱动器会重新出现。常见 UF2 问题复制文件时卡在 0%在 Windows 上西部数据WD的 USB 驱动工具可能导致此问题。卸载该工具即可。拖入 UF2 文件后无反应首先确认你下载的.uf2文件是针对你确切板型的。Feather M4 Express 和 Feather M0 Express 的文件不能混用。其次检查文件是否完整下载。3.3 串行控制台与板子的“对话窗口”串行控制台是除文件系统外与 CircuitPython 交互最重要的途径。它输出程序打印信息、错误回溯并提供了 REPL交互式解释器环境。使用 Mu 编辑器时控制台无显示Mu 的串行控制台面板可能默认很小。一个完整的错误信息可能需要 10 行以上才能显示。如果面板高度不足你只能看到空白或最后一行提示“Press any key to enter the REPL”。解决方法将鼠标悬停在控制台面板的上边缘拖动以增加其高度或者使用右侧的滚动条向上滚动查看之前被“顶掉”的错误信息。利用 REPL 进行高级修复通过串行控制台按任意键进入 REPL 后你可以执行 Python 命令。最强大的一个功能是擦除文件系统 import storage storage.erase_filesystem()这两行命令会彻底格式化CIRCUITPY驱动器将其恢复为出厂状态。这在文件系统严重损坏、安全模式也无法修复时是最终手段。注意这会删除所有数据4. 系统性问题与深度维护有些问题超越了单次操作需要一些系统性的设置和维护策略。4.1 管理 macOS 的隐藏文件macOS 的 Finder 会在外置驱动器上创建一系列隐藏文件如.DS_Store、._filename、.Spotlight-V100等对于闪存空间以 KB 计的 SAMD21 非 Express 板子如 Trinket M0, QT Py M0这些文件是巨大的空间浪费甚至可能引发问题。一劳永逸的解决方案适用于 CircuitPython 4.x在 REPL 中执行storage.erase_filesystem()后CircuitPython 会自动创建一些占位文件来阻止 macOS 生成部分隐藏文件。但这并非完全有效。手动禁用与清理在终端中执行以下命令请将/Volumes/CIRCUITPY替换为你的实际盘符路径# 禁用该卷的 Spotlight 索引 mdutil -i off /Volumes/CIRCUITPY # 进入该卷 cd /Volumes/CIRCUITPY # 删除常见的 macOS 隐藏文件和目录 rm -rf .{,_.}{fseventsd,Spotlight-V*,Trashes} # 创建阻止文件 mkdir .fseventsd touch .fseventsd/no_log .metadata_never_index .Trashes # 返回原目录 cd -安全的文件拷贝方式即使做了以上设置从网上下载的文件如 Adafruit 的库通过 Finder 拖拽拷贝时macOS 仍可能创建扩展属性文件。最安全的方式是使用终端的cp命令并加上-X参数它不会拷贝这些扩展属性。# 拷贝单个文件 cp -X ~/Downloads/adafruit_bus_device.mpy /Volumes/CIRCUITPY/lib/ # 递归拷贝整个目录 cp -rX ~/my_project /Volumes/CIRCUITPY/4.2 释放 SAMD21 非 Express 板子的宝贵空间这些板子如 Trinket M0, GEMMA M0的闪存非常小通常 ~192KB除去固件和文件系统开销用户空间可能只有几十 KB。空间节省技巧删除无用文件检查lib文件夹只保留项目必需的库。可以删除自带的adafruit_wsgi等网络库如果你不用的话。甚至可以删除boot_out.txt但建议保留用于查看版本。使用 Tab 缩进Python 通常用 4 个空格缩进。但在空间紧张时改用单个Tab 字符进行缩进可以节省大量空间。例如一个嵌套 3 层的循环用 Tab 比用 4 个空格节省 9 个字节每行。对于大量代码这很可观。代码精简合并重复代码为函数使用更简洁的写法。4.3 Windows 设备管理混乱的清理如果你在 Windows 上频繁插拔不同的开发板系统可能会积累大量无效的旧设备驱动和 COM 端口记录导致新设备分配不到端口或识别异常。使用设备清理工具下载 Uwe Sieber 的 USB Device Cleanup Tool 。拔掉所有你想清理的开发板和其他 USB 设备。以管理员身份运行该工具。它会列出所有当前未连接的 USB 设备历史记录。通常可以安全地全选所有列表中的设备然后点击“删除”。重新插入你的开发板Windows 会像第一次见到它一样重新安装驱动并分配一个干净的 COM 端口号。这个操作能有效解决“COM端口号无限增长”以及一些因驱动缓存错误导致的无法识别问题。5. 状态指示灯解读板子的“摩斯电码”板载的 RGB LED 或单色 LED 是 CircuitPython 与你沟通的重要窗口。不同颜色和闪烁模式代表了不同的系统状态。CircuitPython 7.0.0 及之后版本简化模式旨在省电启动时快速闪烁黄色数次持续约1秒。在此阶段按 RESET 可进入安全模式。对于蓝牙板之后会有快速蓝色闪烁此时按 RESET 会清除蓝牙配对信息。空闲时每5秒闪烁一次1次绿色用户代码已正常执行完毕。2次红色代码因未捕获的异常而崩溃。需查看串行控制台获取错误详情。3次黄色处于安全模式。REPL 活动时LED 常亮白色仅限 NeoPixel/DotStar RGB LED。CircuitPython 6.3.0 及之前版本信息更丰富常亮绿色code.py正在运行。呼吸绿色code.py已运行完毕或不存在。常亮黄色启动时等待你按 RESET 进入安全模式。呼吸黄色处于安全模式因崩溃后重启。常亮白色REPL 正在运行。常亮蓝色boot.py正在运行。错误代码闪烁发生 Python 异常后LED 会先闪烁错误类型颜色再闪烁行号位数。错误类型颜色绿色缩进错误青色语法错误白色名称错误橙色OS错误紫色值错误黄色其他错误。行号表示白色闪烁千位蓝色百位黄色十位青色个位。例如第 32 行错误黄灯闪 3 次青灯闪 2 次。数字 0 用长暗间隔表示。理解这些“灯语”能让你在不连接电脑的情况下对板子的状态有个快速判断是硬件调试中不可或缺的一环。当看到红灯闪烁时你就知道该去接串口看错误信息了看到呼吸绿灯则意味着你的主程序已经跑完一遍了。