GitHub开源按键状态机lwbtn
原项目地址:https://github.com/MaJerle/lwbtn
移植教程
第一步:找到lwbtn文件
点进这个文件夹,顺着点进去,就可以看到一共那么几个文件:
这几个就是接下来要移植的按键系统。
第二步:文件放入自己的工程
这里要注意的一个点:将 lwbtn_opts_template.h 文件改名为:lwbtn_opts.h 作为用户头文件,并且在keil中新建lwbtn_opts_use.c 文件作为用户.c文件,接下来我们就是要在这个俩个文件中编写我们所需要的函数。
结束以上操作后在keil中有那么几个文件:
第三步:了解各个文件的作用
lwbtn.c
大佬编写的按键状态机的各种状态库以及逻辑判断,这里用户不需要管,也不需要修改。
lwbtn.h
就是 lwbtn.c 状态库的头文件,用户也不需要管,不需要修改。
lwbtn_opt.h
包含按键各种事件的设置,有按下消抖、释放消抖、长按时间等等设置,用户可以在此修改宏定义来设置按键功能。
lwbtn_opts_use.c
用户编写函数的文件,在此增加按键处理函数等
lwbtn_opts.h
就是 lwbtn_opts_use.c 文件的头文件
第五步:在 lwbtn_opts_use.c 文件增加所需函数
点击查看代码
#include "lwbtn_opts.h"/*** @brief 全局变量,记录当前触发的按键编号* * - 0: 无按键* - 1: KEY0* - 2: KEY1* - 3: KEY2* - 4: KEY_UP* 必须要 lwbtn_keys = btn_index + 1; 以摆脱为0时的按键状态*/
uint8_t lwbtn_keys;/* 为每个按键定义GPIO参数 */
lwbtn_argdata_port_pin_state_t key0_gpio = {.port = KEY0_GPIO_Port, /* KEY0的GPIO端口 */.pin = KEY0_Pin, /* KEY0的GPIO引脚 */.state = 0 /* 低电平触发 */
};lwbtn_argdata_port_pin_state_t key1_gpio = {.port = KEY1_GPIO_Port, /* KEY1的GPIO端口 */.pin = KEY1_Pin, /* KEY1的GPIO引脚 */.state = 0 /* 低电平触发 */
};lwbtn_argdata_port_pin_state_t key2_gpio = {.port = KEY2_GPIO_Port, /* KEY2的GPIO端口 */.pin = KEY2_Pin, /* KEY2的GPIO引脚 */.state = 0 /* 低电平触发 */
};lwbtn_argdata_port_pin_state_t key_up_gpio = {.port = KEY_UP_GPIO_Port, /* KEY_UP的GPIO端口 */.pin = KEY_UP_Pin, /* KEY_UP的GPIO引脚 */.state = 1 /* 高电平触发 */
};/* 定义按钮数组,每个按钮绑定对应的GPIO参数 */
lwbtn_btn_t buttons[] = {{ .arg = &key0_gpio }, /* KEY0 */{ .arg = &key1_gpio }, /* KEY1 */{ .arg = &key2_gpio }, /* KEY2 */{ .arg = &key_up_gpio }, /* KEY_UP */
};/*** @brief 获取按钮的当前状态* * 通过读取GPIO引脚的电平,判断按钮是否处于激活状态。* * @param lwobj: LwBTN实例(未使用)* @param btn: 按钮实例,包含GPIO参数* @return uint8_t: 1表示按钮激活,0表示按钮未激活*/
uint8_t get_button_state(lwbtn_t* lwobj, lwbtn_btn_t* btn)
{lwbtn_argdata_port_pin_state_t* cfg = btn->arg;uint8_t pin_state = HAL_GPIO_ReadPin(cfg->port, cfg->pin);return (pin_state == cfg->state) ? 1 : 0; // 返回激活状态
}/*** @brief 按钮事件处理函数* * 根据LwBTN库触发的事件类型,处理按钮的按下、释放、单击、双击和长按事件。* * 每一个事件都会触发一个回调 ** * @param lwobj: LwBTN实例* @param btn: 触发事件的按钮实例* @param evt: 事件类型(按下、释放、单击、长按等)*/
void button_event_handler(lwbtn_t* lwobj, lwbtn_btn_t* btn, lwbtn_evt_t evt)
{// 根据按钮索引识别具体按键uint8_t btn_index = (btn - lwobj->btns);switch (evt) {/* 按键按下事件 */case LWBTN_EVT_ONPRESS:
// lwbtn_keys = btn_index + 1; // 记录按键编号break;/* 按键释放事件 */case LWBTN_EVT_ONRELEASE:
// lwbtn_keys = btn_index + 1; // 记录按键编号break;/* 单击/双击事件 */case LWBTN_EVT_ONCLICK:if (btn->click.cnt == 2) { /* 双击 */lwbtn_keys = btn_index + 1; // 记录按键编号btn->click.cnt = 0; // 重置计数器printf("按键%d 双击\r\n",lwbtn_keys);} else { /* 单击 */lwbtn_keys = btn_index + 1; // 记录按键编号printf("按键%d 单击\r\n",lwbtn_keys);}break;/* 长按事件 */case LWBTN_EVT_KEEPALIVE:lwbtn_keys = btn_index + 1; // 记录按键编号printf("按键%d 长按保持\n", lwbtn_keys);break;}
}/*** @brief 初始化按钮管理器* * 使用LwBTN库初始化按钮管理器,绑定按钮数组、状态读取函数和事件处理函数。*/
void button_init(void)
{lwbtn_init_ex(NULL, buttons, BUTTON_COUNT, get_button_state, button_event_handler);
}/*** @brief 处理按键状态* * 定期调用此函数以处理按键状态,触发事件回调。*/
void get_btn()
{uint32_t tick = 0;tick = HAL_GetTick(); // 获取当前系统时间lwbtn_process(tick); // 处理按键状态
}
第六步:在lwbtn_opts.h 文件增加说明
点击查看代码
#ifndef LWBTN_OPTS_H
#define LWBTN_OPTS_H/* 将此文件重命名为 "lwbtn_opts.h" 以适应您的应用程序 *//** 打开 "include/lwbtn/lwbtn_opt.h" 并* 复制并在此处替换您希望更改的设置值*/#include "main.h" // 此处修改为用户的主头文件#define BUTTON_COUNT (sizeof(buttons) / sizeof(buttons[0]))extern void button_init(void);
void get_btn();extern uint8_t lwbtn_keys;#endif /* LWBTN_OPTS_H */
第七步:主函数使用
点击查看代码
void main(void) {button_init();while(1) {get_btn(); // 持续获取按键值printf("%d\r\n", lwbtn_keys); // 打印出按下的按键if(lwbtn_keys == ??) {...}}
}
使用说明
在 button_event_handler 按钮事件处理函数中,按键按下分为:按下,释放;按下类型又分为:单击、双击、持续按下。
这每一个状态/事件,进行过后,其都会进行一次回调,即回到主函数一次,故也是分为了1、按下 2、释放 3、单击 4、双击 5、持续按下 五个回调状态。
你可以在 button_event_handler 函数中,switch 中,每 case 一个状态,就可以在此状态下执行某些操作
在本移植文件中,仅在按键单击和双击以及持续按下这三个状态中进行了 lwbtn_keys 变量赋值,并且打印当前状态。
目前测试得,同时按下四个按键,无论是单击、双击,还是持续按下,都有及其灵敏的反应,十分推荐使用!
源代码提供
包括原项目代码和我修改移植好的代码,下载链接:
超好用的开源按键状态系统lwbtn