1. USB HID 鼠标基础描述符实现

USB HID 鼠标基础描述符实现 学习卡片

任务说明

本案例实现一个基于STM32F103系列MCU的USB HID键盘设备。设备上电后完成USB枚举,被主机识别为标准键盘;按下开发板上的用户按键时,设备向主机发送一次按键事件(例如字母'A'的按下与释放),主机端可观察到字符输入。核心交付物为完整的USB设备初始化代码、HID报告描述符、按键扫描与上报逻辑。

硬件连接与依赖

  • MCU:STM32F103C8T6(Blue Pill开发板),外部8MHz晶振,系统时钟72MHz
  • USB:PA11(USB_DM)、PA12(USB_DP),板载1.5kΩ上拉电阻至PA12
  • 用户按键:PC13(低电平有效,板载按键)
  • 开发环境:STM32CubeIDE 1.13+,STM32CubeF1固件包
  • 中间件:USB Device库(使用CubeMX生成的PCD驱动)

实现方案

使用STM32CubeMX生成USB Device工程,选择Communication Device Class (CDC)模板后手动修改描述符与端点配置为HID键盘类。核心工作包括:

  1. 配置USB为Device模式,低速/全速选择全速(12Mbps)
  2. 编写HID键盘报告描述符(8字节:修饰键+保留+6个按键)
  3. 实现HID类请求回调(GetReport、SetReport等)
  4. 主循环轮询按键,检测到按下时通过USB发送按键事件

代码实现

以下为关键代码,完整工程由CubeMX生成,此处给出核心修改与新增部分。

// usbd_hid_keyboard.h —— HID键盘报告描述符
#define HID_KEYBOARD_REPORT_DESC_SIZE 63
static const uint8_t HID_KeyboardReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] = {
    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, Variable, Absolute)
    0x95, 0x01,       //   Report Count (1)
    0x75, 0x08,       //   Report Size (8)
    0x81, 0x01,       //   Input (Constant)
    0x95, 0x05,       //   Report Count (5)
    0x75, 0x01,       //   Report Size (1)
    0x05, 0x08,       //   Usage Page (LEDs)
    0x19, 0x01,       //   Usage Minimum (1)
    0x29, 0x05,       //   Usage Maximum (5)
    0x91, 0x02,       //   Output (Data, Variable, Absolute)
    0x95, 0x01,       //   Report Count (1)
    0x75, 0x03,       //   Report Size (3)
    0x91, 0x01,       //   Output (Constant)
    0x95, 0x06,       //   Report Count (6)
    0x75, 0x08,       //   Report Size (8)
    0x15, 0x00,       //   Logical Minimum (0)
    0x25, 0x65,       //   Logical Maximum (101)
    0x05, 0x07,       //   Usage Page (Key Codes)
    0x19, 0x00,       //   Usage Minimum (0)
    0x29, 0x65,       //   Usage Maximum (101)
    0x81, 0x00,       //   Input (Data, Array)
    0xC0              // End Collection
};

// usbd_hid_keyboard.c —— 按键发送函数
#include "usbd_hid_keyboard.h"

// 发送按键事件:按下并释放一个键
// keycode: HID键盘键码,如 'a'对应0x04,'A'对应0x04+左Shift修饰
void HID_KBD_SendKey(uint8_t keycode, uint8_t modifier) {
    uint8_t report[8] = {0};
    
    // 按下事件
    report[0] = modifier;  // 修饰键(如左Shift)
    report[2] = keycode;   // 第一个按键
    USBD_HID_SendReport(&hUsbDeviceFS, report, 8);
    
    // 释放事件(延迟约10ms后发送空报告)
    HAL_Delay(10);
    memset(report, 0, sizeof(report));
    USBD_HID_SendReport(&hUsbDeviceFS, report, 8);
}

// 主循环中调用示例(main.c中)
void HID_KBD_Process(void) {
    static uint8_t last_state = 1;  // PC13上拉,按下为0
    
    uint8_t current_state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
    if (current_state == 0 && last_state == 1) {
        // 检测到按下沿,发送字母 'A'(无Shift时为小写a)
        HID_KBD_SendKey(0x04, 0x00);  // 0x04 = 键盘a
    }
    last_state = current_state;
}

USB配置要点

在CubeMX中需完成以下配置:

  • USB_OTG_FS:激活为Device模式
  • 中间件选择USB Device,Class选择Communication Device Class(生成框架后手动改)
  • 修改usbd_conf.h中端点参数:HID使用端点1 IN,中断传输,最大包长64字节
  • 在usbd_hid.c中注册HID类回调,实现GetHIDDescriptor、GetReportDesc等函数

验证方法

枚举验证:将开发板通过USB连接PC,在设备管理器中应出现“USB输入设备”或“HID键盘设备”,且无黄色感叹号。Linux下执行lsusb可见设备,dmesg输出包含“input: USB HID v1.10 Keyboard”信息。

功能验证:打开任意文本编辑器,按下开发板PC13按键,应输入字符“a”。若需输出大写“A”,修改调用为HID_KBD_SendKey(0x04, 0x02)(0x02为左Shift修饰键)。

判定标准:

  1. 设备枚举成功,主机识别为键盘设备
  2. 每次按下按键,文本编辑器恰好输入一个字符
  3. 连续快速按键不丢失(间隔大于50ms时)

常见问题排查

  • 枚举失败:检查PA12上拉电阻是否连接,USB_DM/DP线序是否正确
  • 无字符输出:确认报告描述符长度与usbd_hid.c中定义一致(63字节)
  • 按键无响应:用万用表测量PC13按下时电平变化,确认GPIO配置为输入上拉
USB HID键盘设备枚举与数据流 STM32F103 USB Device 全速 HID键盘类 PC13 GPIO读取 USB D+/D- 端点1 IN 中断传输 8字节报告 USB主机(PC) HID驱动解析 文本编辑器接收 报告数据 枚举时序 1. 复位 → 地址0 2. 获取设备描述符 3. 设置地址 → 地址1 4. 获取配置描述符 5. 获取HID报告描述符 6. 设置配置 → 就绪 按键事件上报路径 ✓ 验证点:文本编辑器出现字符