NN_Key是一个功能丰富的嵌入式按键处理库,专为STM32等单片机系统设计,提供了完整的按键事件检测和处理能力。本库支持按键消抖、单击、双击、三击、多击、长按、持续长按等多种操作方式,并且提供了组合按键功能,满足复杂人机交互的需求。
库的设计遵循模块化思想,易于集成到各种嵌入式项目中,通过简单的回调机制,可以轻松实现各种按键事件的响应,无需编写复杂的状态机逻辑。
- 多种按键事件:支持单击、双击、三击、多击(>3)、长按、持续长按等事件类型
- 消抖处理:内置消抖算法,避免按键抖动带来的误触发
- 组合按键:支持多个按键的组合检测,最多支持4个按键组合
- 回调机制:基于事件的回调函数注册,灵活响应各类按键事件
- 参数可调:按键的消抖时间、长按时间、连击间隔等参数均可自定义
- 低资源占用:代码高效精简,适合资源受限的嵌入式系统
- 便捷宏定义:提供多种宏定义,简化库的使用
- 首先将
NN_Key.h和NN_Key.c添加到你的项目中 - 在项目中包含头文件:
#include "NN_Key.h" - 定义按键读取函数,用于读取按键的物理状态,例如:
bool Button1_Read(void)
{
// 返回按键的物理状态,按下为true,释放为false
// 这里根据实际硬件进行修改
return (HAL_GPIO_ReadPin(BUTTON1_GPIO_Port, BUTTON1_Pin) == GPIO_PIN_RESET);
}- 创建按键实例并添加到按键管理列表
nn_key_t key2;
NN_Key_Add(&key2, "KEY2", Button2_Read);- 注册按键事件回调函数
// 定义回调函数
NN_KEY_CALLBACK(OnKey1Click)
{
printf("按键 %s 被单击\n", key->key_id);
}
// 注册回调
NN_Key_OnClick(key1, OnKey1Click, NULL);- 在主循环中周期性调用按键处理函数
uint32_t currentTick;
while (1)
{
currentTick = HAL_GetTick(); // 获取系统时钟
NN_Key_Handler(currentTick); // 调用按键处理函数
}bool NN_Key_Init(nn_key_t *key, const char *name, nn_key_read_t pfunc);功能:初始化按键结构体
参数:
key: 按键结构体指针name: 按键名称标识符pfunc: 按键读取函数,返回按键物理状态(true为按下)
返回值:初始化是否成功
示例:
nn_key_t myKey;
NN_Key_Init(&myKey, "Button1", Button1_Read);bool NN_Key_Add(nn_key_t *key, const char *id, nn_key_read_t read_func);功能:初始化按键并添加到全局管理列表,推荐使用此函数
参数:
key: 按键结构体指针id: 按键名称标识符read_func: 按键读取函数
返回值:添加是否成功
示例:
nn_key_t myKey;
NN_Key_Add(&myKey, "Button1", Button1_Read);bool NN_Key_SetPara(nn_key_t *key,
uint16_t debounce_time,
uint16_t long_time,
uint16_t long_alws_time,
uint16_t multi_time,
uint8_t multi_max);功能:设置按键参数
参数:
key: 按键结构体指针debounce_time: 消抖时间(ms),传入0表示不修改long_time: 长按时间(ms),传入0表示不修改long_alws_time: 持续长按时间(ms),传入0表示不修改multi_time: 连按间隔时间(ms),传入0表示不修改multi_max: 最大连按次数,传入0表示不修改
返回值:设置是否成功
示例:
// 设置按键消抖时间为30ms,长按时间为800ms
NN_Key_SetPara(&myKey, 30, 800, 0, 0, 0);bool NN_Key_Handler(uint32_t tick);功能:按键处理函数,需要在主循环中周期性调用
参数:
tick: 当前系统时钟值(ms)
返回值:处理是否成功
示例:
// 在主循环中调用
while (1)
{
uint32_t currentTick = HAL_GetTick();
NN_Key_Handler(currentTick);
}bool NN_Key_SetCb(nn_key_t *key, nn_key_event_t event, nn_key_callback_t cb, void *user_data);功能:设置按键事件回调函数
参数:
key: 按键结构体指针event: 事件类型,可以是以下值之一:KEY_EVENT_PRESSED: 单击事件KEY_EVENT_LONG_PRESSED: 长按事件KEY_EVENT_LONG_PRESSED_ALWS: 持续长按事件KEY_EVENT_DOUBLE_PRESSED: 双击事件KEY_EVENT_TRIPLE_PRESSED: 三击事件KEY_EVENT_MULTI_PRESSED: 多击事件(超过三次)
cb: 回调函数user_data: 用户数据指针,会传递给回调函数,如果不需要可以传入"NULL"
返回值:设置是否成功
示例:
// 定义回调函数
void OnButtonClick(nn_key_t *key, nn_key_event_t event, void *user_data)
{
printf("按键 %s 被点击\n", key->key_id);
}
// 设置单击回调
NN_Key_SetCb(&myKey, KEY_EVENT_PRESSED, OnButtonClick, NULL);bool NN_Key_DeleteCb(nn_key_t *key, nn_key_event_t event);功能:删除按键事件回调函数
参数:
key: 按键结构体指针event: 事件类型
返回值:删除是否成功
示例:
// 删除单击回调
NN_Key_DeleteCb(&myKey, KEY_EVENT_PRESSED);bool NN_Combo_Add(nn_comb_t *comb, const char *id, uint8_t mem_nbr, nn_key_t *member1, nn_key_t *member2, ...);功能:添加组合键
参数:
comb: 组合键结构体指针id: 组合键名称标识符mem_nbr: 组合键成员数量member1: 第一个成员按键member2: 第二个成员按键...: 可变参数,其他成员按键
返回值:添加是否成功
示例:
// 创建一个两键组合
nn_comb_t myComb;
NN_Combo_Add(&myComb, "Combo1", 2, &key1, &key2);
// 创建一个三键组合
nn_comb_t myComb2;
NN_Combo_Add(&myComb2, "Combo2", 3, &key1, &key2, &key3);bool NN_Combo_SetCb(nn_comb_t *combo, nn_comb_callback_t cb, void *para);功能:设置组合键回调函数
参数:
combo: 组合键结构体指针cb: 组合键回调函数para: 用户数据指针
返回值:设置是否成功
示例:
// 定义组合键回调函数
void OnComboTriggered(nn_comb_t *comb, void *user_data)
{
printf("组合键 %s 被触发\n", comb->combo_id);
}
// 设置回调
NN_Combo_SetCb(&myComb, OnComboTriggered, NULL);bool NN_Combo_SetWindowTime(nn_comb_t *combo, uint16_t time_ms);功能:设置组合键窗口时间,即所有成员按键必须在这个时间内被按下才触发组合键
参数:
combo: 组合键结构体指针time_ms: 窗口时间(ms)
返回值:设置是否成功
示例:
// 设置组合键窗口时间为500ms
NN_Combo_SetWindowTime(&myComb, 500);库提供了多种便捷宏定义,用于简化按键库的使用:
// 仅设置按键消抖时间
NN_Key_SetDebounceTime(key, time)
// 仅设置按键长按时间
NN_Key_SetLongPressTime(key, time)
// 仅设置按键持续长按时间
NN_Key_SetLongPressAlwsTime(key, time)
// 仅设置按键连按间隔时间
NN_Key_SetMultiPressTime(key, time)
// 仅设置按键最大连按次数
NN_Key_SetMultiPressMax(key, max)// 简化按键回调函数定义
NN_KEY_CALLBACK(func_name) { /* 处理逻辑 */ }
// 简化组合键回调函数定义
NN_COMB_CALLBACK(func_name) { /* 处理逻辑 */ }// 快速注册单击事件回调
NN_Key_OnClick(key, cb, user_data)
// 快速注册双击事件回调
NN_Key_OnDoubleClick(key, cb, user_data)
// 快速注册三击事件回调
NN_Key_OnTripleClick(key, cb, user_data)
// 快速注册多击事件回调
NN_Key_OnMultiClick(key, cb, user_data)
// 快速注册长按事件回调
NN_Key_OnLongPress(key, cb, user_data)
// 快速注册持续长按事件回调
NN_Key_OnContinuousPress(key, cb, user_data)#include "NN_Key.h"
// 按键读取函数
bool Button1_Read(void)
{
return (HAL_GPIO_ReadPin(BUTTON1_GPIO_Port, BUTTON1_Pin) == GPIO_PIN_RESET);
}
// 单击回调函数
NN_KEY_CALLBACK(OnButton1Click)
{
printf("按键 %s 被单击\n", key->key_id);
// 可以通过user_data访问用户数据
if (user_data) {
int *count = (int*)user_data;
(*count)++;
printf("点击次数: %d\n", *count);
}
}
int main(void)
{
// 系统初始化代码省略...
// 创建按键
nn_key_t *button1;
static int clickCount = 0;
// 使用宏创建按键
NN_Key_Create(button1, "Button1", Button1_Read);
// 设置消抖时间
NN_Key_SetDebounceTime(button1, 30);
// 注册单击回调
NN_Key_OnClick(button1, OnButton1Click, &clickCount);
// 主循环
while (1)
{
uint32_t currentTick = HAL_GetTick();
NN_Key_Handler(currentTick);
}
}#include "NN_Key.h"
// 按键读取函数
bool Button1_Read(void) { /* 读取实现 */ }
// 各种回调函数
NN_KEY_CALLBACK(OnSingleClick) { printf("单击\n"); }
NN_KEY_CALLBACK(OnDoubleClick) { printf("双击\n"); }
NN_KEY_CALLBACK(OnTripleClick) { printf("三击\n"); }
NN_KEY_CALLBACK(OnLongPress) { printf("长按\n"); }
NN_KEY_CALLBACK(OnContinuousPress) { printf("持续长按中...\n"); }
int main(void)
{
// 创建按键
nn_key_t *button;
NN_Key_Create(button, "MultiButton", Button1_Read);
// 设置按键参数
NN_Key_SetPara(button, 20, 800, 2000, 300, 5);
// 注册各类事件回调
NN_Key_OnClick(button, OnSingleClick, NULL);
NN_Key_OnDoubleClick(button, OnDoubleClick, NULL);
NN_Key_OnTripleClick(button, OnTripleClick, NULL);
NN_Key_OnLongPress(button, OnLongPress, NULL);
NN_Key_OnContinuousPress(button, OnContinuousPress, NULL);
// 主循环
while (1)
{
NN_Key_Handler(HAL_GetTick());
HAL_Delay(10);
}
}#include "NN_Key.h"
// 按键读取函数
bool Key1_Read(void) { /* 实现 */ }
bool Key2_Read(void) { /* 实现 */ }
bool Key3_Read(void) { /* 实现 */ }
// 组合键回调
NN_COMB_CALLBACK(OnCombo12Triggered)
{
printf("按键组合 %s 被触发\n", comb->combo_id);
}
// 三键组合回调
NN_COMB_CALLBACK(OnCombo123Triggered)
{
printf("三键组合 %s 被触发\n", comb->combo_id);
}
int main(void)
{
// 创建三个按键
nn_key_t *key1, *key2, *key3;
NN_Key_Create(key1, "Key1", Key1_Read);
NN_Key_Create(key2, "Key2", Key2_Read);
NN_Key_Create(key3, "Key3", Key3_Read);
// 创建两键组合
nn_comb_t *combo12;
NN_Combo_Add(combo12, "Combo12", 2, key1, key2);
NN_Combo_SetCb(combo12, OnCombo12Triggered, NULL);
// 创建三键组合
nn_comb_t *combo123;
NN_Combo_Add(combo123, "Combo123", 3, key1, key2, key3);
NN_Combo_SetCb(combo123, OnCombo123Triggered, NULL);
// 设置组合键窗口时间
NN_Combo_SetWindowTime(combo12, 400); // 400ms窗口
NN_Combo_SetWindowTime(combo123, 600); // 600ms窗口
// 主循环
while (1)
{
NN_Key_Handler(HAL_GetTick());
HAL_Delay(10);
}
}-
调用频率:NN_Key_Handler函数建议以不低于10ms的频率调用,以确保按键状态能够被及时检测。
-
回调函数执行时间:回调函数中应避免长时间执行或阻塞操作,以防影响按键库的正常工作。
-
按键读取函数:确保按键读取函数返回正确的物理状态(按下为true,释放为false)。如果硬件接口的逻辑与此相反,需要在读取函数中进行逻辑翻转。
-
组合键限制:组合键成员最多支持4个按键,且这些按键必须在窗口时间内被按下才能触发组合键事件。
-
资源使用:库内部维护了按键和组合键的全局列表,默认支持最多20个按键和20个组合键,可通过修改头文件中的宏定义进行调整。
-
线程安全性:本库设计用于单线程环境,如在多线程环境下使用,需考虑线程同步问题。