diff --git a/README.md b/README.md index c74d19b..2cd542c 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,37 @@ # MultiButton ## 简介 + MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。 ## 使用方法 + 1.先申请一个按键结构 ```c struct Button button1; ``` + 2.初始化按键对象,绑定按键的GPIO电平读取接口**read_button_pin()** ,后一个参数设置有效触发电平 ```c -button_init(&button1, read_button_pin, 0, 0); +button_init(&button1, read_button_pin, 0); ``` + 3.注册按键事件 ```c -button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler); -button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler); +button_attach(&button1, SINGLE_CLICK, BTN_EVENT_Handler); +button_attach(&button1, DOUBLE_CLICK, BTN_EVENT_Handler); ... ``` + 4.启动按键 ```c button_start(&button1); ``` + 5.设置一个5ms间隔的定时器循环调用后台处理函数 ```c @@ -52,82 +58,203 @@ struct Button { uint8_t debounce_cnt : 3; uint8_t active_level : 1; uint8_t button_level : 1; - uint8_t button_id; - uint8_t (*hal_button_Level)(uint8_t button_id_); + uint8_t (*hal_button_Level)(void); BtnCallback cb[number_of_event]; struct Button* next; }; ``` -这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。 +这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。 ## 按键事件 -事件 | 说明 ----|--- -PRESS_DOWN | 按键按下,每次按下都触发 -PRESS_UP | 按键弹起,每次松开都触发 -PRESS_REPEAT | 重复按下触发,变量repeat计数连击次数 -SINGLE_CLICK | 单击按键事件 -DOUBLE_CLICK | 双击按键事件 -LONG_PRESS_START | 达到长按时间阈值时触发一次 -LONG_PRESS_HOLD | 长按期间一直触发 - +| 事件 | 说明 | +| ---------------- | ------------------------------------ | +| PRESS_DOWN | 按键按下,每次按下都触发 | +| PRESS_UP | 按键弹起,每次松开都触发 | +| PRESS_REPEAT | 重复按下触发,变量repeat计数连击次数 | +| SINGLE_CLICK | 单击按键事件 | +| DOUBLE_CLICK | 双击按键事件 | +| LONG_PRESS_START | 达到长按时间阈值时触发一次 | +| LONG_PRESS_HOLD | 长按期间一直触发 | ## Examples ```c -#include "button.h" +#include "multi_button.h" -unit8_t btn1_id = 0; +typedef enum { + BUTTON_ID_0, + BUTTON_ID_2, -struct Button btn1; + BUTTON_ID_MAX -uint8_t read_button_GPIO(uint8_t button_id) +} BUTTON_ID_INDEX; + +struct Button btnGroup[BUTTON_ID_MAX]; +uint8_t btnActiveLevel[BUTTON_ID_MAX] = {0, 0}; + +uint8_t read_button_level() { - // you can share the GPIO read function with multiple Buttons - switch(button_id) + uint8_t code = 0x01; + for (size_t i = 0; i < BUTTON_ID_MAX; i++) { - case btn1_id: - return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin); - break; + if (get_button_current() == &btnGroup[i]) + { + switch (i) + { + case BUTTON_ID_0: + code = HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin); + break; + case BUTTON_ID_2: + code = HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin); + break; - default: - return 0; - break; + default: + break; + } + } } -} -void BTN1_PRESS_DOWN_Handler(void* btn) -{ - //do something... + return code; } -void BTN1_PRESS_UP_Handler(void* btn) +void BTN_EVENT_Handler(void *btn) { - //do something... -} + for (size_t i = 0; i < BUTTON_ID_MAX; i++) + { + if (((Button *)btn) == &btnGroup[i]) + { + switch (((Button *)btn)->event) + { + case PRESS_DOWN: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; -... + default: + break; + } + break; + case PRESS_UP: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case PRESS_REPEAT: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case SINGLE_CLICK: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case DOUBLE_CLICK: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case LONG_PRESS_START: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case LONG_PRESS_HOLD: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + + default: + break; + } + } + } +} int main() { - button_init(&btn1, read_button_GPIO, 0, btn1_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(&btn2, LONG_PRESS_HOLD, BTN1_LONG_PRESS_HOLD_Handler); - button_start(&btn1); - - //make the timer invoking the button_ticks() interval 5ms. - //This function is implemented by yourself. + for (size_t i = 0; i < BUTTON_ID_MAX; i++) + { + button_init(&btnGroup[i], read_button_level, btnActiveLevel[i]); + + button_attach(&btnGroup[i], PRESS_DOWN, BTN_EVENT_Handler); + button_attach(&btnGroup[i], PRESS_UP, BTN_EVENT_Handler); + button_attach(&btnGroup[i], PRESS_REPEAT, BTN_EVENT_Handler); + button_attach(&btnGroup[i], SINGLE_CLICK, BTN_EVENT_Handler); + button_attach(&btnGroup[i], DOUBLE_CLICK, BTN_EVENT_Handler); + button_attach(&btnGroup[i], LONG_PRESS_START, BTN_EVENT_Handler); + button_attach(&btnGroup[i], LONG_PRESS_HOLD, BTN_EVENT_Handler); + + button_start(&btnGroup[i]); + } + + // make the timer invoking the button_ticks() interval 5ms. + // This function is implemented by yourself. __timer_start(button_ticks, 0, 5); - while(1) - {} + while (1) + { + } } ``` - - diff --git a/examples/example_callback.c b/examples/example_callback.c index 99ffff2..ce6e392 100644 --- a/examples/example_callback.c +++ b/examples/example_callback.c @@ -1,65 +1,176 @@ #include "multi_button.h" -enum Button_IDs { - btn1_id, - btn2_id, -}; +typedef enum { + BUTTON_ID_0, + BUTTON_ID_2, -struct Button btn1; -struct Button btn2; + BUTTON_ID_MAX -uint8_t read_button_GPIO(uint8_t button_id) +} BUTTON_ID_INDEX; + +struct Button btnGroup[BUTTON_ID_MAX]; +uint8_t btnActiveLevel[BUTTON_ID_MAX] = {0, 0}; + +uint8_t read_button_level() { - // you can share the GPIO read function with multiple Buttons - switch(button_id) + uint8_t code = 0x01; + for (size_t i = 0; i < BUTTON_ID_MAX; i++) { - 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; + if (get_button_current() == &btnGroup[i]) + { + switch (i) + { + case BUTTON_ID_0: + code = HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin); + break; + case BUTTON_ID_2: + code = HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin); + break; + + default: + break; + } + } } + return code; } -int main() +void BTN_EVENT_Handler(void *btn) { - 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); + for (size_t i = 0; i < BUTTON_ID_MAX; i++) + { + if (((Button *)btn) == &btnGroup[i]) + { + switch (((Button *)btn)->event) + { + case PRESS_DOWN: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; - while(1) - {} -} + default: + break; + } + break; + case PRESS_UP: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; -void BTN1_PRESS_DOWN_Handler(void* btn) -{ - //do something... + default: + break; + } + break; + case PRESS_REPEAT: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case SINGLE_CLICK: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case DOUBLE_CLICK: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case LONG_PRESS_START: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + case LONG_PRESS_HOLD: + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + break; + + default: + break; + } + } + } } -void BTN1_PRESS_UP_Handler(void* btn) +int main() { - //do something... -} + for (size_t i = 0; i < BUTTON_ID_MAX; i++) + { + button_init(&btnGroup[i], read_button_level, btnActiveLevel[i]); + + button_attach(&btnGroup[i], PRESS_DOWN, BTN_EVENT_Handler); + button_attach(&btnGroup[i], PRESS_UP, BTN_EVENT_Handler); + button_attach(&btnGroup[i], PRESS_REPEAT, BTN_EVENT_Handler); + button_attach(&btnGroup[i], SINGLE_CLICK, BTN_EVENT_Handler); + button_attach(&btnGroup[i], DOUBLE_CLICK, BTN_EVENT_Handler); + button_attach(&btnGroup[i], LONG_PRESS_START, BTN_EVENT_Handler); + button_attach(&btnGroup[i], LONG_PRESS_HOLD, BTN_EVENT_Handler); + + button_start(&btnGroup[i]); + } + + // make the timer invoking the button_ticks() interval 5ms. + // This function is implemented by yourself. + __timer_start(button_ticks, 0, 5); + + while (1) + { + } +} \ No newline at end of file diff --git a/examples/example_poll.c b/examples/example_poll.c index eb06029..1e9b6f3 100644 --- a/examples/example_poll.c +++ b/examples/example_poll.c @@ -1,43 +1,108 @@ #include "multi_button.h" -unit8_t btn1_id = 0; -struct Button btn1; +typedef enum { + BUTTON_ID_0, + BUTTON_ID_2, -uint8_t read_button_GPIO(uint8_t button_id) + BUTTON_ID_MAX + +} BUTTON_ID_INDEX; + +struct Button btnGroup[BUTTON_ID_MAX]; +uint8_t btnActiveLevel[BUTTON_ID_MAX] = {0, 0}; + +uint8_t read_button_level() { - // you can share the GPIO read function with multiple Buttons - switch(button_id) + uint8_t code = 0x01; + for (size_t i = 0; i < BUTTON_ID_MAX; i++) { - case btn1_id: - return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin); - default: - return 0; + if (get_button_current() == &btnGroup[i]) + { + switch (i) + { + case BUTTON_ID_0: + code = HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin); + break; + case BUTTON_ID_2: + code = HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin); + break; + + default: + break; + } + } } + return code; } - int main() { - static uint8_t btn1_event_val; + static uint8_t btn_event_val[BUTTON_ID_MAX] = {NONE_PRESS, NONE_PRESS}; - button_init(&btn1, read_button_GPIO, 0, btn1_id); - button_start(&btn1); + for (size_t i = 0; i < BUTTON_ID_MAX; i++) + { + button_init(&btnGroup[i], read_button_level, btnActiveLevel[i]); + + button_start(&btnGroup[i]); + } - //make the timer invoking the button_ticks() interval 5ms. - //This function is implemented by yourself. + // make the timer invoking the button_ticks() interval 5ms. + // This function is implemented by yourself. __timer_start(button_ticks, 0, 5); - while(1) + while (1) { - if(btn1_event_val != get_button_event(&btn1)) { - btn1_event_val = get_button_event(&btn1); - - if(btn1_event_val == PRESS_DOWN) { - //do something - } else if(btn1_event_val == PRESS_UP) { - //do something - } else if(btn1_event_val == LONG_PRESS_HOLD) { - //do something + for (size_t i = 0; i < BUTTON_ID_MAX; i++) + { + if (btn_event_val[i] != get_button_event(&btnGroup[i])) + { + btn_event_val[i] = get_button_event(&btnGroup[i]); + + if (btn_event_val[i] == PRESS_DOWN) + { + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + } + else if (btn_event_val[i] == PRESS_UP) + { + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + } + else if (btn_event_val[i] == LONG_PRESS_HOLD) + { + switch (i) + { + case BUTTON_ID_0: + // do something + break; + case BUTTON_ID_2: + // do something + break; + + default: + break; + } + } } } } diff --git a/multi_button.c b/multi_button.c index 1061e68..e091b54 100644 --- a/multi_button.c +++ b/multi_button.c @@ -10,22 +10,22 @@ //button handle list head. static struct Button* head_handle = NULL; +//button handle list head. +static struct Button* cur_handle = NULL; /** * @brief Initializes the button struct handle. * @param handle: the button handle strcut. * @param pin_level: read the HAL GPIO of the connet button level. * @param active_level: pressed GPIO level. - * @param button_id: the button id. * @retval None */ -void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level, uint8_t button_id) +void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level) { memset(handle, 0, sizeof(struct Button)); handle->event = (uint8_t)NONE_PRESS; handle->hal_button_Level = pin_level; - handle->button_level = handle->hal_button_Level(button_id); + handle->button_level = handle->hal_button_Level(); handle->active_level = active_level; - handle->button_id = button_id; } /** @@ -50,6 +50,15 @@ PressEvent get_button_event(struct Button* handle) return (PressEvent)(handle->event); } +/** + * @brief Inquire the button handle used. + * @retval button handler. + */ +Button* get_button_current(void) +{ + return cur_handle; +} + /** * @brief Button driver core function, driver state machine. * @param handle: the button handle strcut. @@ -57,7 +66,8 @@ PressEvent get_button_event(struct Button* handle) */ void button_handler(struct Button* handle) { - uint8_t read_gpio_level = handle->hal_button_Level(handle->button_id); + uint8_t read_gpio_level = handle->hal_button_Level(); + cur_handle = handle; //ticks counter working.. if((handle->state) > 0) handle->ticks++; @@ -148,9 +158,6 @@ void button_handler(struct Button* handle) handle->state = 0; //reset } break; - default: - handle->state = 0; //reset - break; } } @@ -202,3 +209,4 @@ void button_ticks() button_handler(target); } } + diff --git a/multi_button.h b/multi_button.h index b066ade..f64bc82 100644 --- a/multi_button.h +++ b/multi_button.h @@ -38,8 +38,7 @@ typedef struct Button { uint8_t debounce_cnt : 3; uint8_t active_level : 1; uint8_t button_level : 1; - uint8_t button_id; - uint8_t (*hal_button_Level)(uint8_t button_id_); + uint8_t (*hal_button_Level)(void); BtnCallback cb[number_of_event]; struct Button* next; }Button; @@ -48,9 +47,10 @@ typedef struct Button { extern "C" { #endif -void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level, uint8_t button_id); +void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level); void button_attach(struct Button* handle, PressEvent event, BtnCallback cb); PressEvent get_button_event(struct Button* handle); +Button* get_button_current(void); int button_start(struct Button* handle); void button_stop(struct Button* handle); void button_ticks(void);