开源按键库MultiButton
点击此连接下载
![](https://img-blog.csdnimg.cn/direct/99592bbe02754ed193c14c6773cce129.png)
按钮结构体
/* 声明一个按键结构体类型(链表) */
typedef struct Button {
uint16_t ticks; //系统节拍计数
uint8_t repeat : 4; //重复按键,双击、三击...
uint8_t event : 4; //事件
uint8_t state : 3; //状态
uint8_t debounce_cnt : 3; //去抖动次数
uint8_t active_level : 1; //有效电平
uint8_t button_level : 1; //按键电平
uint8_t button_id; //按键ID
uint8_t (*hal_button_Level)(uint8_t button_id_); //获取按键电平的函数指针
BtnCallback cb[number_of_event]; //按键回调函数指针数组(事件)
struct Button* next; //按键使用链表存储
}Button;
按钮事件驱动枚举
/* 声明一个按键事件的枚举类型,包括了所有的按键操作类型 */
typedef enum {
PRESS_DOWN = 0, //按下信号
PRESS_UP, //松开信号
PRESS_REPEAT, //重复按下计数,记按键连击数量
SINGLE_CLICK, //单击
DOUBLE_CLICK, //双击
LONG_PRESS_START, //长按达到阈值时触发
LONG_PRESS_HOLD, //长按一直触发
number_of_event, //事件
NONE_PRESS //无操作
}PressEvent;
第一步:按键初始化函数
/**
* @brief 初始化按键结构体变量handle
* @param handle: 按键结构体变量
* @param pin_level: 读取按键电平的函数(这里需要定义一个指定类型的函数来获取按键电平)
* @param active_level: 按键按下时的电平
* @param button_id: 自定义的按键ID
* @retval None
*/
//按键结构体初始化,赋予按键获取电平的函数指针,并读出当前电平
void button_init(struct Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id)
{
//结构体初始化为全0
memset(handle, 0, sizeof(struct Button));
//初始化为没有按键事件
handle->event = (uint8_t)NONE_PRESS;
//读取按键电平状态函数指针
handle->hal_button_Level = pin_level;
//读取按键电平
handle->button_level = !active_level;
//按下有效电平
handle->active_level = active_level;
//按键号
handle->button_id = button_id;
}
第二步:将当前按键与按键事件相关联
/**
* @brief Attach the button event callback function.
* @param handle: 定义的按键结构体
* @param event: 按键事件,想要一个按键触发多个事件时,可以多次调用该函数
* @param cb: 回调函数(需要人为定义)
* @retval None
*/
//按键注册(赋予特定的按键事件以回调函数)
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb)
{
handle->cb[event] = cb;
}
第三步:该按键已经初始化完成,下面需要将该按键加入到按键链表之中
/**
* @brief 将(Button*)handle 添加到链表头部
* @param handle: target handle struct.
* @retval 0: succeed. -1: already exist.
*/
/*启动一个按键,即新增一个按键结构体链表节点*/
int button_start(struct Button* handle)
{
struct Button* target = head_handle;
while(target) { //如果当前结构体已经在链表中存在,返回-1
if(target == handle) return -1; //already exist.
target = target->next;
}
handle->next = head_handle;
head_handle = handle;
return 0;
}
定时扫描链表
/**
* @brief background ticks, timer repeat invoking interval 5ms.
* 按键扫描,扫描时长由用户实现
* @param None.
* @retval None
*/
/*按键节拍,每一次节拍事件遍历按键列表中所有按键,调用驱动函数*/
void button_ticks(void)
{
struct Button* target;
for(target=head_handle; target; target=target->next) {
button_handler(target); //核心逻辑实现,按键回调事件在该函数中调用(满足条件)
}
}
代码调用:
#include "multi_button.h"
enum Button_IDs {
btn1_id,
btn2_id,
};
struct Button btn1;
struct Button btn2;
uint8_t read_button_GPIO(uint8_t button_id)
{
// you can share the GPIO read function with multiple Buttons
switch(button_id)
{
case btn1_id:
return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);
case btn2_id:
return HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin);
default:
return 0;
}
}
int main()
{
button_init(&btn1, read_button_GPIO, 0, btn1_id);
button_init(&btn2, read_button_GPIO, 0, btn2_id);
button_attach(&btn1, PRESS_DOWN, BTN1_PRESS_DOWN_Handler);
button_attach(&btn1, PRESS_UP, BTN1_PRESS_UP_Handler);
button_attach(&btn1, PRESS_REPEAT, BTN1_PRESS_REPEAT_Handler);
button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_Click_Handler);
button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_Click_Handler);
button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_PRESS_START_Handler);
button_attach(&btn1, LONG_PRESS_HOLD, BTN1_LONG_PRESS_HOLD_Handler);
button_attach(&btn2, PRESS_DOWN, BTN2_PRESS_DOWN_Handler);
button_attach(&btn2, PRESS_UP, BTN2_PRESS_UP_Handler);
button_attach(&btn2, PRESS_REPEAT, BTN2_PRESS_REPEAT_Handler);
button_attach(&btn2, SINGLE_CLICK, BTN2_SINGLE_Click_Handler);
button_attach(&btn2, DOUBLE_CLICK, BTN2_DOUBLE_Click_Handler);
button_attach(&btn2, LONG_PRESS_START, BTN2_LONG_PRESS_START_Handler);
button_attach(&btn2, LONG_PRESS_HOLD, BTN2_LONG_PRESS_HOLD_Handler);
button_start(&btn1);
button_start(&btn2);
//make the timer invoking the button_ticks() interval 5ms.
//This function is implemented by yourself.
__timer_start(button_ticks, 0, 5);
while(1)
{}
}
void BTN1_PRESS_DOWN_Handler(void* btn)
{
//do something...
}
void BTN1_PRESS_UP_Handler(void* btn)
{
//do something...
}