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 字节):
鼠标(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, ¶m);
}
}