返回首页

USB HID 协议学习笔记

概述

USB HID(Human Interface Device)是 USB 设备类规范之一,最初设计用于键盘、鼠标等人机交互设备,现在广泛应用于各种自定义设备。

USB HID 基础

设备类定义

设备描述符结构

设备描述符
    ├── 配置描述符
    │   ├── 接口描述符 (HID)
    │   │   ├── HID 描述符
    │   │   ├── 端点描述符 (中断输入)
    │   │   └── 端点描述符 (中断输出,可选)
    │   └── ...
    └── ...

HID 描述符

标准接口描述符

/* HID 接口描述符 */
struct usb_if_descriptor {
    uint8_t bLength;            /* 9 */
    uint8_t bDescriptorType;    /* INTERFACE */
    uint8_t bInterfaceNumber;   /* 接口编号 */
    uint8_t bAlternateSetting;  /* 0 */
    uint8_t bNumEndpoints;      /* 1 (输入) 或 2 (输入+输出) */
    uint8_t bInterfaceClass;    /* 0x03 (HID) */
    uint8_t bInterfaceSubClass; /* 0x00 或 0x01 */
    uint8_t bInterfaceProtocol; /* 0x00 / 0x01 / 0x02 */
    uint8_t iInterface;         /* 字符串索引 */
};

HID 类描述符

/* HID 类描述符 */
struct usb_hid_descriptor {
    uint8_t bLength;            /* 9 */
    uint8_t bDescriptorType;    /* 0x21 (HID) */
    uint16_t bcdHID;           /* HID 版本:1.11 = 0x0111 */
    uint8_t bCountryCode;       /* 国家代码:0 = 不支持 */
    uint8_t bNumDescriptors;    /* 描述符数量:通常 1 */
    uint8_t bReportDescriptorType;  /* 0x22 (报告) */
    uint16_t wReportDescriptorLength; /* 报告描述符长度 */
};

报告描述符

报告描述符结构

HID 报告描述符定义设备发送/接收的数据格式。

/* 简单键盘报告描述符示例 */
const uint8_t hid_report_descriptor[] = {
    /* Usage Page (Generic Desktop) */
    HID_GI_USAGE_PAGE, HID_USAGE_GEN_DESKTOP,
    
    /* Usage (Keyboard) */
    HID_LI_USAGE, HID_USAGE_GEN_DESKTOP_KEYBOARD,
    
    /* Collection (Application) */
    HID_MI_COLLECTION, HID_COLLECTION_APPLICATION,
    
        /* Usage Page (Keyboard/Keypad) */
        HID_GI_USAGE_PAGE, HID_USAGE_GEN_KEYBOARD,
        
        /* Usage Minimum (Keyboard Left Control) */
        HID_LI_USAGE_MIN(1), 0xE0,
        
        /* Usage Maximum (Keyboard Right GUI) */
        HID_LI_USAGE_MAX(1), 0xE7,
        
        /* Logical Minimum (0) */
        HID_GI_LOGICAL_MIN(1), 0x00,
        
        /* Logical Maximum (1) */
        HID_GI_LOGICAL_MAX(1), 0x01,
        
        /* Report Size (1) */
        HID_GI_REPORT_SIZE, 0x01,
        
        /* Report Count (8) */
        HID_GI_REPORT_COUNT, 0x08,
        
        /* Input (Data, Var, Abs) - 修饰键 */
        HID_MI_INPUT, 0x02,
        
        /* Report Size (8) */
        HID_GI_REPORT_SIZE, 0x08,
        
        /* Report Count (1) */
        HID_GI_REPORT_COUNT, 0x01,
        
        /* Input (Const, Var, Abs) - 填充字节 */
        HID_MI_INPUT, 0x03,
        
        /* Report Size (8) */
        HID_GI_REPORT_SIZE, 0x08,
        
        /* Report Count (6) */
        HID_GI_REPORT_COUNT, 0x06,
        
        /* Logical Maximum (101) */
        HID_GI_LOGICAL_MAX(1), 0x65,
        
        /* Usage Maximum (101) */
        HID_LI_USAGE_MAX(1), 0x65,
        
        /* Input (Data, Array) - 按键码 */
        HID_MI_INPUT, 0x00,
        
    /* End Collection */
    HID_MI_COLLECTION_END,
};

鼠标报告描述符

const uint8_t mouse_report_descriptor[] = {
    HID_GI_USAGE_PAGE, HID_USAGE_GEN_DESKTOP,
    HID_LI_USAGE, HID_USAGE_GEN_DESKTOP_MOUSE,
    HID_MI_COLLECTION, HID_COLLECTION_APPLICATION,
    
        HID_LI_USAGE, HID_USAGE_GEN_DESKTOP_POINTER,
        HID_MI_COLLECTION, HID_COLLECTION_PHYSICAL,
        
            HID_GI_USAGE_PAGE, HID_USAGE_GEN_BUTTON,
            HID_LI_USAGE_MIN(1), 0x01,
            HID_LI_USAGE_MAX(1), 0x03,
            HID_GI_LOGICAL_MIN(1), 0x00,
            HID_GI_LOGICAL_MAX(1), 0x01,
            HID_GI_REPORT_SIZE, 0x01,
            HID_GI_REPORT_COUNT, 0x03,
            HID_MI_INPUT, 0x02,  /* 按键 */
            
            HID_GI_REPORT_SIZE, 0x05,
            HID_GI_REPORT_COUNT, 0x01,
            HID_MI_INPUT, 0x03,  /* 填充 */
            
            HID_GI_USAGE_PAGE, HID_USAGE_GEN_DESKTOP,
            HID_LI_USAGE, HID_USAGE_GEN_DESKTOP_X,
            HID_LI_USAGE, HID_USAGE_GEN_DESKTOP_Y,
            HID_GI_LOGICAL_MIN(1), 0x81,  /* -127 */
            HID_GI_LOGICAL_MAX(1), 0x7F,  /* 127 */
            HID_GI_REPORT_SIZE, 0x08,
            HID_GI_REPORT_COUNT, 0x02,
            HID_MI_INPUT, 0x06,  /* X, Y 相对位置 */
            
        HID_MI_COLLECTION_END,
    HID_MI_COLLECTION_END,
};

报告格式

键盘报告格式

/* 标准键盘报告 */
struct hid_keyboard_report {
    uint8_t modifiers;     /* 修饰键位图 */
    uint8_t reserved;      /* 保留(填充) */
    uint8_t keycodes[6];   /* 最多6个按键码 */
};

/* 修饰键位图 */
#define HID_MOD_LCTRL   (1 << 0)
#define HID_MOD_LSHIFT  (1 << 1)
#define HID_MOD_LALT    (1 << 2)
#define HID_MOD_LGUI    (1 << 3)
#define HID_MOD_RCTRL   (1 << 4)
#define HID_MOD_RSHIFT  (1 << 5)
#define HID_MOD_RALT    (1 << 6)
#define HID_MOD_RGUI    (1 << 7)

/* 常用按键码 */
#define HID_KEY_A       0x04
#define HID_KEY_B       0x05
#define HID_KEY_C       0x06
#define HID_KEY_1       0x1E
#define HID_KEY_2       0x1F
#define HID_KEY_ENTER   0x28
#define HID_KEY_SPACE   0x2C
#define HID_KEY_LEFT    0x50
#define HID_KEY_RIGHT   0x4F
#define HID_KEY_UP      0x52
#define HID_KEY_DOWN    0x51

鼠标报告格式

struct hid_mouse_report {
    uint8_t buttons;       /* 按键位图 (bit0=左, bit1=右, bit2=中) */
    int8_t x;              /* X 相对位移 (-127 ~ 127) */
    int8_t y;              /* Y 相对位移 (-127 ~ 127) */
};

HID 描述符项

全局项(Global Items)

项目标签说明
Usage Page0x04用途页面
Logical Minimum0x14逻辑最小值
Logical Maximum0x24逻辑最大值
Physical Minimum0x34物理最小值
Physical Maximum0x44物理最大值
Report Size0x74报告字段位数
Report Count0x94报告字段数量
Report ID0x84报告标识

局部项(Local Items)

项目标签说明
Usage0x08用途
Usage Minimum0x18用途最小值
Usage Maximum0x28用途最大值

主项(Main Items)

项目标签说明
Input0x80输入报告
Output0x90输出报告
Feature0xB0特性报告
Collection0xA0集合开始
End Collection0xC0集合结束

数据传输

中断传输

HID 设备使用中断传输:

主机 ←── IN 端点 ── 设备
主机 ── OUT 端点 ──→ 设备

特点:

数据包格式

[Report ID (可选)] [报告数据]

常见 HID 设备

启动设备

自定义 HID

调试工具

Linux

# 列出 HID 设备
ls /dev/hidraw*

# 查看设备信息
cat /sys/class/hidraw/hidraw0/device/uevent

# 读取 HID 报告
hexdump -C /dev/hidraw0

Windows

最佳实践

  1. 报告描述符设计:简洁明了,避免不必要的复杂性
  2. 报告大小:保持合理大小,64字节是常见上限
  3. 轮询间隔:根据应用需求选择(键盘10ms,鼠标1ms)
  4. 错误处理:处理传输失败和设备断开

参考链接


*学习笔记创建时间: 2026-03-19*