key开发指南
概述
按键系统支持两种类型按键:
- Power Key按键:电源键,默认支持
- Function Key按键:功能键,可通过GPIO外接按键实现,最多可扩展7个
按键类型示意

支持的按键事件类型:
- 单击(CLICKUP)
- 双击(CLICKUP_2)
- 短按(LONGPRESS_1S)
- 长按(LONGPRESS_5S)
快速验证板载按键
社区固件的产品输入模块已在启动阶段初始化 Power Key 并注册按键消息链路,因此无需再创建一套会重复占用定时器和 GPIO 回调的 demo。烧录社区固件并进入应用列表后,依次进行以下验证:
- 单击 Power Key,确认屏幕亮灭状态发生变化。
- 双击 Power Key,确认系统进入应用列表或执行当前产品定义的双击动作。
- 长按 Power Key,确认系统产生长按动作;具体动作由产品层当前注册的
BUTTON_LONGPRESS_1S、BUTTON_LONGPRESS_5S处理逻辑决定。
板载 Power Key 不依赖额外硬件。Function Key 属于扩展 GPIO 按键,只有在接入按键、上拉/下拉和消抖电路并完成引脚映射后才能验证;不要为了测试 Function Key 改写 Power Key 的现有回调。
功能描述
按键模块架构

按键模块提供的接口:
| 接口声明 | 功能说明 |
|---|---|
| uapi_button_init() | 初始化按键模块 |
| uapi_button_register() | 注册按键引脚映射 |
| uapi_button_gpio_register() | 注册 GPIO 按键 |
| uapi_button_send_msg_register() | 注册消息发送函数 |
| uapi_timer_init() | 初始化定时器 |
| uapi_timer_adapter() | 适配定时器 |
| uapi_timer_create() | 创建定时器 |
开发指引
按键初始化
errcode_t uapi_button_init(void)
{
errcode_t ret = 0;
ret = uapi_timer_init();
ret |= uapi_timer_adapter(1, TIMER_1_IRQN, irq_prio(TIMER_1_IRQN)); /* 使用timer1 */
if (ret != ERRCODE_SUCC) {
PRINT("uapi_timer_init FAILED 0x%x", ret);
return ret;
}
ret = uapi_timer_create(1, &g_button_timer); /* 使用timer1 */
if (ret != ERRCODE_SUCC) {
PRINT("uapi_timer_create FAILED 0x%x", ret);
return ret;
}
return ERRCODE_SUCC;
}
注册按键引脚映射
errcode_t uapi_button_register(button_map_t* button_map)
{
errcode_t ret = 0;
if (button_map == NULL) {
return ERRCODE_FAIL;
}
button_peripheral_api *button_api = button_port_get_api();
for (uint8_t i = 0; i < BUTTON_PIN_MAP_MAX; i++) {
g_button_pin_map[i].pin = button_map[i].pin;
g_button_pin_map[i].button = button_map[i].button;
if (button_map[i].pin != PIN_NONE && button_map[i].button != BUTTON_MAX) {
if (button_map[i].button == BUTTON_PWR) {
button_api->button_pmu_pwr_cfg(true);
}
ret |= uapi_button_gpio_register(g_button_pin_map[i].pin);
} else if (button_map[i].pin == PIN_NONE && button_map[i].button == BUTTON_PWR) {
ret = button_api->button_register_callback(g_button_pin_map[i].pin,
(osal_irq_handler)button_irq_callback);
if (ret != ERRCODE_SUCC) {
PRINT("button register failed\r\n");
return ret;
}
continue;
}
}
return ret;
}
注册按键回调
button_map_t g_brandy_button_pin_map[BUTTON_PIN_MAP_MAX] = {
{ PIN_NONE, BUTTON_PWR }, // 电源键
{ S_MGPIO25, BUTTON_1 }, // GPIO按键1
{ PIN_NONE, BUTTON_2 }, // 可继续扩展
{ PIN_NONE, BUTTON_3 },
{ PIN_NONE, BUTTON_4 },
{ PIN_NONE, BUTTON_5 },
{ PIN_NONE, BUTTON_6 },
{ PIN_NONE, BUTTON_7 },
};
// 调用注册
uapi_button_register(g_brandy_button_pin_map);
注册消息发送函数
void uapi_button_send_msg_register(msg_send_callback_t cb)
{
if (cb != NULL) {
g_msg_send_cb = cb;
}
}
配置电源键模式
Power Key支持设置强制触发事件:
typedef enum {
PDMODE_RE_UP, // 重启
PDMODE_DOWN, // 关机
PDMODE_MAX
} power_mode_t;
// 设置为关机模式
// 具体接口请参考电源管理模块源码
// 设置为重启模式(默认)
// 具体接口请参考电源管理模块源码
配置电源键触发时间
Power Key支持设置触发事件的时间阈值:
typedef enum {
PDTIME_LEVEL0, // 10秒
PDTIME_LEVEL1, // 11秒(默认)
PDTIME_LEVEL2, // 12秒
PDTIME_LEVEL3, // 13秒
PDTIME_LEVELMAX
} power_time_t;
// 设置为12秒触发
// 具体接口请参考电源管理模块源码
说明: 由于受片内ULP 32K时钟源精度影响,在0℃~55℃温度范围内按键触发时间误差约为0%~16%。
GPIO按键适配步骤
1. 配置按键引脚映射
修改button_feature.c中的g_brandy_button_pin_map:
button_map_t g_brandy_button_pin_map[BUTTON_PIN_MAP_MAX] = {
{ PIN_NONE, BUTTON_PWR }, // 电源键(默认支持)
{ S_MGPIO25, BUTTON_1 }, // GPIO按键1
{ S_MGPIO26, BUTTON_2 }, // GPIO按键2
{ PIN_NONE, BUTTON_3 },
{ PIN_NONE, BUTTON_4 },
{ PIN_NONE, BUTTON_5 },
{ PIN_NONE, BUTTON_6 },
{ PIN_NONE, BUTTON_7 },
};
2. 配置GPIO管脚IE(低功耗版本)
在 board_evb.h 中修改对应管脚的 IE 配置:
// 原始配置
{ HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_DISABLE },
// 修改为(开启输入使能)
{ HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENABLE },
3. 新增按键事件枚举
在 button_feature.h 中新增按键事件枚举:
typedef enum {
/* power key */
BUTTON_PWR_START = 0,
BUTTON_PWR_CLICKUP,
BUTTON_PWR_CLICKUP_2,
BUTTON_PWR_LONGPRESS_1S,
BUTTON_PWR_LONGPRESS_5S,
BUTTON_PWR_INVALID,
/* function key */
BUTTON1_START,
BUTTON1_CLICKUP,
BUTTON1_CLICKUP_2,
BUTTON1_LONGPRESS_1S,
BUTTON1_LONGPRESS_5S,
BUTTON1_INVALID,
/* new key */
BUTTON2_START,
BUTTON2_CLICKUP,
BUTTON2_CLICKUP_2,
BUTTON2_LONGPRESS_1S,
BUTTON2_LONGPRESS_5S,
BUTTON2_INVALID,
BUTTON_BUTT
} event_button_t;
4. 实现按键事件处理
在 button_event_get 接口中新增事件处理如下,默认只有 BUTTON_1 事件。例如要新增两个 GPIO 按键,需要在 BUTTON1 事件处理之后新增一组 BUTTON2 的事件处理,以此类推:
static event_button_t button_event_get(button_id_t id, button_report_state_t state)
{
event_button_t event = BUTTON_PWR_START;
if (id == BUTTON_1) {
event = BUTTON1_START;
}
/* new key */
if (id == BUTTON_2) {
event = BUTTON2_START;
}
// ... 更多按键处理
return event;
}
说明: 若只适配一个GPIO按键,完成步骤1和2即可,否则需要全部步骤适配完成。
注意事项
说明: 按键模块接口详细说明请参考上方接口表格中的头文件声明。
常见问题
| 问题 | 解决方案 |
|---|---|
| 按键无响应 | 检查GPIO管脚配置和IE设置是否正确 |
| 多按键冲突 | 检查GPIO管脚是否被其他功能占用 |
| 低功耗下按键失效 | 确保GPIO管脚IE配置正确 |
| 事件误触发 | 调整消抖时间和按键事件阈值 |
| Power Key无法关机 | 检查电源管理模块配置是否为关机模式 |
| 长按触发时间不准 | 检查电源管理模块配置,考虑32K时钟精度误差 |
按键事件时间说明
