别再只会点灯了!用STM32F103的USB HID功能,做个能骗过电脑的真键盘

张开发
2026/4/19 23:18:11 15 分钟阅读

分享文章

别再只会点灯了!用STM32F103的USB HID功能,做个能骗过电脑的真键盘
从零构建STM32虚拟键盘深入解析USB HID协议与实战开发记得第一次用STM32实现LED闪烁时的成就感吗现在是时候升级你的技能树了。今天我们要做的不是点亮几个发光二极管而是让一块不到20元的STM32F103C8T6开发板伪装成标准USB键盘——没错就是那种插上电脑就能直接打字的设备。这听起来像是黑客电影里的桥段但实际上只需要理解几个关键概念就能实现。1. 为什么需要了解USB HID开发十年前我接手了一个医疗设备项目需要在不改动原有系统的情况下模拟键盘输入。那时我才意识到掌握USB HID开发就像获得了一把万能钥匙——它能让你与任何计算机系统进行最底层的交互。不同于串口需要额外驱动HID设备有着天然的兼容性优势即插即用现代操作系统内置HID驱动无需额外安装低延迟USB 2.0全速模式下延迟可控制在1ms以内高可靠性硬件级的数据校验机制多功能性单设备可同时实现键盘、鼠标、游戏手柄等功能在物联网和嵌入式系统越来越普及的今天这种技术可以用于 • 安全领域的双因素认证令牌 • 工业控制面板的快速原型开发 • 特殊输入设备的定制如脚踏板、呼吸控制器 • 自动化测试中的输入模拟2. 硬件准备与环境搭建我的工作台上常年备着几片蓝色药丸STM32F103C8T6开发板的昵称它不仅价格亲民性能也足够应对大多数USB应用。以下是构建虚拟键盘所需的全部硬件组件型号/参数备注主控芯片STM32F103C8T6核心板需带USB接口开发环境STM32CubeIDE 1.10.1或Keil MDK调试工具ST-Link V2也可用J-Link外围电路10K电阻×4, 按键×4用于简单测试软件配置有个小技巧先安装STM32CubeMX时勾选Install all libraries这样可以避免后续缺少HAL库的麻烦。新建工程时关键设置// 时钟树配置示例 SYSCLK 72MHz USB Clock 48MHz (必须精确) APB1 Prescaler 2注意USB时钟必须严格保持48MHz误差不超过0.25%否则可能导致枚举失败。3. USB HID协议深度解析第一次接触USB描述符时我被那一堆十六进制数吓到了。直到后来明白它本质上就是设备的身份证能力说明书事情才变得简单。一个完整的HID设备需要定义四种核心描述符设备描述符声明供应商ID、产品ID等基本信息配置描述符定义电源管理和接口数量接口描述符指定使用的协议和端点HID描述符包含报告描述符的位置和大小报告描述符是最复杂的部分它用特殊的物品标签语法定义数据格式。比如下面这段定义了简单的键盘0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x06, // Usage (Keyboard) 0xA1, 0x01, // Collection (Application) 0x05, 0x07, // Usage Page (Key Codes) 0x19, 0xE0, // Usage Minimum (224) 0x29, 0xE7, // Usage Maximum (231) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data,Var,Abs) // ...更多按键定义实际开发中我推荐使用USB-IF官方的HID Descriptor Tool生成这部分代码它能可视化地构建描述符并自动生成代码。保存为.h文件后直接替换CubeMX工程中的默认描述符即可。4. CubeMX配置实战技巧在CubeMX的USB中间件配置中选择Custom HID模式后有几个关键参数经常被忽视bInterval设置为1表示1ms的轮询间隔实际效果取决于主机Packet size键盘通常需要8字节输入报告Endpoint addressIN端点建议用0x81OUT端点用0x01配置GPIO时有个实用技巧将按键GPIO设置为外部中断模式同时在NVIC中启用对应中断。这样可以在中断服务函数中立即触发USB报告发送实现零延迟检测void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { uint8_t key_report[8] {0}; if(GPIO_Pin KEY1_Pin) { key_report[2] 0x1E; // 键盘码对应1 USBD_CUSTOM_HID_SendReport(hUsbDeviceFS, key_report, 8); HAL_Delay(50); // 简单防抖 memset(key_report, 0, 8); USBD_CUSTOM_HID_SendReport(hUsbDeviceFS, key_report, 8); } }生成代码后记得在usbd_conf.h中调整这两个参数#define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 8 #define USBD_CUSTOMHID_INREPORT_BUF_SIZE 85. 调试与问题排查第一次尝试时我的设备在Windows设备管理器中显示为未知设备花了两天才找到问题所在。现在我把常见问题总结如下枚举失败检查清单[ ] USB DP引脚是否接1.5K上拉电阻[ ] 时钟配置是否正确HSI需校准PLL需锁定[ ] 描述符长度是否与声明一致[ ] 供应商/产品ID是否冲突数据发送成功但无输入的解决方案使用USBlyzer或Wireshark抓包确认数据格式符合HID规范检查报告描述符中的Usage Page是否正确测试发送标准键码如0x04代表a确保每次按键后发送释放报告全零数据包有个特别隐蔽的坑某些杀毒软件会拦截非常规HID设备。测试时可以先关闭实时防护或者申请微软WHQL认证对商业产品很重要。6. 进阶开发思路基础功能实现后可以尝试这些增强功能复合设备开发 在同一个USB接口上实现键盘鼠标自定义HID设备只需在CubeMX中添加多个HID接口为每个接口创建独立的报告描述符在应用层管理不同功能的数据流无线化改造 通过BLE模块如HC-05实现无线键盘# 伪代码示例 while True: key get_ble_data() if key A: send_hid_report(0x04)安全增强 • 实现AES加密的按键数据 • 添加指纹识别模块作为身份验证 • 使用USB隔离器防止电源反灌记得三年前我为银行开发过一个双因素认证令牌就是基于STM32的HID功能。当用户插入设备时它会自动输入动态验证码比手动抄写方便多了。关键在于理解USB HID不只是键盘鼠标它是嵌入式系统与PC交互的通用桥梁。

更多文章