资讯详情

MicroPython pyb.USB_HID 类全解析:在 STM32 上模拟 USB 鼠标与键盘

📅 2026/9/20 18:38:43 | 华诺云谱 👁 阅读
MicroPython pyb.USB_HID 类全解析:在 STM32 上模拟 USB 鼠标与键盘
嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载本篇技术指南以 MicroPython 官方文档 docs/library/pyb.USB_HID.rst 为主体系统讲解pyb.USB_HID类的使用方法如何通过pyb.usb_mode()使能 HID 接口、如何用send()与recv()收发 HID 报告并深入 STM32 移植层源码ports/stm32/usb.c、ports/stm32/usbd_hid_interface.c剖析其底层实现。读完本文你将能够独立编写板卡伪装成鼠标/键盘的实战程序理解 HID 报告描述符、报文格式与超时机制并能基于仓库内的预置常量pyb.hid_mouse、pyb.hid_keyboard或自定义报告描述符完成任意 HID 设备的模拟。一、pyb.USB_HID 是什么USB_HID类是 MicroPython pyboardSTM32 移植版提供的 USB Human Interface Device人机接口设备HID类。它允许创建一个表示板卡 USB HID 接口的对象用于将开发板模拟为鼠标、键盘等标准外设从而向连接的主机如 PC发送输入事件或接收主机下发的报告。import pyb hid pyb.USB_HID() # 创建 USB_HID 对象该类的核心特征可以概括为两点它是接口而非实体按 ports/stm32/usb.c 中的设计哲学注释USB 本身不是一个实体真正可访问的是各个接口VCP、MSC、HID。pyb.USB_HID()只是取回该接口对应的对象。使用前必须先用pyb.usb_mode()打开 HID 接口在 pyb.USB_HID.rst 中明确说明Before you can use this class, you need to usepyb.usb_mode()to set the USB mode to include the HID interface。在 usb.c 的make_new中甚至留有一行TODO raise exception if USB is not configured for HID注释意味着当前版本在未启用 HID 时创建对象并不会主动报错但收发操作将无法正常工作。从源码看pyb_usb_hid_obj是一个单例对象其结构仅包含对象基类与指向usb_device_t的指针typedef struct _pyb_usb_hid_obj_t { mp_obj_base_t base; usb_device_t *usb_dev; } pyb_usb_hid_obj_t;构造器pyb_usb_hid_make_new不接受任何参数mp_arg_check_num(n_args, n_kw, 0, 0, false)直接返回该单例。二、前置条件用 pyb.usb_mode() 使能 HID 接口在使用USB_HID之前必须先通过pyb.usb_mode()将板卡 USB 模式配置为包含 HID 的复合模式。该函数的完整签名与说明见 docs/library/pyb.rstpyb.usb_mode(modestr, port-1, vid0xf055, pid-1, msc(), hidpyb.hid_mouse, high_speedFalse)2.1 modestr 可选模式modestr含义None禁用 USBVCP仅 VCP虚拟串口接口MSC仅 MSC大容量存储设备接口VCPMSCVCP 与 MSCVCPHIDVCP 与 HID人机接口设备VCPMSCHIDVCP、MSC 与 HID仅 PYBD 系列板卡可用为向后兼容CDC等价于VCP同理CDCMSC、CDCHID。该兼容表在 usb.c 的pyb_usb_mode_table中有完整实现其中还包含MICROPY_HW_USB_CDC_NUM 2/3时支持的多 VCP 组合模式如2xVCP、3xVCPMSCHID等取决于具体板卡配置。2.2 其它参数port整数0, 1, ...选择板卡的多 USB 端口中的哪一个-1表示使用默认或自动选择的端口。vid / pid自定义 VID厂商 ID与 PID产品 IDpid-1时会根据modestr自动选择内置的 PID源码中对应MICROPY_HW_USB_PID_*系列宏如MICROPY_HW_USB_PID_CDC_HID。msc仅 MSC 模式有效指定要暴露的 SCSI LUN 列表如msc(pyb.Flash(), pyb.SDCard())。hid仅 HID 模式有效指定 HID 细节为一个五元组(subclass, protocol, max packet length, polling interval, report descriptor)。默认值为适合 USB 鼠标的参数仓库还预置了适合键盘的pyb.hid_keyboard常量。high_speed设为True时若硬件支持则启用 USB HS高速模式。2.3 预置 HID 常量pyb.hid_mouse 与 pyb.hid_keyboard在 usb.c 中这两个常量被定义为由 5 个元素组成的 ROM 元组// 鼠标(subclass, protocol, max_packet, polling_interval, report_desc) { MP_ROM_INT(1), // subclass: boot MP_ROM_INT(2), // protocol: mouse MP_ROM_INT(USBD_HID_MOUSE_MAX_PACKET), MP_ROM_INT(8), // polling interval: 8ms ... } // 键盘(subclass, protocol, max_packet, polling_interval, report_desc) { MP_ROM_INT(1), // subclass: boot MP_ROM_INT(1), // protocol: keyboard MP_ROM_INT(USBD_HID_KEYBOARD_MAX_PACKET), MP_ROM_INT(8), // polling interval: 8ms ... }两者均采用Boot subclass子类 1与8ms 轮询间隔区别仅在于协议号鼠标 2、键盘 1与各自的报告描述符、最大包长。hid_mouse与hid_keyboard在 modpyb.c 中被注册为pyb模块的属性。2.4 实战在 boot.py 中按需切换 USB 模式仓库自带示例 examples/SDdatalogger/boot.py 演示了在boot.py中根据按键状态动态选择 USB 模式的典型写法if switch_value: pyb.usb_mode(VCPMSC) pyb.main(cardreader.py) # 按下开关读卡器模式 else: pyb.usb_mode(VCPHID) pyb.main(datalogger.py) # 未按开关HID 模式配合 USB_HID 收发三、构造器USB_HID()创建一个新的 USB_HID 对象无任何参数。如前所述源码中它返回的是全局单例与创建的次数无关因此也可以安全地在多个地方重复调用。import pyb hid pyb.USB_HID() # 获得 HID 接口对象四、发送数据USB_HID.send(data)USB_HID.send(data)通过 USB HID 接口发送一个 HID 报告report。data可以是整数构成的 tuple / list或者bytearray字节缓冲。4.1 源码中的参数处理与限制在 usb.c 的pyb_usb_hid_send中参数按以下规则处理首先尝试将参数当作可读缓冲mp_get_buffer处理——即bytearray等直接可用若失败则按 tuple/list 解析mp_obj_get_array逐元素取整数值填入临时缓冲限制tuple/list 形式的报告长度超过 8 字节时会抛出ValueError: tuple/list too large for HID report; use bytearray instead——因为临时缓冲只有byte temp_buf[8]。要发送更长的报告如键盘的 8 字节报告以外的自定义报告应改用bytearray底层调用USBD_HID_SendReport完成发送成功返回发送字节数失败返回0。发送方法返回发送的字节数失败时为 0不会抛出异常。4.2 鼠标报告格式pyb.hid_mousepyb.hid_mouse的完整报告描述符定义在 usbd_cdc_msc_hid.c。综合描述符可以确定鼠标报告为4 字节字节含义0按键位bit0 左键、bit1 右键、bit2 中键高 5 位为填充1X 轴相对位移-127 ~ 1272Y 轴相对位移-127 ~ 1273滚轮相对位移-127 ~ 127对应描述符关键片段Report Count(3), Report Size(1)的 3 个按钮位、Report Size(5)的填充位以及Logical Minimum(-127) / Logical Maximum(127)、Report Size(8), Report Count(3)的 X/Y/Wheel 三个相对位移字节。import pyb hid pyb.USB_HID() # 移动鼠标向右 50、向下 30无按键 hid.send((0, 50, 30, 0)) # 单击左键按下再松开 hid.send((1, 0, 0, 0)) hid.send((0, 0, 0, 0)) # 滚动滚轮向上 hid.send((0, 0, 0, 1))4.3 键盘报告格式pyb.hid_keyboard键盘报告描述符见 usbd_cdc_msc_hid.c报告为标准的8 字节Boot Keyboard 格式字节含义0修饰键位bit0 Ctrl、bit1 Shift、bit2 Alt、bit3 GUIWin/Command……1保留字节恒为 02 ~ 76 个同时按下的按键键码0 ~ 101见描述符Logical Maximum(101)import pyb, time hid pyb.USB_HID() keyboard pyb.hid_keyboard # 先用键盘常量配置 USB 模式见下 # 按下并松开字母 a键码 0x04 hid.send((0, 0, 0x04, 0, 0, 0, 0, 0)) time.sleep_ms(50) hid.send((0, 0, 0, 0, 0, 0, 0, 0)) # 按下 CtrlC修饰键 bit0 键码 0x06 hid.send((0x01, 0, 0x06, 0, 0, 0, 0, 0)) time.sleep_ms(50) hid.send((0, 0, 0, 0, 0, 0, 0, 0))注意若要用键盘协议需在usb_mode中传入hidpyb.hid_keyboard否则板卡上报的是鼠标协议主机端会按鼠标报告解析这些字节。五、接收数据USB_HID.recv(data, *, timeout5000)USB_HID.recv(data, *, timeout5000)在总线上接收数据data的两种形式对应两种行为data 为整数表示要接收的字节数函数会分配一个新的字节缓冲返回内含实际接收到的字节data 为可变缓冲如bytearray接收到的字节被填入该缓冲函数返回实际读入的字节数。timeout是等待接收的超时时间单位为毫秒默认 5000ms。超时行为在源码中有明确定义usbd_hid_rx在超时后返回-MP_ETIMEDOUT而pyb_usb_hid_recv捕获到负返回值时不抛出异常而是将结果置为0usb.c——即超时时整数形式返回空字节串、缓冲形式返回 0。5.1 底层接收机制接收路径的核心实现在 usbd_hid_interface.cusbd_hid_init初始化report_in_len USBD_HID_REPORT_INVALID即(size_t)-1表示无待读报告并返回内部缓冲report_in_buf的地址供底层 USB 驱动存放首个传入报告usbd_hid_receive当中断端点收到主机下发的 IN 报告时仅记录长度report_in_len len不立即安排下一次接收直到用户读取当前报告usbd_hid_rx在超时时间timeout_ms内轮询等待report_in_len变为有效值一旦有数据拷贝min(len, report_in_len)字节到用户缓冲随后调用USBD_HID_ReceivePacket调度下一个报告的接收并返回实际拷贝字节数。这一设计意味着recv()一次调用对应读取一个完整 HID 报告报告长度由最大包长HID_DATA_FS_MAX_PACKET_SIZE决定见 usbd_hid_interface.h。5.2 接收示例接收方向通常用于板卡接收主机下发的场景例如键盘的 LED 输出报告、自定义 HID 设备的命令下发import pyb hid pyb.USB_HID() # 方式一按字节数接收返回新缓冲 data hid.recv(8, timeout1000) # 方式二接收进预分配缓冲返回字节数 buf bytearray(8) n hid.recv(buf, timeout1000) print(n, buf)5.3 与 select/poll 配合USB_HID对象实现了流式接口的ioctlusb.c支持MP_STREAM_POLL_RD可读有报告待接收与MP_STREAM_POLL_WR可写底层允许发送报告。因此可以配合select.select()在多个流对象间轮询避免阻塞import pyb, select hid pyb.USB_HID() vcp pyb.USB_VCP() while True: r, w, x select.select([hid, vcp], [], []) if hid in r: data hid.recv(8, timeout0) # 处理 HID 输入六、完整实战将板卡变成组合输入设备综合以上内容一个把 STM32 板卡同时伪装成鼠标与键盘通过VCPHID保持串口调试能力的完整程序如下import pyb, time # 1. 在 boot.py 中先行配置或在此调用推荐放在 boot.py pyb.usb_mode(VCPHID, hidpyb.hid_mouse) hid pyb.USB_HID() # 模拟鼠标移动轨迹 for i in range(10): hid.send((0, 5, 0, 0)) # 每次向右移动 5 time.sleep_ms(20) # 发送一次左键点击 hid.send((1, 0, 0, 0)) time.sleep_ms(20) hid.send((0, 0, 0, 0))若需在鼠标与键盘之间切换需要在切换后重新上电或重新执行pyb.usb_mode因为源码注释明确 USB 设备只在设备的通电生命周期内初始化一次only init USB once in the devices power-lifetime见 usb.c运行中反复切换模式不会生效。七、自定义 HID 设备进阶usb_mode的hid参数接受任意(subclass, protocol, max packet length, polling interval, report descriptor)五元组因此理论上可以模拟任意符合 HID 规范的设备例如游戏手柄、多媒体控制键等。报告描述符需按 USB HID 规范手工构造为字节序列import pyb # 自定义报告描述符此处仅为示意需按目标设备规范编写 custom_desc bytes([ 0x05, 0x01, # Usage Page (Generic Desktop) 0x09, 0x05, # Usage (Game Pad) 0xA1, 0x01, # Collection (Application) ... 0xC0, # End Collection ]) pyb.usb_mode(VCPHID, hid(1, 0, 8, 8, custom_desc)) # subclass/协议/最大包长/轮询间隔/描述符 hid pyb.USB_HID() hid.send(bytearray([...])) # 按自定义描述符定义的长度发送报告从 usb.c 可看到hid关键字参数默认值为pyb.hid_mouse即不传时按鼠标协议工作。八、注意事项与限制小结必须先行使能 HID 模式在调用pyb.USB_HID()收发之前确保boot.py中已调用pyb.usb_mode(VCPHID, ...)或VCPMSCHID后者仅 PYBD 板卡支持。USB 配置只在通电生命周期内生效一次usb_mode必须在boot.py阶段调用程序运行中途切换不会重新枚举设备。tuple/list 发送上限 8 字节更长的报告请使用bytearray否则抛ValueError。超时返回 0 / 空数据而非异常recv超时不抛异常编程时需自行判断返回值。旧的pyb.hid()函数已弃用docs/library/pyb.rst 中说明pyb.hid((buttons, x, y, z))已弃用应改用pyb.USB_HID.send()对应 C 侧实现pyb_hid_send_report也标注为 deprecatedusb.c。平台相关性pyb.USB_HID属 STM32 移植层专属接口modpyb.c 注册于pyb模块其它移植如 ESP32、rp2没有该模块跨平台项目需使用各自移植的 HID API如machine.USBDevice。九、进一步阅读类文档原文docs/library/pyb.USB_HID.rstpyb.usb_mode()/pyb.hid_mouse/pyb.hid_keyboard完整说明docs/library/pyb.rstPython 层绑定实现send/recv/ioctl/构造器ports/stm32/usb.c底层报告接收引擎ports/stm32/usbd_hid_interface.c 与 usbd_hid_interface.h鼠标/键盘报告描述符与 USB 描述符usbd_cdc_msc_hid.c真实使用示例examples/SDdatalogger/boot.py赞分享嵌入式语言运行时编程语言解释器编译器物联网系统编程【免费下载链接】micropythonMicroPython - a lean and efficient Python implementation for microcontrollers and constrained systems项目地址https://gitcode.com/gh_mirrors/mi/micropython点击查看免费下载相关推荐Flipper Zero终极指南USB模拟技术与键盘鼠标劫持实战Flipper Zero终极指南USB模拟技术与键盘鼠标劫持实战 Flipper Zero是一款功能强大的便携式多功能工具专为安全研究人员、硬件爱好者和渗透示例工程AutoHotkey键盘鼠标模拟keyboard_mouse模块API详解AutoHotkey键盘鼠标模拟keyboard_mouse模块API详解 你是否还在为重复的键盘鼠标操作感到厌烦想通过脚本自动化日常办公任务却不知从何入手RPAGUI 自动化桌面应用NanoKVM虚拟设备终极指南如何实现USB键盘鼠标的完美模拟NanoKVM虚拟设备终极指南如何实现USB键盘鼠标的完美模拟 NanoKVM是一款基于RISC V架构的开源IP KVM解决方案它提供了强大的 虚拟设备功物联网嵌入式音视频后端上一篇Learn Prompting学习路径从新手到专家的提示工程成长计划下一篇把文献阅读时间砍掉一半Awesome Claude Skills文献分析与总结工具完整上手指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。