ARTICLE DETAIL

资讯详情

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

树莓派 Pico USB 从硬件原理到 MicroPython 控制与排查

树莓派 Pico USB 从硬件原理到 MicroPython 控制与排查 树莓派 Pico 这块板子我前前后后折腾了不下十块从最开始的流水灯到后来的 USB 通信每次碰到问题十有八九都出在USB这个看似不起眼的功能上。很多人拿它当 Arduino 用点个灯、读个传感器几乎感觉不到 USB 的存在但只要你想让 Pico 跟电脑正经交换数据、想搞 HID 键盘鼠标、想弄明白拔插时那个盘符和串口到底是什么就会发现 Pico 的 USB 远不是能烧录、能输出 REPL这么简单。这篇东西不写流水账就沿着硬件原理、外设架构、MicroPython 控制和踩坑实录四条线把树莓派 Pico USB 从底层到应用串一遍看完你能直接上手控制它也能自己在电脑上排查 USB 不识别、驱动冲突这类老问题。1. 硬件原理RP2040 里的 USB 到底是块什么料1.1 不是所有 USB 都是 2.0 高速Pico 只有全速 12Mbps先泼一盆冷水树莓派 Pico 用的 RP2040 芯片USB 控制器是设备端Device Only不支持 Host 模式速度也只有USB 2.0 Full Speed即 12Mbps不是 480Mbps 的 High Speed。很多初学者一看到板子上有 USB 口就以为它能像电脑一样接 U 盘、接摄像头这是最大的误区。RP2040 这颗芯片在设计时定位就是低成本、低功耗的嵌入式控制器USB 主要解决跟电脑怎么通信的问题而不是怎么当电脑主机的问题。12Mbps 听上去不大但实际用来跑串口、跑 HID、传传感器数据完全够用一秒钟 1.5MB 左右的理论带宽发送几 KB 的日志根本感觉不到瓶颈。另外注意一点Pico 的 USB 是嵌入式 PHY也就是物理层收发器直接集成在芯片内部不需要外接 USB PHY 芯片。D 和 D- 两根线直接从芯片引脚出来经过板上的 ESD 保护和串联电阻接到 USB Type-C 座原版 Pico 是 Micro-USBPico W 和 Pico 2 才逐步换 Type-C。这就是为什么 Pico 的 BOM 这么干净——USB 这部分几乎不占额外成本。1.2 上电和供电链路VBUS、VSYS 与 VBUS_DETECT 的关系USB 接口对 Pico 来说不只是数据口它还是默认的主供电口。官方推荐用 5V USB 供电但要注意5V VBUS 不是直接进 RP2040 的而是先经过一片肖特基二极管防止反灌电流后接到 VSYS 网络。VSYS 电压范围是 1.8V~5.5V板上有一颗 LDO 把电压降到 3.3V 给芯片供电。在这个供电链路里有一个非常关键的引脚叫VBUS_DETECT对应的是GP24。它的作用就是检测 USB 的 VBUS 是否存在用来告诉你的程序我现在是插着 USB 线的。MicroPython 里可以直接读这个引脚的电平判断设备是否处于 USB 供电状态。后面讲软件控制时我会给你一个实际可用的检测代码段。这里有一个非常容易踩的坑VBUS_DETECT 的电压是 5V不是 3.3V。有些朋友手痒想拿 GPIO 去测电压或者直接把其他外设的 3.3V 输出接到这个脚上轻则检测失效重则烧坏引脚。正常用 MicroPython 读电平没问题因为是芯片内部的 ADC/GPIO 电路做了处理但如果你自己飞线一定要确认耐压。1.3 数据线上的细节D 上拉电阻决定了设备身份USB 总线上的 D 和 D- 并不是像串口一样简单地发高低电平。在 USB 2.0 Full Speed 下设备端的 D 线上要有一个 1.5kΩ 的上拉电阻主机检测到这个上拉才知道有一个全速设备连接了。Pico 板上已经集成好了这个电阻不需要你操心但理解这一点对排查问题很有帮助。很多USB 不识别的问题本质上就是主机在 D/D- 上没检测到符合规范的设备信号。比如线材里没有数据线芯只有电源线或者 D 上拉失效电脑就会报未知 USB 设备或设备描述符请求失败。我做过的实验里USB 线质量问题导致的识别失败比芯片故障导致的识别失败要常见得多后面排查章节我会专门列一个清单。2. 外设架构USB 在 RP2040 系统里扮演什么角色2.1 BOOTSEL 模式为什么按住按键再插线会变 U 盘RP2040 的 ROM 里固化了一个 bootloader芯片上电时如果检测到 BOOTSEL 引脚被拉低就会进入USB 启动模式。在这个模式下RP2040 会把自身模拟成一个 USB Mass Storage 设备一个 U 盘里面只有一个叫INDEX.HTM的文件和你的 Flash 内容把编译好的.uf2固件拖进去芯片就会把固件写入 Flash然后自动重启。这就是树莓派 Pico 不需要专用烧录器的核心原因。BOOTSEL 的检测逻辑是这样的按住板子上的 BOOTSEL 按键同时用 USB 线连接电脑松开按键电脑上就会弹出一个 U 盘。注意顺序很重要必须是先按住按键再上电如果你先插了线再按通常不会进入烧录模式除非用machine.bootloader()从软件层面触发重启。MicroPython 里有一行代码可以直接让 Pico 重新进入 BOOTSEL 模式import machine machine.bootloader()执行完这条指令RP2040 会软复位并进入 USB Mass Storage 模式。我经常用这个方法做固件升级和恢复变砖的板子比插拔 USB 线要优雅很多。2.2 USB 设备栈CDC、MSC 与 HID 的不同角色RP2040 的 USB 控制器支持多种设备类Device Class但同一时刻你能让多少种角色同时工作取决于固件怎么配置设备描述符。常见的三种角色CDCCommunications Device Class虚拟串口。你在电脑上看到的 COM 口Windows或 /dev/ttyACM0Linux就是 CDC 设备。MicroPython 的 REPL 就挂在这个 CDC 串口上。MSCMass Storage ClassU 盘。BOOTSEL 模式烧录时提供的就是 MSC 功能。HIDHuman Interface Device键盘、鼠标、游戏手柄。标准 MicroPython 固件默认不提供 HID 配置但 CircuitPython 或者自己用 C SDK 定制固件可以做到。这里面有一个容易混淆的点MicroPython 的 REPL 和虚拟串口不是同一个东西吗简单说REPL 是跑在虚拟串口上的一套交互式解释器USB 底层只负责把串口数据包传输到电脑。你打开串口终端连上那个 COM 口看到的就是 MicroPython 的交互界面它是通过 USB CDC 通道实现的。2.3 USB DPRAMRP2040 USB 控制器的数据中转站如果你要看 RP2040 的数据手册会发现 USB 控制器内部有一块专用的双端口 RAM叫DPRAM。主机通过 USB 总线发来的数据先被 USB 硬件解析然后写入 DPRAMCPU 再去 DPRAM 读取。反过来CPU 要发送的数据也是先放进 DPRAMUSB 外设硬件自动把数据打包成 USB 包按速率要求发出去。这种设计的好处是USB 通信不占用 CPU 的实时处理。你不需要像软件模拟串口那样在中断里一个字节一个字节地拼协议硬件已经把底层打包、校验、重传都处理好了。对于嵌入式开发这意味着你在跑复杂算法或者控制舵机的同时后台还能稳定地和 PC 通信。MicroPython 固件把 DPRAM 的缓冲区管理和端点Endpoint配置都封装起来了所以你直接用print()输出到 REPL 时感觉不到底层细节。但如果你以后想用 C SDK 写自定义 USB 设备比如同时做 CDC 和 HID 的复合设备就必须亲手配置端点描述符、缓冲区大小和中断回调那才是真正考验对 DPRAM 理解的时候。2.4 为什么说 USB 是 Pico 的生命线从外设架构上看USB 对 RP2040 来说不是一个可有可无的通信外设而是整套开发流程的基础设施。没有 USB你就没法烧录 UF2 固件、没法跑 REPL、没法做主机和设备之间的实时调试。它同时承担了四件事供电默认 5V 电源入口。烧录BOOTSEL 模式下的 MSC 拖拽烧录。调试MicroPython REPL、C SDK 的 pico_stdio 都能通过 USB CDC 输出日志和交互。数据通道与 PC 或手机OTG交换业务数据。理解这一点之后你再去看那些Pico 连不上电脑的求助帖就会发现大部分人都是卡在这四条线中的一条上。排查思路也由此展开先确认供电正常再检查有没有进 BOOTSEL然后看串口驱动和终端软件最后才去怀疑引脚和硬件焊接。3. 用 MicroPython 控制 USB从读 VBUS 到串口指令交互3.1 标准固件下 MicroPython 的 USB 能力边界树莓派 Pico 的官方 MicroPython 固件默认的 USB 配置是CDC MSC 复合设备。也就是说你插上 Pico 后电脑上会出现一个虚拟串口和一个名为RPI-RP2的 U 盘注意这个 U 盘只在烧录模式下出现正常运行时会有一个 FAT 文件系统但 MicroPython 固件默认不挂载成可访问的 U 盘给用户具体取决于固件版本。在这个标准固件里你不能直接用 MicroPython 的 API 去把 USB 设备类改成 HID也不能随意修改 USB 描述符。想改的话有两个路线用 CircuitPython 固件它内置了usb_hid、usb_cdc、usb_midi等库配置起来非常直观。用 C SDK 自定义构建 MicroPython 固件修改mpconfigboard.h里的配置项比如把 USB 描述符改成 CDCHID 复合设备然后重新编译整个固件。如果你只是想让 Pico 通过 USB 串口跟电脑交换数据用标准 MicroPython 就够了完全不需要自定义固件。3.2 检测 VBUS让程序知道 USB 是否连接先看一个最实用的功能读取 USB 供电状态。为什么要这个我在很多项目中遇到过一种需求——设备在电池供电和 USB 供电两种模式下功耗策略完全不同。电池模式要关掉部分外设USB 模式则可以把功能全开。Pico 上检测 VBUS 非常简单只需要读取 GP24 的电平from machine import Pin import time vbus Pin(24, Pin.IN) while True: if vbus.value() 1: print(USB connected, running full mode) # 在这里开启所有外设 else: print(Battery mode, power saving) # 在这里关闭大功率外设 time.sleep(1)这段代码在你插上 USB 线的时候会打印USB connected拔掉就打印Battery mode。注意 GP24 的电平逻辑是有 USB 供电时读到 1没有时读到 0。这是由板上硬件电路决定的不同板子可能有差异自己画板子时一定要看原理图确认。3.3 从 USB 虚拟串口接收指令用 sys.stdin 实现简单协议标准 MicroPython 固件中REPL 本身就跑在 USB CDC 串口上。但你不可能在 REPL 里人肉敲命令来跟设备交互更常规的方式是PC 端程序往 USB 串口发数据Pico 端跑一个循环去读取并解析。MicroPython 里读取 USB CDC 数据跟读取普通 UART 的标准输入是一样的道理直接操作sys.stdinimport sys import select from machine import Pin, PWM # 舵机初始化GPIO 1550Hz servo PWM(Pin(15)) servo.freq(50) def set_angle(angle): # 0度对应0.5ms脉宽180度对应2.5ms脉宽 duty 0.5 (angle / 180.0) * 2.0 duty_u16 int(duty / 20.0 * 65535) servo.duty_u16(duty_u16) print(fservo set to {angle} deg) print(USB command interface ready, waiting for angle...) while True: if select.select([sys.stdin], [], [], 0)[0]: line sys.stdin.readline().strip() if line: try: angle int(line) if 0 angle 180: set_angle(angle) else: print(angle out of range) except ValueError: print(invalid number)这段代码的思路是select 轮询标准输入USB CDC来了一行数据就读出来把字符串转成角度设置舵机 PWM。PC 端用串口助手发一个90回车舵机就转到 90 度打一条回显。这里我用的是 PWM 控制的舵机因为树莓派 pico 控制舵机这个话题热度一直很高。舵机的原理不复杂控制信号是一个周期 20ms50Hz的方波其中高电平时间决定了舵机转动的角度。标准舵机 0 度时高电平大约 0.5ms180 度时大约 2.5ms中间线性对应。换算成 RP2040 的 16 位 PWM 计数就是代码里 duty_u16 那段计算公式。3.4 实现 USB HID想要键盘鼠标该怎么做如果你搜过树莓派 Pico USB HID大概率会看到一堆拿 CircuitPython 做的 BadUSB 键盘或鼠标项目。这个方向用 Pico 做确实很合适因为 RP2040 的 USB 控制器原生支持 HID 设备类。标准 MicroPython 固件不带 HID 功能但 CircuitPython 改一行配置就能启用。下面的例子可以演示Pico 变成 USB 键盘按下按钮自动打字。安装 CircuitPython 固件后写一个code.pyimport usb_hid from adafruit_hid.keyboard import Keyboard from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS import board import digitalio import time keyboard Keyboard(usb_hid.devices) layout KeyboardLayoutUS(keyboard) button digitalio.DigitalInOut(board.GP15) button.direction digitalio.Direction.INPUT button.pull digitalio.Pull.UP while True: if not button.value: layout.write(Hello from Pico HID) time.sleep(1)按下接在 GP15 的按钮接地Pico 就会在电脑上输出一段文字。实际用起来确实很爽但也要注意这种功能如果被不当使用就是标准的 BadUSB 攻击场景我不建议在未经授权的设备上测试自己在实验板或者虚拟机里玩一玩就好。3.5 自定义固件与 USB 描述符进阶玩家的地盘如果你不想换 CircuitPython还想在 MicroPython 里同时用 REPL 和 HID那条路就是自定义固件。MicroPython 的 rp2 端口把所有 USB 配置放在了ports/rp2/mpconfigport.h和ports/rp2/boards/目录下的板级配置里。你可以参考官方文档把MICROPY_HW_USB_CDC、MICROPY_HW_USB_MSC这些宏改一改重新编译。但这个过程的坑比较多需要装编译器、配置工具链、改完还要重新烧录验证。我的建议是如果你只是想在 MicroPython 里用 HID先试 CircuitPython如果不愿意换再去碰自定义固件。因为后者花的时间精力可能够你用 C SDK 从零写一个完整的 USB 设备了。4. 实操过程从烧录到 USB 串口控制舵机完整复现4.1 环境准备与固件烧录要复制我上面的示例你需要这几样东西树莓派 Pico 板子一块Pico W 也可以USB 相关操作是一样的一根确认支持数据传输的 USB 线别用只能充电的线这是新手第一坑一个标准 SG90 舵机接在 GP15供电用 5V 和 GND注意舵机的地和 Pico 的地要共地烧录 MicroPython 固件的步骤按住 Pico 板子上的 BOOTSEL 按键不放。用 USB 线连接 Pico 和电脑等 2 秒松开按键。电脑上出现一个名为RPI-RP2的 U 盘。到树莓派官网下载.uf2格式的 MicroPython 固件注意选对芯片型号Pico 和 Pico 2 的固件不通用。把.uf2文件直接拖进RPI-RP2盘烧录完成后 Pico 会自动重启U 盘消失设备管理器中多出一个 USB 串口。如果你用的是 Thonny IDE它会在底部自动识别 Pico 的串口并进入 MicroPython 环境不需要额外配置驱动。Windows 系统上Pico 的虚拟串口走的是系统自带的 usbser.sys 驱动一般不需要手动安装插上就会认出USB Serial Device (COMx)。4.2 接线与主程序上传舵机接线如下舵机引脚接到 Pico信号线橙/黄GP15电源正极红5VVBUS 或 VSYS电源负极棕/黑GND把上面 3.3 节里那个 PWM 舵机程序存成main.py用 Thonny 保存到 Pico 的 Flash 里。保存成功后拔掉 USB 再插上程序会自动运行。这时候你用任意串口助手打开 Pico 的 COM 口波特率不管设多少没问题USB CDC 是虚拟串口不依赖波特率发送90舵机应该转 90 度发送180舵机转 180 度。第一次跑通这个流程时我最深刻的体会是MicroPython 让 USB 串口通信的复杂度降到了几乎为零你不用关心缓冲区大小不用处理串口波特率也不用理清 USB 描述符怎么配置就能在 20 分钟内实现上位机发指令、下位机执行动作的完整链路。4.3 为什么我在实际项目里还会加 USB 转 TTL 芯片这里多说一句关于USB 转串口芯片的事情。很多人在搜 Pico 相关问题时会看到 FT232R、CH340、CP2102 这些芯片的驱动。它们是干嘛的本质上就是把电脑的 USB 信号转换成 UART TTL 电平信号的外部转换芯片。Pico 的 USB 是直接做成虚拟串口CDC跟这些芯片不是一回事。但对某些项目你可能会需要电脑同时跟多个串口设备通信Pico 的 USB 口只够连一个。想在 Pico 上跑一个自定义 UART 协议把 USB 口留给调试用。遇到某些老系统对 USB CDC 兼容性不好用 CH340 这类转换芯片反而更稳。常见 USB 转 UART 芯片对比芯片系统自带驱动稳定性常见场景FT232R需要装驱动很好工业调试、老旧设备兼容CH340需要装驱动良好Arduino 兼容板、低成本开发CP2102需要装驱动很好物联网模块调试、开发板RP2040 内置 CDC系统自带良好Pico 调试、虚拟串口我个人的经验是调试时直接用 Pico 的 USB CDC生产交付时如果客户电脑环境复杂就在板子上多留一个 USB 转 TTL 芯片的仓位两边都稳。5. 常见问题与排查USB 不识别、驱动冲突、设备描述符失败5.1 未知 USB 设备设备描述符请求失败怎么办这个问题在 Pico 和 RP2040 相关的论坛里出现频率极高而且不止 Pico很多 DIY USB 设备都会遇到。典型的故障现象是插上 Pico电脑的设备管理器里出现一个带黄色感叹号的未知 USB 设备并提示设备描述符请求失败。按我实际排查的经验出现这个错误99% 的情况下不是 RP2040 芯片烧了而是下面三件事之一USB 线问题。很多手机附带的线只走电源不走数据换一根确定了能传数据的线问题立刻消失。这是概率最高的原因。供电不足。某些 USB Hub 或者老式电脑前置面板供电不稳Pico 在上电时无法完成 USB 枚举。换一个电脑背后的 USB 口或者用带外部供电的 Hub 测试。固件卡死在早期初始化。如果自己写的代码或者 flash 里的数据把 USB 相关引脚搞乱了也会出现枚举失败。解决办法就是按住 BOOTSEL 刷回官方固件。5.2 Windows 串口识别成了 FT232/CH340但打不开有些朋友会碰到这种情况插上 Pico设备管理器里出现的是USB Serial Port (COM3)看起来正常但用串口软件打开却报错或者只能打开一次就再也打不开。这里要分清楚如果你用的是 Pico 板载 USB 口驱动是 usbser.sys不应该出现 FT232 或者 CH340 的驱动。如果设备管理器里出现了这些名字说明你插的不是 Pico 的 USB 口而是板子上可能外接了一个 USB 转 TTL 模块或者你把 Pico DBG 口Pico 2 上的接到了电脑。还有一种情况串口被占用。Thonny 打开 REPL 后其他串口软件就打不开同一个 COM 口了。这是正常的不是硬件故障。用 Thonny 的时候串口助手必须先断开反过来也一样。5.3 BOOTSEL 进不去U 盘盘符一闪而过按住 BOOTSEL 再插线电脑有提示音但 U 盘盘符一闪而过或者根本没出现。遇到这个情况多半是Flash 里的内容导致 USB 枚举失败。解决办法拔掉 Pico 的 USB。按住 BOOTSEL 不放。插入 USB等 3 秒再松开。如果还是不行用短接线把 RP2040 的 RUNRESET引脚对地短接一下让芯片彻底复位再试。如果折腾到最后 U 盘还是不出来先用官方 C SDK 的picotool或者openocd走 SWD 接口擦除 Flash。没有 SWD 调试器的话也可以用另一块 Pico 当 SWD 烧录器去擦除这套Pico 救 Pico的方法我试过多次管用。5.4 MicroPython 运行了但 print 输出看不到程序能跑舵机能转但电脑上的 USB 串口看不到print()的输出。这是另一个高频问题原因通常是你在main.py里做了一堆耗时操作把 REPL 的 USB CDC 输出堵住了。USB CDC 是有缓冲区的如果你在循环里不断输出大量数据而电脑端没有及时读取缓冲区满了之后后续输出会被阻塞看起来就像程序卡死。解决办法减少不必要的print或者用select做非阻塞读取。在 PC 端打开串口并持续接收数据哪怕不需要也开着。如果只是要让程序启动时不干扰 REPL可以在main.py开头加一个延时比如time.sleep(1)给 USB 枚举留时间。5.5 快速排查速查表现象优先级排查方向大概率解决方案插上 Pico完全没有反应1. USB 线 2. 供电 3. BOOTSEL换数据线换 USB 口提示未知 USB 设备1. 线材 2. 供电 3. 固件拔掉所有 USB 设备重试刷官方固件出现 U 盘但拖不进固件1. 固件格式 2. Flash 损坏重新下载 .uf2用 SWD 擦除 Flash串口打不开1. 串口占用 2. 驱动冲突断开其他 IDE关闭占用程序print 不输出1. 缓冲区 2. 代码阻塞降低输出频率使用 select 非阻塞读取REPL 能用但舵机不动1. 供电 2. 共地 3. PWM 频率舵机外接 5V确认 GND 跟 Pico 共地最后再分享一个小技巧我前阵子做一个桌面小工具Pico 通过 USB 连电脑电脑端用 Python 的pyserial发指令控制多个舵机动作。调试时经常遇到一个问题程序跑得好好的突然串口断了然后再也打不开只能拔插 USB。后来我查清楚了是电脑睡眠唤醒后 USB CDC 枚举异常导致的不是 Pico 的锅。解决办法是在 Pico 端监听 VBUS 状态如果检测到 VBUS 从有到无就主动执行machine.reset()。拔掉重插时程序重新初始化 USB 设备Windows 重新枚举就正常了。现在这块板子在桌面上连续跑了一个多月再没出现过串口用着用着就消失的情况。所以说把硬件原理吃透一点很多看似玄学的问题其实都能在原理图上找到答案。
返回列表