# MultiButton **Repository Path**: a_just_do_it_admin/multi-button ## Basic Information - **Project Name**: MultiButton - **Description**: 中文注释并修复相关问题。 button是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。 - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2023-09-02 - **Last Updated**: 2023-09-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MultiButton ## 简介 button是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。 由github上0x1abin的MultButton稍作修改得到此代码。 原作者网站:https://github.com/0x1abin/MultiButton 原按键驱动代码问题: 1、在初始化时结构体中的button_level变量直接由读取电平接口赋值,可能会导致上电瞬间误读电平,从而导致误触发事件 2、按键连按两下,并在第二次按下时按住不放,会额外触发一次按下事件 3、在按键进行连击事件驱动时,因结构体中repeat变量可能会溢出,而误触发单双击事件 4、在进行双击事件时会触发一次连击事件(此问题可忽略) 本代码修复上面的问题。 可根据需要自行在代码中添加三击、四击...(注:需修改源代码) ## 使用方法(有两种,通过在头文件中修改宏定义MALLOC更改使用) ### 一、静态内存分配(MALLOC 1) 1、先申请一个按键结构体 ```c struct Button button1; ``` 2、初始化按键对象,绑定按键的GPIO电平读取接口**read_button_pin()** ,有效触发电平,电平读取接口id ```c button_init(&button1, read_button_pin, 0, 0); ``` 3、注册按键事件 ```c button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler); button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler); ... ``` 4、启动按键 ```c button_start(&button1); ``` 5、设置一个5ms间隔的定时器循环调用后台处理函数 ```c while(1) { ... if(timer_ticks == 5) { timer_ticks = 0; button_ticks(); } } ``` 6、如按键不使用可退出 ```c button_stop(&button1); ``` ### 示例 注册两个按键button1和button2 ```c #include "button.h" struct Button button1; struct Button button2; uint8_t read_button_pin(uint8_t button_id) { switch(button_id) { case 0: return HAL_GPIO_ReadPin(GPIO_Port, Pin_1); break; case 1: return HAL_GPIO_ReadPin(GPIO_Port, Pin_2); break; default: return 0; } } void BTN1_PRESS_DOWN_Handler(void* btn) { //do something... } void BTN1_PRESS_UP_Handler(void* btn) { //do something... } ... void BTN2_CALLBACK_Handler(void* btn) { Button* handle = (Button*)btn; switch(handle->event) { case PRESS_DOWN: //do something... break; case DOUBLE_CLICK: //do something... break; //... default:break; } } int main() { /*button1示例,单个按键事件数少时适用*/ button_init(&button1, read_button_GPIO, 0, 0);//初始化button1 button_attach(&button1, PRESS_DOWN, BTN1_PRESS_DOWN_Handler); //按下触发事件注册 button_attach(&button1, PRESS_UP, BTN1_PRESS_UP_Handler); //弹起事件注册 ... button_start(&button1);//启动button1 /*button2示例,单个按键事件数多时适用*/ button_init(&button2, read_button_GPIO, 0, 1);//初始化button2 button_attach(&button2, PRESS_DOWN, BTN2_CALLBACK_Handler);//按下触发事件注册 button_attach(&button2, PRESS_UP, BTN2_CALLBACK_Handler);//弹起事件注册 ... button_start(&button2);//启动button2 while(1) { button_ticks();//5ms循环调用 delay_ms(5);//此处用延时函数演示,实际使用可自行使用定时器 } } ``` ### 二、动态内存分配(MALLOC 0) 1、先申请一个按键结构体指针 ```c struct Button *button1; ``` 2、初始化按键对象,与静态内存分配大致相同,此处函数初始化后会为button1动态分配内存空间 ```c button_init(&button1,...); ``` 接下来流程与静态内存分配大致相同。 注:如此处按键不使用,则需要释放内存 ```c button_free(&button1);//释放内存前会先检查是否存在工作链表中,如存在则先退出 ```