开始前适用开发板:ESP32-S3 Korvo · 开发框架:ESP-IDF
适用开发板:Korvo S3 · 工程
02.beginner.usb_hid_keyboard· targetesp32s3
连接:USB 接 PC,枚举为 HID 键盘
学习时长:约 20 分钟 · 难度:★★☆☆☆
学习目标
完成本节后,你将能够:
- 理解 USB HID(Human Interface Device)的基本概念
- 掌握 Report Descriptor 如何定义「设备是什么」
- 了解 8 字节键盘报告的结构
- 能够修改代码发送自定义按键序列
1. 这个例子在干嘛
把 ESP32-S3 变成一个 USB 键盘。插到电脑上,电脑会自动识别为一个标准键盘设备,然后程序自动发送按键(比如字母 A),你会在电脑的记事本中看到字符出现。
生活类比:就像一个自动打字的键盘——你插上 USB,它自己就开始"按键"了。
┌──────────┐ USB 线 ┌──────────┐
│ Korvo S3 │◄────────────►│ PC │
│ (Device) │ │ (Host) │
│ │ │ │
│ 发送 HID │ ────────► │ 记事本 │
│ 键盘报告 │ │ 出现字符 │
└──────────┘ └──────────┘
与 P4C5 区别:P4C5 有 MIPI 大屏显示状态 UI,Korvo 主要靠串口 log 观察。逻辑相同。P4 版见 P4C5 usb_hid_keyboard。
2. 编译烧录
cd Korvo_Firmware\02.beginner.usb_hid_keyboard
idf.py set-target esp32s3
idf.py build flash monitor
重要注意事项
- 使用 数据线(不是纯充电线)连接 Korvo USB 口与 PC
- 烧录前:把光标从重要文档/输入框移开!因为烧录后设备会立即开始"打字"
- 如果需要重新烧录但设备一直在打字:断电 → 按住 BOOT 键上电 → 进入下载模式
3. 运行现象
| 阶段 | PC 端 | 串口输出 |
|---|---|---|
| 上电 | 系统提示发现新 HID 设备 | USB 初始化日志 |
| 枚举完成 | 设备管理器出现"HID Keyboard" | USB Device Connected |
| 发送按键 | 记事本中出现字符 | Sending key report... |
4. USB HID 协议入门
4.1 什么是 HID?
HID(Human Interface Device)是 USB 协议中定义的一类设备,涵盖键盘、鼠标、手柄、触摸板等。特点是 免驱动——操作系统内置 HID 驱动,插上即用。
4.2 Report Descriptor(报告描述符)
这是整个 HID 的"身份证",告诉电脑"我是什么设备、我会发什么数据"。
Report Descriptor 告诉 Host:
├── 我是一个键盘 (Usage: Keyboard)
├── 我会发送 8 字节的数据
│ ├── 第 1 字节:修饰键(Ctrl/Shift/Alt/Win)
│ ├── 第 2 字节:保留(固定 0x00)
│ └── 第 3~8 字节:最多同时按下 6 个键
└── 键码范围:0x00 ~ 0xE7
4.3 键盘报告结构(8 字节)
字节: [0] [1] [2] [3] [4] [5] [6] [7]
含义: 修饰键 保留 键1 键2 键3 键4 键5 键6
修饰键 bit 定义:
bit 0 = Left Ctrl bit 4 = Right Ctrl
bit 1 = Left Shift bit 5 = Right Shift
bit 2 = Left Alt bit 6 = Right Alt
bit 3 = Left Win bit 7 = Right Win
示例:
[0x00, 0x00, 0x04, 0,0,0,0,0] → 按下 'a'
[0x02, 0x00, 0x04, 0,0,0,0,0] → 按下 'A' (Left Shift + a)
[0x00, 0x00, 0x00, 0,0,0,0,0] → 松开所有键(必须发!)
常见坑:发送按键后必须发送一个全零报告表示「松开」,否则电脑认为键一直按着。
5. 关键文件与代码解析
| 文件 | 作用 | 重点关注 |
|---|---|---|
main/app_main.c | USB 初始化 + 测试调用 | app_main() → hid_keyboard_test() |
main/usbx_demo.c | Report Descriptor 定义 + 报告发送 | 描述符数组、hid_keyboard_test 函数 |
核心代码流程
app_main()
→ CherryUSB 初始化(或 TinyUSB,取决于工程)
→ 注册 HID 设备(附带 Report Descriptor)
→ 等待 USB 枚举完成
→ hid_keyboard_test()
→ 填充 8 字节报告
→ usb_hid_send_report() // 发送按键
→ 延时
→ 发送全零报告 // 松开
6. 常见问题与排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| PC 无设备出现 | 线材问题;USB 口不支持 Device 模式 | 换数据线;确认 USB-OTG 口而非 UART 口 |
| 设备识别但无按键 | 测试函数未调用;端点 busy | 检查 hid_keyboard_test 是否被执行 |
| 不停重复打字 | 代码在 while 循环中重复发送 | 改为发送一次后 break 或加长延时 |
| 记事本出现乱码 | 键码映射错误 | 核对 HID Usage Table(0x04 = 'a',依次递增) |
| 烧录困难 | 设备一直在发按键干扰 | 断电 → BOOT 按键 → 上电进下载模式 |
7. 常用 HID 键码速查
| 键码 (hex) | 按键 | 键码 (hex) | 按键 |
|---|---|---|---|
| 0x04 | a/A | 0x1E | 1/! |
| 0x05 | b/B | 0x1F | 2/@ |
| ... | ... | ... | ... |
| 0x1D | z/Z | 0x27 | 0/) |
| 0x28 | Enter | 0x2C | Space |
| 0x29 | Escape | 0x2A | Backspace |
完整表请查阅 USB HID Usage Tables 文档(hid1_11.pdf)。
8. 动手改造建议
- 自动打字机:让设备循环发送 "Hello World\n",每次上电自动在记事本打出问候
- 快捷键器:组合修饰键 + 字母键,发送
Ctrl+C/Ctrl+V - 密码输入器:存储一段密码,按板上按钮(若有)触发一次输入
- 与鼠标 HID 对比:跑
02.beginner.usb_hid_mouse,观察报告结构差异
鼠标 HID 报告对比
键盘:[修饰键, 保留, 键1, 键2, 键3, 键4, 键5, 键6] (8字节)
鼠标:[按钮, X位移, Y位移, 滚轮] (4字节)
9. 知识延伸
- CherryUSB vs TinyUSB:两者都是 ESP32-S3 可用的 USB 协议栈,CherryUSB 是国产开源项目,TinyUSB 社区更大
- USB Device vs USB Host:本例 S3 做 Device(被控方);S3 也支持 Host 模式(控制 U 盘、键盘等)
- 复合设备:可以同时注册 HID 键盘 + HID 鼠标,一个 USB 口当两个设备用
- ESP32-S3 的 USB 优势:原生 USB-OTG 控制器,不需要外接 USB 芯片
10. 下一步
| 方向 | 推荐例程 |
|---|---|
| USB HID 鼠标 | 02.beginner.usb_hid_mouse |
| USB 通用教程 | USB 使用教程 |
| Wi-Fi 联网 | wifi_station |
酷世DIY · Kevincoooool