USB HID 模拟鼠标操作
1. 什么是 USB HID ?
USB HID 是一种通用标准,用于连接 USB 设备和计算机。它允许计算机和 USB 设备之间进行通信,并提供了一种标准的接口,用于处理输入和输出。USB HID 设备可以包括键盘、鼠标、游戏控制器、传感器等。 它与CDC 的主要区别在于,CDC 是用于串行通信的,而 HID 是用于输入和输出的。
2. USB HID 测试的引脚定义
没有对应的特殊要求 3. stm32cubeMX中USB HID的配置


- 打开STM32CubeMX,选择你的STM32芯片型号,并创建一个新的项目。
- 在“Pinout & Configuration”选项卡中,找到“Connectivity”部分,点击“USB”选项。
- 在“Configuration”选项卡中,找到“Device(FS)”选项,并勾选“Device”选项。
- 在 "Middlewares and software packages" 选项卡中,找到 "USB Device" 选项,并点击.
- 在 "Class For FS IP" 下拉菜单中选择 "Human Interface Device(HID)"。 选项。
- 下面的选项部分还要特别注意。

- 其中自供电模式是
- 如果选择 Enabled,那么USB设备必须自供电.
- 如果选择 Disabled,那么USB设备不能自供电, 需要通过USB主机供电, 对于像键盘鼠标这种设备,就需要设置成 Disabled.
- 需要注意的是: USB接口,需要配置时钟为48MHZ.

4. 分析USB HID设备代码
一般USB的设备描述符包含三种: USBD_HID_CfgFSDesc, USBD_HID_CfgHSDesc, USBD_HID_OtherSpeedCfgDesc, 分别对应的全速\高速\其它速度的描述符.这三种描述符相差不大,所有的代码都是相同的,只是最后一行的速度不同.
c
__ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END =
{
0x09, /* bLength: Configuration Descriptor size */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
USB_HID_CONFIG_DESC_SIZ,
/* wTotalLength: Bytes returned */
0x00,
0x01, /*bNumInterfaces: 接口数量(1)*/
0x01, /*bConfigurationValue: 配置编号(1)*/
0x00, /*iConfiguration: 配置字符串索引(0=无)*/
0xE0, /*bmAttributes: 设备属性(0xe0=自供电、远程唤醒) */
0x32, /*MaxPower 100 mA: 电源消耗(100mA)*/
/************** Descriptor of Joystick Mouse interface ****************/
0x09, /*bLength: 接口描述符大小(9字节)*/
USB_DESC_TYPE_INTERFACE, /*bDescriptorType: 描述符类型(接口=0x04)*/
0x00, /*bInterfaceNumber: 接口编号(0)*/
0x00, /*bAlternateSetting: 备用设置编号(0)*/
0x01, /*bNumEndpoints: 此接口使用的端点数量(1个)*/
0x03, /*bInterfaceClass: 接口类(HID=0x03)*/
0x01, /*bInterfaceSubClass: 接口子类(启动协议=1)*/
0x02, /*nInterfaceProtocol: 接口协议(鼠标=2)*/
0, /*iInterface: 接口字符串描述符索引(0=无)*/
/******************** Descriptor of Joystick Mouse HID ********************/
0x09, /*bLength: HID描述符大小(9字节)*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID类型(0x21)*/
0x11, /*bcdHID: HID类规范版本号(1.11)*/
0x01,
0x00, /*bCountryCode: 国家代码(0=不支持本地化)*/
0x01, /*bNumDescriptors: 后续描述符数量(1个)*/
0x22, /*bDescriptorType: 报告描述符类型(0x22)*/
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: 报告描述符长度*/
0x00,
/******************** Descriptor of Mouse endpoint ********************/
0x07, /*bLength: 端点描述符大小(7字节)*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType: 端点类型(0x05)*/
HID_EPIN_ADDR, /*bEndpointAddress: 端点地址(IN方向)*/
0x03, /*bmAttributes: 端点属性(中断传输)*/
HID_EPIN_SIZE, /*wMaxPacketSize: 最大包大小*/
0x00,
HID_FS_BINTERVAL, /*bInterval: 轮询间隔*/
/* 34 */
};您观察得非常准确!这段配置描述符确实包含三个关键部分,这三部分共同定义了一个USB HID鼠标设备的核心特性。让我逐一详细解析:
一、整体结构解析
这是一个USB配置描述符,它定义了设备的一种工作配置。在您的代码中,它包含:
配置描述符头 (9字节) + 接口描述符 (9字节) + HID描述符 (9字节) + 端点描述符 (7字节)总共34字节,与代码最后的注释/* 34 */对应。
二、各部分详细解析
1. 接口描述符 (Interface Descriptor)
c
/************** Descriptor of Joystick Mouse interface ****************/
0x09, /*bLength: 接口描述符大小(9字节)*/
USB_DESC_TYPE_INTERFACE, /*bDescriptorType: 描述符类型(接口=0x04)*/
0x00, /*bInterfaceNumber: 接口编号(0)*/
0x00, /*bAlternateSetting: 备用设置编号(0)*/
0x01, /*bNumEndpoints: 此接口使用的端点数量(1个)*/
0x03, /*bInterfaceClass: 接口类(HID=0x03)*/
0x01, /*bInterfaceSubClass: 接口子类(启动协议=1)*/
0x02, /*nInterfaceProtocol: 接口协议(鼠标=2)*/
0, /*iInterface: 接口字符串描述符索引(0=无)*/作用:告诉主机"我有一个接口,它是HID鼠标"
- bInterfaceNumber: 0 - 这是设备的第一个接口
- bInterfaceClass: 0x03 - 这是 HID类设备
- nInterfaceProtocol: 0x02 - 具体是鼠标 (1=键盘,2=鼠标)
2. HID描述符 ( HID Descriptor)
c
/******************** Descriptor of Joystick Mouse HID ********************/
0x09, /*bLength: HID描述符大小(9字节)*/
HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID类型(0x21)*/
0x11, /*bcdHID: HID类规范版本号(1.11)*/
0x01,
0x00, /*bCountryCode: 国家代码(0=不支持本地化)*/
0x01, /*bNumDescriptors: 后续描述符数量(1个)*/
0x22, /*bDescriptorType: 报告描述符类型(0x22)*/
HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: 报告描述符长度*/
0x00,作用:提供HID设备的详细信息
- bcdHID: 0x0111 - 符合HID规范1.11版本
- bCountryCode: 0x00 - 美国英语布局
- 关键信息:
0x22表示后面有一个报告描述符,长度为HID_MOUSE_REPORT_DESC_SIZE- 报告描述符定义了鼠标的数据格式(X/Y移动、按钮状态等)
3. 端点描述符 (Endpoint Descriptor)
c
/******************** Descriptor of Mouse endpoint ********************/
0x07, /*bLength: 端点描述符大小(7字节)*/
USB_DESC_TYPE_ENDPOINT, /*bDescriptorType: 端点类型(0x05)*/
HID_EPIN_ADDR, /*bEndpointAddress: 端点地址(IN方向)*/
0x03, /*bmAttributes: 端点属性(中断传输)*/
HID_EPIN_SIZE, /*wMaxPacketSize: 最大包大小*/
0x00,
HID_FS_BINTERVAL, /*bInterval: 轮询间隔*/作用:定义数据传输的具体通道
- HID_EPIN_ADDR - 端点地址(如0x81,表示端点1,IN方向)
- bmAttributes: 0x03 - 使用中断传输模式(最适合HID设备)
- HID_EPIN_SIZE - 每次传输的最大数据量(通常4字节)
- HID_FS_BINTERVAL - 轮询间隔(您在之前配置的0x0A=10ms)
三、从USB协议角度理解这三部分
想象一下USB通信就像建立一个公司组织架构:
接口描述符 = 部门定义
- 定义了这是一个"鼠标部门"(HID鼠标接口)
- 确定了部门编号(0号部门)
- 指定了部门类型(HID类,鼠标协议)
HID描述符 = 部门工作规范
- 定义了部门的操作手册(HID规范1.11版)
- 说明了部门需要填写的"报表格式"(报告描述符定义了鼠标数据格式)
- 指定了工作语言(英语,代码页0)
端点描述符 = 数据传输通道
- 定义了一个专用的"汇报通道"(端点)
- 确定了汇报频率(每10ms汇报一次)
- 限定了每次汇报的数据量(最大4字节)
- 指定了汇报方向(设备→主机,IN方向)
四、这三部分如何协同工作?
- 设备插入时:主机读取整个配置描述符
- 识别设备类型:看到接口描述符,知道是HID鼠标
- 加载驱动:根据HID描述符,加载相应的HID驱动程序
- 建立通信:根据端点描述符,建立中断传输通道
- 数据传输:设备每10ms通过指定的端点发送鼠标数据
五、实际工作流程示例
c
// 当鼠标移动时:
1. 固件准备好鼠标数据(例如:按钮状态,X/Y位移)
2. 通过端点1(HID_EPIN_ADDR)发送数据
3. 主机每10ms检查一次这个端点
4. 收到数据后,操作系统移动光标六. 总结
有了上面的描述,我们就大体知道了这个HID鼠标设备具体工作流程了. 但是还有一个问题: 如何定义鼠标数据格式? 这就需要另一个描述符: 鼠标报告描述符, 这个描述符定义了鼠标数据的具体格式, 包括按钮状态、X/Y位移等信息.
5. 分析鼠标报告描述符
c
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
//------ 定义设备为鼠标 -------
0x05, 0x01, // Usage Page (Generic Desktop) - 用途页:通用桌面
0x09, 0x02, // Usage (Mouse) - 用途:鼠标
0xA1, 0x01, // Collection (Application) - 开始应用集合
0x09, 0x01, // Usage (Pointer) - 用途:指针设备
// ############## 结束物理集合 ##############
0xA1, 0x00, // Collection (Physical) - 开始物理集合
//------ 定义3个按钮 -------
0x05, 0x09, // Usage Page (Button) - 用途页:按钮
0x19, 0x01, // Usage Minimum (1) - 最小用途:按钮1
0x29, 0x03, // Usage Maximum (3) - 最大用途:按钮3
0x15, 0x00, // Logical Minimum (0) - 逻辑最小值:0
0x25, 0x01, // Logical Maximum (1) - 逻辑最大值:1
// ===== 定义3个按钮 =====
0x95, 0x03, // Report Count (3) - 报告数量:3个
0x75, 0x01, // Report Size (1) - 报告大小:每个1位
0x81, 0x02, // Input (Data,Var,Abs) - 输入:数据,变量,绝对值
// ==== 定义了5位的常量填充位,凑齐1字节 =====
0x95, 0x01, // Report Count (1) - 报告数量:1个
0x75, 0x05, // Report Size (5) - 报告大小:5位
0x81, 0x01, // Input (Cnst,Arr,Abs) - 输入:常量,数组,绝对值
// ------ 定义X/Y位移 -------
0x05, 0x01, // Usage Page (Generic Desktop) - 用途页:通用桌面
0x09, 0x30, // Usage (X) - 用途:X轴
0x09, 0x31, // Usage (Y) - 用途:Y轴
0x09, 0x38, // Usage (Wheel) - 用途:滚轮
0x15, 0x81, // Logical Minimum (-127) - 逻辑最小值:-127
0x25, 0x7F, // Logical Maximum (127) - 逻辑最大值:+127
0x75, 0x08, // Report Size (8) - 报告大小:8位
0x95, 0x03, // Report Count (3) - 报告数量:3个
0x81, 0x06, // Input (Data,Var,Rel) - 输入:数据,变量,相对值
// ############## 结束物理集合 ##############
0xC0, // End Collection - 结束物理集合
// -------- 额外的功能定义 --------
0x09, 0x3c, // Usage (Motion Wakeup) - 用途:运动唤醒
0x05, 0xff, // Usage Page (Vendor Defined) - 用途页:厂商定义
0x09, 0x01, // Usage (Vendor 1) - 用途:厂商1
0x15, 0x00, // Logical Minimum (0) - 逻辑最小值:0
0x25, 0x01, // Logical Maximum (1) - 逻辑最大值:1
0x75, 0x01, // Report Size (1) - 报告大小:1位
0x95, 0x02, // Report Count (2) - 报告数量:2个
0xb1, 0x22, // Feature (Data,Var,Abs,NoPref) - 特征:数据,变量,绝对值
0x75, 0x06, // Report Size (6) - 报告大小:6位
0x95, 0x01, // Report Count (1) - 报告数量:1个
0xb1, 0x01, // Feature (Cnst,Arr,Abs) - 特征:常量,数组,绝对值
// ############## 结束物理集合 ##############
0xC0, // End Collection
};