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

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

博客导航

博客导航

posted @ 2025-03-18 20:16  膝盖中箭卫兵  阅读(1151)  评论(0)    收藏  举报
ORCID iD icon https://orcid.org/0000-0001-5102-772X