【STM32】超好用的开源按键状态系统lwbtn,以及超详细的移植教程

news/2025/3/18 20:16:54/文章来源:https://www.cnblogs.com/Skyrim-sssuuu/p/18779666

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/901087.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rp2040笔记[1]-使用embassy实现呼吸灯并通过命令行切换状态

使用rust的embassy在rp2040芯片核心板实现呼吸灯.摘要 使用rust的embassy在rp2040芯片核心板实现呼吸灯. 关键词 rust;embassy;rp2040;blink;pwm; 关键信息项目地址:[https://github.com/ByeIO/byeefree.rp2040_quad.embassy][package] edition = "2021" name = &quo…

014 登入页-Element-Plus的图标引入和使用

1、安装图标 2、使用 这里我们用全局注册的方法 放到这里 现在我们换一种方式 在src文件夹里面 新建文件夹global,都是一些全局的东西(这个就叫全局注册) 新建文件register-icons.ts (注册图标)这页这样写这段代码是使用 JavaScript(或可能是 TypeScript,从 app: any…

20242405 实验一《Python程序设计》实验报告

20242405 2024-2025-2 《Python程序设计》实验一报告 课程:《Python程序设计》 班级: 2424 姓名: 孙煜麟 学号:20242405 实验教师:王志强 实验日期:2025年3月12日 必修/选修: 公选课 1.实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能 3.编写程序,练习…

day:24 python——类的三大特性

python三大特性:封装,多态,继承 一、封装: 1、封装:封装就是隐藏对象一些不希望外部所访问到的属性和方法,保证安全 2、概念:指的是在设计时,不对外提供,隐藏起来,提供公共方法以外对其方法就是把属性和方法封装到一个抽象的类中, 3、封装相当于一个黑盒子,我们将事务相…

探秘Transformer系列之(15)--- 采样和输出

从零开始解析Transformer,目标是:(1) 解析Transformer如何运作,以及为何如此运作,让新同学可以入门;(2) 力争融入一些比较新的或者有特色的论文或者理念,让老鸟也可以有所收获。探秘Transformer系列之(15)--- 采样和输出 目录探秘Transformer系列之(15)--- 采样和输出…

c语言02_数据类型上

一、c是怎么变成汇编的 1、裸函数是编译器不管的 ⑴写一个空函数(里面什么都不写),f7f5打开反汇编f11打开jmp什么都没写里面还是有一大堆(是编译器和连接器做的)⑵裸函数f7f5查看反汇编找到调用的函数0040D708f11打开再f11打开,里面一行汇编代码都没有⑶ ①空函数 f7f5运…

win11家庭版24H2,使用VMware虚拟机问题

一、安装VMware,提示 “安装程序检测到主机启用了 Hyper-v或 Device/credential Guard。。。”,我勾选了自动安装WHP后点击下一步,完成了VMware的安装。二、解压了一个虚拟机,用VMware打开并选择已复制虚拟机,出现“此平台不支持虚拟化”的错误,点击“是”也无法打开虚拟…

M-LAG

一、M-LAG简介 1.1 M-LAG使用场景​ M-LAG(Multichassis Link Aggregation Group)即跨设备链路聚合组,是一种实现跨设备链路聚合的机制。M-LAG主要应用于普通以太网络、VXLAN和IP网络的双归接入,可以起到负载分担或备份保护的作用。相较于另一种常见的可靠性接入技术——堆…

FastAPI测试策略:参数解析单元测试

扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长 探索数千个预构建的 AI 应用,开启你的下一个伟大创意第一章:核心测试方法论 1.1 三层测试体系架构 # 第一层:模型级测试 def test_user_model_validation():with pytest.raises(ValidationError):User(age=-5)…

MSTP协议

一、MSTP(多生成树协议)简介 1.1 MSTP(多生成树协议)使用场景MSTP(Multiple Spanning Tree Protocol,IEEE 802.1s), 基于 RSTP 的多实例扩展协议,通过划分多个生成树实例(MSTI)实现 VLAN 与生成树的灵活映射,在保留 RSTP 快速收敛特性的基础上,支持 多拓扑负载均衡…

Eth-Trunk协议

一、Eth-Trunk(链路聚合协议)使用场景 1.1 Eth-Trunk(链路聚合协议)简介​ 原名叫链路聚合组(Link Aggregation Group),通过将多个物理接口捆绑为一个逻辑接口,可以在不进行硬件升级的条件下,达到增加链路带宽的目的。1.2 Eth-Trunk(链路聚合协议)实现目的增加带宽链…