跳转至

HID

BLE HID — 键盘 / 鼠标 — BLE HID over GATT、HID Report 协议

前置阅读:Hello Notify

学习目标

  • 理解 BLE HID 的工作原理——HID Service + Report Characteristic
  • 掌握 HID Report 格式——键盘 8 字节、鼠标 4 字节
  • 理解 BLE HID 的连接参数要求——短间隔、零延迟
  • 能够在 WS63 上实现一个 BLE 键盘或鼠标

规格与功能

WS63 做 BLE 键盘:GPIO 按键矩阵 → 解析为 HID 按键码 → BLE Notify 发送 Report → 手机/PC 收到按键输入。

基本概念

HID Service 结构

HID Service (UUID 0x1812)
├── Report Map Characteristic (UUID 0x2A4B)    — 描述按键布局(只读)
├── Report Characteristic (UUID 0x2A4D)         — 传输按键数据(NOTIFY + WRITE)
├── Boot Keyboard Input (UUID 0x2A22)          — BIOS 兼容模式(NOTIFY)
└── Boot Mouse Input (UUID 0x2A33)             — BIOS 兼容模式(NOTIFY)

HID Report 格式

键盘(8 字节):

Byte 0: Modifier (Ctrl/Shift/Alt/GUI 各占 1 bit)
Byte 1: Reserved (0x00)
Byte 2-7: 按键码(最多 6 键同时按下)

鼠标(4 字节):

Byte 0: Button (左/右/中)
Byte 1: X 位移 (-127 ~ +127)
Byte 2: Y 位移 (-127 ~ +127)
Byte 3: 滚轮 (-127 ~ +127)

BLE HID vs SLE HID

BLE HID SLE HID
协议层 HID over GATT (HOGP) SLE Low Latency 模式
标准性 国际标准(Bluetooth SIG) HiSilicon 私有
连接间隔 ≤ 11.25ms 125Hz~8KHz 调度
延迟 ~11ms ~1ms(最低)
兼容性 所有手机/PC 原生支持 需要 SLE 对端设备

涉及 API

API 谁调用 用途
gatts_notify_indicate() Peripheral 发送 HID Report
gap_ble_connect_param_update() Peripheral 请求更新连接参数到 HID 规范
gatts_add_service_sync() Peripheral 注册 HID Service

案例操作指导

WS63 上电 → 手机/PC 搜索并连接 BLE 键盘 → 按键 → 屏幕出现字符。

关键配置

  • 连接间隔:11.25ms(HID 规范 ≤ 11.25ms)
  • Latency:0(最低延迟)
  • 发送策略:按键变化时发送,无按键不发送(省电)

代码详解

Report Map 描述符

// 键盘 Report Map——告诉主机按键布局
static const uint8_t keyboard_report_map[] = {
    0x05, 0x01,       // Usage Page (Generic Desktop)
    0x09, 0x06,       // Usage (Keyboard)
    0xA1, 0x01,       // Collection (Application)
    0x05, 0x07,       //   Usage Page (Keyboard)
    0x19, 0xE0,       //   Usage Minimum (Keyboard LeftControl)
    0x29, 0xE7,       //   Usage Maximum (Keyboard Right GUI)
    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)
    // ... (按键数组省略)
    0xC0              // End Collection
};

按键检测与 Report 发送

static void scan_keyboard_and_send(void)
{
    uint8_t report[8] = {0};

    // Byte 0: Modifier (Ctrl/Shift/Alt/GUI)
    if (gpio_read(KEY_CTRL))  report[0] |= 0x01;
    if (gpio_read(KEY_SHIFT)) report[0] |= 0x02;

    // Byte 2-7: 按键码(最多 6 键)
    uint8_t key_idx = 2;
    if (gpio_read(KEY_A))     report[key_idx++] = 0x04;  // HID 按键码 'A'
    if (gpio_read(KEY_B))     report[key_idx++] = 0x05;
    // ...

    if (key_idx > 2) {  // 有按键按下
        gatts_notify_indicate(g_conn_id, g_report_char_handle,
                              report, sizeof(report));
    }
}

连接参数优化

static void conn_state_cb(uint16_t conn_id, bt_gap_conn_state_t state)
{
    if (state == CONNECTED) {
        // HID 设备连接后立即请求短连接间隔
        bt_gap_conn_param_t param = {
            .interval_min = 9,   // 11.25ms
            .interval_max = 9,
            .latency      = 0,   // 零延迟
            .timeout      = 200, // 2 秒
        };
        gap_ble_connect_param_update(conn_id, &param);
    }
}