杰理 SDK 文档中心
首页
首页
  • SDK 概述与入门

    • SDK 总览
    • 支持芯片与蓝牙认证
    • 工程结构导航
  • 开发环境与构建

    • 环境搭建与工具链安装
    • 编译指南与工程选择
    • 烧录与生产工具
  • BLE 透传/数传应用

    • 透传应用框架与处理模块
    • 透传与数传示例
    • 多连接与自定义服务示例
    • FindMy 与查找网络示例
  • HID 人机交互应用

    • 键盘与按键设备示例
    • 鼠标设备示例
    • 遥控器示例
    • HID 蓝牙应用模块
  • 公共 BSP 模块

    • 按键、编码器与红外输入
    • 传感器驱动
    • LED 与显示控制
    • 串口与 USB 通信
    • 存储、参数与时钟
    • 电源与温度管理
    • 消息、内存与系统配置
    • OTA 升级框架
  • 蓝牙协议栈与库

    • BLE 控制器与协议栈适配
    • 经典蓝牙 BR/EDR 支持
    • 第三方蓝牙协议
    • 设备管理框架
    • DUT 测试与射频认证
  • 构建系统与开发工具

    • Makefile 构建系统
    • 固件后处理与配置工具
    • 辅助脚本与库合并
  • 文档与硬件资料

    • AT 命令参考
    • 硬件参考资料
    • SDK 文档与在线资源

键盘与按键设备示例

本文档介绍 fw-AW33N_BLE_SDK 中「键盘与按键设备示例」(apps/demo/hid)的完整实现:从应用入口的分支选择、USB HID 键盘设备描述符与报表描述符,到 BLE HID 服务的标准 UUID 定义,以及配套的板级配置。它面向需要基于 AW33N 平台开发 BLE/USB 键盘、按键遥控器、Keyfob 等 HID 设备的工程师,是一份源码级参考。

Purpose and Scope

本页面覆盖与 HID 键盘/按键类设备 相关的能力:

  • apps/demo/hid 示例工程的入口与启动流程(app_main.c)
  • USB HID 键盘设备实现(hid_keyboard.c)中的设备/接口/端点描述符与 HID Report Descriptor
  • BLE HID 服务(HID over GATT)的标准 UUID 定义(standard_hid.h)
  • 示例工程板级目录(apps/demo/hid/board/bd57)中键盘、鼠标、遥控器多个变体配置

以下内容属于兄弟页面,不在本页展开:鼠标类设备的完整实现(hid_mouse.c 与 board_aw33n_mouse*.c 的详细行为)、USB 音频/媒体类设备(hid_media.c)、RCSP 遥控器协议(rcsp_hid)、BLE 协议栈底层与 GATT 服务注册机制。如需了解 BLE 协议栈接入,请参见协议栈相关页面。

Overview

在 AW33N 平台上,HID 设备有两条输出路径:

  1. USB HID:设备通过 USB 枚举为标准 HID 键盘,Host(PC/手机)通过中断端点轮询读取按键报表。
  2. BLE HID(HID over GATT):设备作为 BLE Peripheral 广播 HID Service(UUID 0x1812),Host 通过 GATT 的 Report Characteristic 收发按键数据。

示例工程 apps/demo/hid 把这两条路径所需的描述符、报表定义与启动逻辑集中在一起,并通过编译期宏(CONFIG_APP_*)在同一个 SDK 中切换出键盘(hid_key)、Keyfob、按键翻页器(keypage)、遥控器(hid_rc)、鼠标(mouse_dual / mouse_low_latency)等不同产品形态。这样设计的好处是:应用框架、电源管理、消息分发、USB 枚举等基础设施完全复用,只有"应用分支"与"板级配置"不同,厂商只需修改板级头文件即可快速产出新产品。

核心设计要点:

  • 描述符驱动一切:USB HID 的键盘功能完全由 sHIDDescriptor(设备描述)与 sHIDReportDesc(报表描述)决定,代码本身不参与"哪些键被按下"的语义判断,只负责搬运报表字节。
  • 报表 ID 区分通道:键盘报表使用 Report ID 0x3,Consumer Control(多媒体键)报表使用 Report ID 0x05,同一根中断端点上用 Report ID 区分两种输入。
  • BLE 与 USB 共享同一套 HID 语义:BLE 侧只定义 GATT 特征 UUID(Report、Report Map、Protocol Mode 等),报表内容与 USB 侧一致,因此同一套按键扫描代码可以同时服务两种传输。
  • 中断轮询节奏:USB 端点配置为 Interrupt 传输、bInterval = 0x01(约 10ms 轮询一次),兼顾响应速度与总线占用。

Architecture

下图展示了键盘示例从应用入口到 USB/BLE 两条 HID 输出路径的整体架构,节点名称均取自仓库中的实际文件/模块:

flowchart TD
    subgraph sg_App["应用层 apps/demo/hid"]
        AppMain["app_main.c<br/>app_main() / main_app_get_name()"]
        Board["board/bd57<br/>board_aw33n_demo.c + board_config.h"]
    end

    subgraph sg_Usb["USB 设备层"]
        HidKeyboard["usb/device/hid_keyboard.c<br/>sHIDDescriptor + sHIDReportDesc"]
        UsbStack["usb_stack.h / usb_config.h"]
    end

    subgraph sg_Ble["BLE HID 层"]
        StdHid["include/standard_hid.h<br/>HID Service 0x1812"]
        BleStack["BLE GATT Stack"]
    end

    subgraph sg_Host["Host 端"]
        PcHost["PC / 手机 Host"]
    end

    AppMain -->|"CONFIG_APP_KEYBOARD -> hid_key"| Board
    Board -->|"USB_DEVICE_CLASS_CONFIG & HID_CLASS"| HidKeyboard
    HidKeyboard --> UsbStack
    UsbStack -->|"Interrupt EP IN/OUT<br/>10ms poll"| PcHost
    Board -->|"HID over GATT"| StdHid
    StdHid --> BleStack
    BleStack -->|"Report Characteristic"| PcHost

架构解读:

  • app_main.c 是唯一入口:app_main() 完成内存段、中断优先级、开机按键、低压检测等平台初始化后,调用 main_application_operation_state(NULL, APP_STA_START) 进入应用状态机;随后 main_app_get_name() 依据 CONFIG_APP_* 宏选出实际应用分支(键盘 → hid_key / ACTION_HID_MAIN)。
  • 板级目录 决定"这个产品长什么样":board_aw33n_demo.c 是键盘/按键演示板,board_aw33n_mouse*.c 是鼠标变体,board_aw33n_rc.c 是遥控器变体,它们通过 Makefile / .cbp 工程文件单独编译。
  • USB 路径:hid_keyboard.c 在 USB_DEVICE_CLASS_CONFIG & HID_CLASS 条件编译下提供完整描述符,#pragma 段指令把 HID 相关数据放入 .usb_slave.hid.* 专用段,便于链接器布局与低功耗管理。
  • BLE 路径:standard_hid.h 只做一件事——定义 HID over GATT 的标准 16-bit UUID 常量,避免魔法数散落各处;真正的服务注册与报表收发由 BLE 协议栈(本页不展开)完成。

应用分支与启动流程

入口初始化:app_main()

app_main() 是整个示例的起点,位于 apps/demo/hid/app_main.c:

void app_main()
{
#if UPDATE_V2_EN
    /* 初始化检查升级状态, 测试盒升级后要关机, APP-OTA升级后要开机*/
    update_success_boot_check();
#endif

    log_info(">>>>>>>>>>>>>>>>>>app_main...\n");
    log_info("nk_malloc: %08x,%04x, nv_malloc: %08x,%04x", NK_RAM_MALLOC_START_ADDR, NK_RAM_MALLOC_SIZE,
             NV_RAM_MALLOC_START_ADDR, NV_RAM_MALLOC_SIZE);

#if TCFG_POWER_ON_NEED_KEY
    check_power_on_key();
#endif

#if TCFG_SYS_LVD_EN
    app_power_vbat_check();
#endif

    main_application_operation_state(NULL, APP_STA_START);
}

Source: app_main.c

设计意图:

  • 先检查升级状态(UPDATE_V2_EN),保证 OTA 后能正确决定"开机还是关机";
  • 打印内存布局(NK/NV RAM malloc 地址与大小),这是调试蓝牙内存池的常用手段;
  • TCFG_POWER_ON_NEED_KEY 开启时,check_power_on_key() 会循环等待开机键:长按超过 70 个 10ms 周期才真正开机,否则进入软关机(power_set_soft_poweroff()),防止误触开机;
  • TCFG_SYS_LVD_EN 开启时做低压检测,电量不足时阻止启动;
  • 最后把控制权交给 main_application_operation_state(),进入应用状态机。

分支选择:main_app_get_name()

键盘/按键设备的"形态"由编译宏决定,app_main.c 第 166-200 行:

static void main_app_get_name(struct intent *it)
{
    init_intent(it);
    // 选择应用分支
#if(CONFIG_APP_KEYBOARD)
    it->name = "hid_key";
    it->action = ACTION_HID_MAIN;

#elif(CONFIG_APP_KEYFOB)
    it->name = "keyfob";
    it->action = ACTION_KEYFOB;

#elif(CONFIG_APP_KEYPAGE)
    it->name = "keypage";
    it->action = ACTION_KEYPAGE;

#elif(CONFIG_APP_REMOTE_CONTROL)
    it->name = "hid_rc";
    it->action = ACTION_REMOTE_CONTROL;

#elif(CONFIG_APP_MOUSE_DUAL)
    it->name = "mouse_dual";
    it->action = ACTION_MOUSE_MAIN;

#elif(CONFIG_APP_MOUSE_LOW_LATENCY)
    it->name = "mouse_low_latency";
    it->action = ACTION_MOUSE_MAIN;

#elif(CONFIG_APP_IDLE)
    it->name = "idle";
    it->action = ACTION_IDLE_MAIN;

#else
    ASSERT(0, "no app!!!");
#endif
}

Source: app_main.c

设计意图: 这是典型的"配置驱动的应用选择器"。struct intent 是 SDK 的启动意图(intent)机制:name 决定加载哪个应用模块,action 决定初始动作。键盘示例对应的 CONFIG_APP_KEYBOARD 会启动名为 hid_key 的应用并执行 ACTION_HID_MAIN。若所有宏都未定义,ASSERT(0, "no app!!!") 会直接触发断言,避免在未配置形态时静默运行——这是嵌入式 SDK 常见的"fail fast"策略。

USB HID 键盘设备实现

段布局与条件编译

hid_keyboard.c 位于 apps/app/bsp/common/usb/device/hid_keyboard.c,文件开头的 #pragma 把 HID 相关的 BSS、数据、常量与代码分别放入 .usb_slave.hid.* 段,日志 Tag 为 [HID_KEYBOARD],并整体被 #if USB_DEVICE_CLASS_CONFIG & HID_CLASS 条件编译包裹:

#pragma bss_seg(".usb_slave.hid.data.bss")
#pragma data_seg(".usb_slave.hid.data")
#pragma const_seg(".usb_slave.hid.text.const")
#pragma code_seg(".usb_slave.hid.text")
#pragma str_literal_override(".usb_slave.hid.text.const")

#include "usb/device/usb_stack.h"
#include "usb/device/hid.h"
#include "usb_config.h"
#include "usb.h"
#include "app_config.h"

#define LOG_TAG_CONST       USB
#define LOG_TAG             "[HID_KEYBOARD]"
...
#if USB_DEVICE_CLASS_CONFIG & HID_CLASS

Source: hid_keyboard.c

设计意图: 段重定向(#pragma bss_seg/data_seg/const_seg/code_seg)是杰理 SDK 管理 USB RAM 的惯用手段——把 HID 设备代码放进专用段后,链接脚本可以在低功耗(soft power off)时整体回收或保持这些段,从而精确控制功耗与内存占用。条件编译 HID_CLASS 保证未启用 HID 类的工程不会引入任何键盘代码,实现"配置即裁剪"。

设备描述符:sHIDDescriptor

设备描述符(hid_keyboard.c 第 25-70 行)定义了一个标准 HID 键盘接口:

  • 接口描述符:bInterfaceClass = USB_CLASS_HID,bInterfaceSubClass = 0x01(Boot Interface),bInterfaceProtocol = 0x01(Keyboard)。Boot 子类意味着 Host 在进入 OS 前(BIOS/引导阶段)也能识别该键盘,这是键盘类设备的标配。
  • HID 描述符:bcdHID = 0x0110(HID 1.10 规范),后跟一个 Report Descriptor(类型 0x22),长度占位符由驱动在枚举时回填。
  • 中断 IN 端点:USB_DIR_IN | HID_KEYBOARD_EP_IN,USB_ENDPOINT_XFER_INT,bInterval = 0x01(10ms 轮询)。
  • 可选中断 OUT 端点:当 HID_KEYBOARD_EP_OUT 为真时增加第二个端点,用于接收 Host 下发的输出报表(如键盘 LED 状态:Num Lock / Caps Lock)。

HID Report Descriptor:sHIDReportDesc

报表描述符(hid_keyboard.c 第 72-119 行)定义了两个 Application Collection:

  1. 标准键盘报表(Report ID 0x3),8 字节按键报文:1 字节修饰键(Ctrl/Shift/Alt/GUI,对应 Usage 0xE0~0xE7)+ 1 字节保留位 + 6 字节普通按键数组(Usage 0x00~0xFF 的 Keypad 页面)。这是 USB HID Boot Keyboard 的标准 8 字节格式,Host 端无需额外驱动即可解析。
  2. Consumer Control 报表(Report ID 0x05):16 位 Consumer 页面 Usage(0x00~0x28C),用于多媒体按键(音量、播放/暂停等),与键盘报表共用同一中断端点,用 Report ID 区分。
#define HID_KEYBOARD_REPORT_ID      0x3
static const u8 sHIDReportDesc[] = {
    0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
    0x09, 0x06,        // Usage (Keyboard)
    0xA1, 0x01,        // Collection (Application)
    0x85, HID_KEYBOARD_REPORT_ID,//   Report ID (1)
    0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
    0x19, 0xE0,        //   Usage Minimum (0xE0)
    0x29, 0xE7,        //   Usage Maximum (0xE7)
    0x15, 0x00,        //   Logical Minimum (0)
    0x25, 0x01,        //   Logical Maximum (1)
    0x75, 0x01,        //   Report Size (1)
    0x95, 0x08,        //   Report Count (8)
    0x81, 0x02,        //   Input (Data,Var,Abs,...)
    ...
    0x95, 0x06,        //   Report Count (6)
    0x75, 0x08,        //   Report Size (8)
    ...
    0x81, 0x00,        //   Input (Data,Array,Abs,...)
    0xC0,              // End Collection
    0x05, 0x0C,        // Usage Page (Consumer)
    0x09, 0x01,        // Usage (Consumer Control)
    0xA1, 0x01,        // Collection (Application)
    0x85, 0x05,        //   Report ID (3)
    0x75, 0x10,        //   Report Size (16)
    ...
    0x81, 0x00,        //   Input (Data,Array,Abs,...)
    0xC0,              // End Collection
};

Source: hid_keyboard.c

设计意图: 描述符以字节数组手写而非结构体,是 USB 描述符的常见做法——描述符在编译期完全确定、零运行时开销,且能精确控制每个字节。Modifier 键用 8 个 1-bit 字段(Var)而普通键用 6 字节数组(Array),遵循 HID 规范对键盘的特殊约定:修饰键可多键同时按住(位掩码),普通键最多同时按下 6 个(溢出丢弃)。

BLE HID 服务定义

BLE 侧的键盘通过 HID over GATT(标准 HID Service 0x1812)工作。standard_hid.h(apps/demo/hid/include/standard_hid.h)集中定义了该服务涉及的全部标准 16-bit UUID:

#define HID_UUID_16                                 0x1812
#define HID_INFORMATION_UUID_16                     0x2A4A
#define HID_REPORT_MAP_UUID_16                      0x2A4B
#define HID_CONTROL_POINT_UUID_16                   0x2A4C
#define HID_REPORT_UUID_16                          0x2A4D
#define PROTOCOL_MODE_UUID_16      				    0x2A4E
#define HID_REPORT_REFERENCE_UUID_16                0x2908

Source: standard_hid.h

各 UUID 的角色:

UUID名称用途
0x1812HID ServiceHID over GATT 服务声明
0x2A4AHID Information设备 HID 版本、国家码、标志位
0x2A4BReport Map与 USB 侧 sHIDReportDesc 内容一致的报表描述符,Host 据此解析按键数据
0x2A4CControl Point可选;用于 Suspend/Exit Suspend 控制
0x2A4DReport实际按键数据特征(可带 Report Reference 描述符 0x2908 指明 Report ID 与类型)
0x2A4EProtocol ModeBoot/Report 两种协议模式切换
0x2908Report Reference描述符,把 Report 特征绑定到具体 Report ID 与输入/输出/特征类型

设计意图: BLE HID 之所以复用 USB 的报表概念,是因为 Host(Windows/macOS/Android/iOS)对 HID over GATT 的解析流程与 USB HID 几乎一致:先读 Report Map 知道报文布局,再订阅 Report 特征收按键。因此 SDK 在 standard_hid.h 中只定义 UUID,实际报表内容仍引用 USB 侧的同一套描述符语义,同一份按键扫描/编码逻辑可同时驱动 USB 与 BLE 两条链路。

Core Flow:从按键到 Host 的完整链路

下图展示一次"按键按下 → Host 收到键值"的完整数据流,覆盖 BLE HID 与 USB HID 两条路径:

sequenceDiagram
    participant User as 用户
    participant Key as 按键扫描 (板级 board_aw33n_demo.c)
    participant App as hid_key 应用 (ACTION_HID_MAIN)
    participant BLE as BLE GATT (HID Service 0x1812)
    participant USB as USB HID 设备 (hid_keyboard.c)
    participant Host as Host (PC/手机)

    User->>Key: 按下按键
    Key->>App: 按键消息 (msg 队列)
    App->>App: 映射为 HID 键码 (Usage ID)
    par BLE 路径
        App->>BLE: 写入 Report 特征 (0x2A4D)
        BLE->>Host: GATT Notification/Indication
    and USB 路径
        App->>USB: 组 8 字节按键报表 (Report ID 0x3)
        USB->>Host: Interrupt IN 端点 (10ms 轮询)
    end
    Host->>Host: 解析报表, 产生键盘事件

流程说明:

  1. 采集:板级按键扫描(board_aw33n_demo.c 中的按键矩阵/ADC 扫描)检测到按下事件,通过 SDK 消息队列投递给应用。
  2. 语义转换:hid_key 应用把"物理按键"映射为 HID Usage ID(例如 A 键 → 0x04),并维护修饰键状态(Shift/Ctrl 等)。
  3. 并行分发:应用按需向两条路径提交:
    • BLE 路径写 Report 特征(0x2A4D),Host 通过 Notification 实时收到;
    • USB 路径把键码填入 8 字节报表(Report ID 0x3,修饰键 1 字节 + 保留 1 字节 + 键码数组 6 字节),等待 Host 在 10ms 中断轮询时取走。
  4. Host 解析:Host 依据 Report Map 把字节还原为键值并产生输入事件。松键时应用必须发送"全零报表"(空键码),否则按键会被视为持续按住——这是 HID 键盘实现最常见的坑。

配置选项

键盘/按键示例的行为完全由编译期宏控制,分布在板级头文件与 app_config.h 中。以下是源码中出现的核心配置:

配置宏类型默认/取值说明
CONFIG_APP_KEYBOARD编译宏0/1选择键盘应用分支(hid_key + ACTION_HID_MAIN)
CONFIG_APP_KEYFOB编译宏0/1选择 Keyfob(遥控钥匙)应用分支
CONFIG_APP_KEYPAGE编译宏0/1选择按键翻页器应用分支
CONFIG_APP_REMOTE_CONTROL编译宏0/1选择遥控器应用分支(hid_rc)
CONFIG_APP_MOUSE_DUAL / CONFIG_APP_MOUSE_LOW_LATENCY编译宏0/1鼠标双模/低延迟变体(兄弟页面)
CONFIG_APP_IDLE编译宏0/1空闲应用(调试用)
USB_DEVICE_CLASS_CONFIG位掩码含 HID_CLASS启用 USB HID 类设备
HID_KEYBOARD_EP_IN宏端点号键盘中断 IN 端点地址
HID_KEYBOARD_EP_IN_MAX_SIZE宏报文大小IN 端点最大包长(如 8/16 字节)
HID_KEYBOARD_EP_OUT宏0/1是否启用中断 OUT 端点(接收 LED 等输出报表)
HID_KEYBOARD_EP_OUT_MAX_SIZE宏报文大小OUT 端点最大包长
TCFG_POWER_ON_NEED_KEY宏0/1开机需按键长按确认,防误触(约 700ms)
TCFG_SYS_LVD_EN宏0/1启动前低压检测
TCFG_AUTO_SHUT_DOWN_TIME宏秒自动关机时间(示例中 app_var.auto_off_time 默认置 0 关闭)

上表中的端点宏(HID_KEYBOARD_EP_*)在 hid_keyboard.c 中被引用;应用分支宏在 app_main.c 中被引用;电源相关宏在 app_main.c 中被引用。

API Reference(关键入口)

void app_main(void)

示例工程入口。完成升级状态检查、内存布局打印、开机键确认、低压检测后,调用 main_application_operation_state(NULL, APP_STA_START) 启动应用状态机。

  • 参数:无
  • 返回:无
  • 说明:APP_STA_START 是状态机首态;实际加载哪个应用由 main_app_get_name() 决定。

static void main_app_get_name(struct intent *it)

根据 CONFIG_APP_* 编译宏选择应用分支,填充启动意图。

  • 参数:it(struct intent *)——启动意图,name 字段为应用模块名,action 字段为初始动作。
  • 返回:无
  • 注意:所有分支宏均未定义时执行 ASSERT(0, "no app!!!"),属于 fail-fast 保护。

void check_power_on_key(void)

开机键确认逻辑(TCFG_POWER_ON_NEED_KEY 开启时生效)。循环检测电源状态:长按超过 70 个 10ms 周期(约 700ms)视为有效开机;松开则进入软关机 power_set_soft_poweroff()。

  • 参数:无
  • 返回:无
  • 依赖:get_power_on_status()、set_key_poweron_flag()、power_set_soft_poweroff() 等电源管理接口。

void app_var_init(void)

初始化全局应用变量 app_var:关闭自动关机(auto_off_time = 0)、设置提示音频率(warning_tone_v / poweroff_tone_v)。

描述符数据(编译期常量)

  • sHIDDescriptor[]:USB 键盘接口/端点描述符,见 hid_keyboard.c 第 25-70 行。
  • sHIDReportDesc[]:键盘 + Consumer Control 报表描述符,见 hid_keyboard.c 第 72-119 行。

失败模式与边界情况

以下行为均能从源码结构推导并应在移植时重点验证:

  • 按键粘滞(Stuck Key):HID 键盘语义要求松键时发送空键码报表。若应用在 ACTION_HID_MAIN 循环中漏发"全零报表",Host 会认为按键持续按住。实现时必须在按键释放事件里清零 8 字节报表(含修饰键位)。
  • 6 键无冲突(6KRO)限制:报表中普通键数组只有 6 个槽位,第 7 个键同时按下会被 HID 规范定义为"溢出(Rollover)"并被 Host 忽略。需要更多同时按键时,必须修改 sHIDReportDesc 的 Report Count 并同步放大 HID_KEYBOARD_EP_IN_MAX_SIZE。
  • 描述符长度占位符:sHIDDescriptor 中 Report 描述符长度字段为 0(第 51-52 行),依赖 USB 驱动在枚举阶段回填。若驱动未实现回填,Host 会读到 0 长度的 Report Map 导致设备无法识别——移植新平台时务必确认该回填逻辑。
  • 未配置应用分支:main_app_get_name() 在所有 CONFIG_APP_* 宏都为 0 时直接 ASSERT(0, "no app!!!")。新增产品形态时,必须在板级配置中恰好定义一个分支宏。
  • 开机误触:TCFG_POWER_ON_NEED_KEY 未开启时,上电即进系统,可能因运输/手持误触导致设备异常开机耗电;量产产品建议开启并按需调整 70 个 10ms 周期的判定时长。
  • USB 枚举失败:#pragma 段指令把 HID 代码放入 .usb_slave.hid.* 段,若链接脚本未包含这些段(或 USB_DEVICE_CLASS_CONFIG 未含 HID_CLASS),USB 侧将静默无 HID 功能,且无编译期报错——排查"插上没反应"时应先检查这两个前提。

并发与功耗考虑

  • 中断轮询 vs 通知:USB 路径是 Host 主动轮询(10ms),BLE 路径是设备主动 Notification,两条路径完全独立,不存在共享缓冲区竞争的前提是应用层为每条链路维护独立报表缓冲区;否则多任务同时写同一报表数组会产生数据撕裂。
  • 低功耗段管理:HID 代码/数据被显式放入 .usb_slave.hid.* 段,配合 SDK 的电源管理可以在无 USB 会话时整体断电。eSystemConfirmStopStatus() 返回 1 表示系统进入"无定时唤醒的深度睡眠"(Endless Sleep),键盘示例默认启用,意味着空闲时应无周期性唤醒,此时蓝牙保持连接的功耗完全取决于协议栈。
  • 启动路径中的忙等:check_power_on_key() 在开机确认期间 os_time_dly(1) 循环并喂狗(clr_wdt()),是刻意为之——既保证按键判定实时性,又避免看门狗复位。修改判定时长时需同步确认喂狗节奏。

扩展点

  • 新增产品形态:在 main_app_get_name() 的 #if/#elif 链中增加一个 CONFIG_APP_XXX 分支,并在板级目录新增 board_aw33n_xxx.c 与配套 *_cfg.h / *_global_build_cfg.h,即可复用全部基础设施。仓库中的鼠标(board_aw33n_mouse*.c)与遥控器(board_aw33n_rc.c)变体就是现成范例。
  • 自定义报表:修改 sHIDReportDesc 的 Collection/Usage/Report ID 即可扩展功能(如加入系统控制页、媒体页的更多按键)。注意:Report ID 是 BLE 与 USB 两侧共享的协议契约,standard_hid.h 中 HID_REPORT_REFERENCE_UUID_16 (0x2908) 描述符必须与之一致,否则 Host 解析 BLE 报表会错位。
  • 输出报表(LED):开启 HID_KEYBOARD_EP_OUT 后可接收 Host 下发的 LED 状态(Num Lock/Caps Lock/Scroll Lock,见 sHIDReportDesc 中 Usage Page LEDs 的 Output 字段),可用于驱动键盘指示灯。
  • 协议模式:通过 PROTOCOL_MODE_UUID_16 (0x2A4E) 可在 Boot 协议与 Report 协议间切换,适配不同的 Host 引导环境。

相关链接

  • apps/demo/hid/app_main.c — 示例入口与分支选择
  • apps/demo/hid/include/standard_hid.h — BLE HID 服务 UUID 定义
  • apps/app/bsp/common/usb/device/hid_keyboard.c — USB HID 键盘描述符与报表描述符
  • apps/demo/hid/board/bd57/board_config.h — 板级配置汇总
  • apps/demo/hid/board/bd57/AW33N_hid.cbp — Code::Blocks 工程文件(编译入口)
  • apps/demo/hid/board/bd57/board_aw33n_demo.c — 键盘演示板初始化
  • apps/demo/hid/board/bd57/Makefile — 命令行构建脚本
  • 兄弟页面:鼠标设备示例(hid_mouse.c、board_aw33n_mouse*.c)、遥控器示例(board_aw33n_rc.c、rcsp_hid)、USB 媒体设备(hid_media.c)
Next
鼠标设备示例