MultiButton
使用方法
1.先申请一个按键结构
struct Button button1;
2.初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平
button_init(&button1, read_button_pin, 0);
3.注册按键事件
button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler);
button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler);
...
4.启动按键
button_start(&button1);
5.设置一个5ms间隔的定时器循环调用后台处理函数
while(1) {
...
if(timer_ticks == 5) {
timer_ticks = 0;
button_ticks();
}
}
特性
MultiButton 使用C语言实现,基于面向对象方式设计思路,每个按键对象单独用一份数据结构管理:
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 (*hal_button_Level)(void);
BtnCallback cb[number_of_event];
struct Button* next;
};
这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。
按键事件
| 事件 | 说明 |
|---|---|
| PRESS_DOWN | 按键按下,每次按下都触发 |
| PRESS_UP | 按键弹起,每次松开都触发 |
| PRESS_REPEAT | 重复按下触发,变量repeat计数连击次数 |
| SINGLE_CLICK | 单击按键事件 |
| DOUBLE_CLICK | 双击按键事件 |
| LONG_RRESS_START | 达到长按时间阈值时触发一次 |
| LONG_PRESS_HOLD | 长按期间一直触发 |
Examples
#include "button.h"
struct Button btn1;
int read_button1_GPIO()
{
return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);
}
int main()
{
button_init(&btn1, read_button1_GPIO, 0);
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_RRESS_START, BTN1_LONG_RRESS_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.
__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...
}
...
代码:
两个example
event_async.c
1 #include "multi_button.h" 2 3 struct Button btn1; 4 struct Button btn2; 5 6 int read_button1_GPIO() 7 { 8 return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin); 9 } 10 11 int read_button2_GPIO() 12 { 13 return HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin); 14 } 15 16 int main() 17 { 18 button_init(&btn1, read_button1_GPIO, 0); 19 button_init(&btn2, read_button2_GPIO, 0); 20 21 button_attach(&btn1, PRESS_DOWN, BTN1_PRESS_DOWN_Handler); 22 button_attach(&btn1, PRESS_UP, BTN1_PRESS_UP_Handler); 23 button_attach(&btn1, PRESS_REPEAT, BTN1_PRESS_REPEAT_Handler); 24 button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_Click_Handler); 25 button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_Click_Handler); 26 button_attach(&btn1, LONG_RRESS_START, BTN1_LONG_RRESS_START_Handler); 27 button_attach(&btn2, LONG_PRESS_HOLD, BTN1_LONG_PRESS_HOLD_Handler); 28 29 button_attach(&btn2, PRESS_DOWN, BTN2_PRESS_DOWN_Handler); 30 button_attach(&btn2, PRESS_UP, BTN2_PRESS_UP_Handler); 31 button_attach(&btn2, PRESS_REPEAT, BTN2_PRESS_REPEAT_Handler); 32 button_attach(&btn2, SINGLE_CLICK, BTN2_SINGLE_Click_Handler); 33 button_attach(&btn2, DOUBLE_CLICK, BTN2_DOUBLE_Click_Handler); 34 button_attach(&btn2, LONG_RRESS_START, BTN2_LONG_RRESS_START_Handler); 35 button_attach(&btn2, LONG_PRESS_HOLD, BTN2_LONG_PRESS_HOLD_Handler); 36 37 button_start(&btn1); 38 button_start(&btn2); 39 40 //make the timer invoking the button_ticks() interval 5ms. 41 //This function is implemented by yourself. 42 __timer_start(button_ticks, 0, 5); 43 44 while(1) 45 {} 46 } 47 48 void BTN1_PRESS_DOWN_Handler(void* btn) 49 { 50 //do something... 51 } 52 53 void BTN1_PRESS_UP_Handler(void* btn) 54 { 55 //do something... 56 } 57 58 ...
event_inquire.c
1 #include "multi_button.h" 2 3 struct Button btn1; 4 5 int read_button1_GPIO() 6 { 7 return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin); 8 } 9 10 11 int main() 12 { 13 static uint8_t btn1_event_val; 14 15 button_init(&btn1, read_button1_GPIO, 0); 16 button_start(&btn1); 17 18 //make the timer invoking the button_ticks() interval 5ms. 19 //This function is implemented by yourself. 20 __timer_start(button_ticks, 0, 5); 21 22 while(1) 23 { 24 if(btn1_event_val != get_button_event(&btn1)) { 25 btn1_event_val = get_button_event(&btn1); 26 27 if(btn1_event_val == PRESS_DOWN) { 28 //do something 29 } else if(btn1_event_val == PRESS_UP) { 30 //do something 31 } else if(btn1_event_val == LONG_PRESS_HOLD) { 32 //do something 33 } 34 } 35 } 36 }
...
1 /* 2 * Copyright (c) 2016 Zibin Zheng <znbin@qq.com> 3 * All rights reserved 4 */ 5 6 #ifndef _MULTI_BUTTON_H_ 7 #define _MULTI_BUTTON_H_ 8 9 #include "stdint.h" 10 #include "string.h" 11 12 //According to your need to modify the constants. 13 #define TICKS_INTERVAL 5 //ms 14 #define DEBOUNCE_TICKS 3 //MAX 8 15 #define SHORT_TICKS (300 /TICKS_INTERVAL) 16 #define LONG_TICKS (1000 /TICKS_INTERVAL) 17 18 19 typedef void (*BtnCallback)(void*); 20 21 typedef enum { 22 PRESS_DOWN = 0, 23 PRESS_UP, 24 PRESS_REPEAT, 25 SINGLE_CLICK, 26 DOUBLE_CLICK, 27 LONG_RRESS_START, 28 LONG_PRESS_HOLD, 29 number_of_event, 30 NONE_PRESS 31 }PressEvent; 32 33 typedef struct Button { 34 uint16_t ticks; 35 uint8_t repeat : 4; 36 uint8_t event : 4; 37 uint8_t state : 3; 38 uint8_t debounce_cnt : 3; 39 uint8_t active_level : 1; 40 uint8_t button_level : 1; 41 uint8_t (*hal_button_Level)(void); 42 BtnCallback cb[number_of_event]; 43 struct Button* next; 44 }Button; 45 46 #ifdef __cplusplus 47 extern "C" { 48 #endif 49 50 void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level); 51 void button_attach(struct Button* handle, PressEvent event, BtnCallback cb); 52 PressEvent get_button_event(struct Button* handle); 53 int button_start(struct Button* handle); 54 void button_stop(struct Button* handle); 55 void button_ticks(void); 56 57 #ifdef __cplusplus 58 } 59 #endif 60 61 #endif
....
1 /* 2 * Copyright (c) 2016 Zibin Zheng <znbin@qq.com> 3 * All rights reserved 4 */ 5 6 #include "multi_button.h" 7 8 #define EVENT_CB(ev) if(handle->cb[ev])handle->cb[ev]((Button*)handle) 9 10 //button handle list head. 11 static struct Button* head_handle = NULL; 12 13 /** 14 * @brief Initializes the button struct handle. 15 * @param handle: the button handle strcut. 16 * @param pin_level: read the HAL GPIO of the connet button level. 17 * @param active_level: pressed GPIO level. 18 * @retval None 19 */ 20 void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level) 21 { 22 memset(handle, sizeof(struct Button), 0); 23 handle->event = (uint8_t)NONE_PRESS; 24 handle->hal_button_Level = pin_level; 25 handle->button_level = handle->hal_button_Level(); 26 handle->active_level = active_level; 27 } 28 29 /** 30 * @brief Attach the button event callback function. 31 * @param handle: the button handle strcut. 32 * @param event: trigger event type. 33 * @param cb: callback function. 34 * @retval None 35 */ 36 void button_attach(struct Button* handle, PressEvent event, BtnCallback cb) 37 { 38 handle->cb[event] = cb; 39 } 40 41 /** 42 * @brief Inquire the button event happen. 43 * @param handle: the button handle strcut. 44 * @retval button event. 45 */ 46 PressEvent get_button_event(struct Button* handle) 47 { 48 return (PressEvent)(handle->event); 49 } 50 51 /** 52 * @brief Button driver core function, driver state machine. 53 * @param handle: the button handle strcut. 54 * @retval None 55 */ 56 void button_handler(struct Button* handle) 57 { 58 uint8_t read_gpio_level = handle->hal_button_Level(); 59 60 //ticks counter working.. 61 if((handle->state) > 0) handle->ticks++; 62 63 /*------------button debounce handle---------------*/ 64 if(read_gpio_level != handle->button_level) { //not equal to prev one 65 //continue read 3 times same new level change 66 if(++(handle->debounce_cnt) >= DEBOUNCE_TICKS) { 67 handle->button_level = read_gpio_level; 68 handle->debounce_cnt = 0; 69 } 70 } else { //leved not change ,counter reset. 71 handle->debounce_cnt = 0; 72 } 73 74 /*-----------------State machine-------------------*/ 75 switch (handle->state) { 76 case 0: 77 if(handle->button_level == handle->active_level) { //start press down 78 handle->event = (uint8_t)PRESS_DOWN; 79 EVENT_CB(PRESS_DOWN); 80 handle->ticks = 0; 81 handle->repeat = 1; 82 handle->state = 1; 83 } else { 84 handle->event = (uint8_t)NONE_PRESS; 85 } 86 break; 87 88 case 1: 89 if(handle->button_level != handle->active_level) { //released press up 90 handle->event = (uint8_t)PRESS_UP; 91 EVENT_CB(PRESS_UP); 92 handle->ticks = 0; 93 handle->state = 2; 94 95 } else if(handle->ticks > LONG_TICKS) { 96 handle->event = (uint8_t)LONG_RRESS_START; 97 EVENT_CB(LONG_RRESS_START); 98 handle->state = 5; 99 } 100 break; 101 102 case 2: 103 if(handle->button_level == handle->active_level) { //press down again 104 handle->event = (uint8_t)PRESS_DOWN; 105 EVENT_CB(PRESS_DOWN); 106 handle->repeat++; 107 if(handle->repeat == 2) { 108 EVENT_CB(DOUBLE_CLICK); // repeat hit 109 } 110 EVENT_CB(PRESS_REPEAT); // repeat hit 111 handle->ticks = 0; 112 handle->state = 3; 113 } else if(handle->ticks > SHORT_TICKS) { //released timeout 114 if(handle->repeat == 1) { 115 handle->event = (uint8_t)SINGLE_CLICK; 116 EVENT_CB(SINGLE_CLICK); 117 } else if(handle->repeat == 2) { 118 handle->event = (uint8_t)DOUBLE_CLICK; 119 } 120 handle->state = 0; 121 } 122 break; 123 124 case 3: 125 if(handle->button_level != handle->active_level) { //released press up 126 handle->event = (uint8_t)PRESS_UP; 127 EVENT_CB(PRESS_UP); 128 if(handle->ticks < SHORT_TICKS) { 129 handle->ticks = 0; 130 handle->state = 2; //repeat press 131 } else { 132 handle->state = 0; 133 } 134 } 135 break; 136 137 case 5: 138 if(handle->button_level == handle->active_level) { 139 //continue hold trigger 140 handle->event = (uint8_t)LONG_PRESS_HOLD; 141 EVENT_CB(LONG_PRESS_HOLD); 142 143 } else { //releasd 144 handle->event = (uint8_t)PRESS_UP; 145 EVENT_CB(PRESS_UP); 146 handle->state = 0; //reset 147 } 148 break; 149 } 150 } 151 152 /** 153 * @brief Start the button work, add the handle into work list. 154 * @param handle: target handle strcut. 155 * @retval 0: succeed. -1: already exist. 156 */ 157 int button_start(struct Button* handle) 158 { 159 struct Button* target = head_handle; 160 while(target) { 161 if(target == handle) return -1; //already exist. 162 target = target->next; 163 } 164 handle->next = head_handle; 165 head_handle = handle; 166 return 0; 167 } 168 169 /** 170 * @brief Stop the button work, remove the handle off work list. 171 * @param handle: target handle strcut. 172 * @retval None 173 */ 174 void button_stop(struct Button* handle) 175 { 176 struct Button** curr; 177 for(curr = &head_handle; *curr; ) { 178 struct Button* entry = *curr; 179 if (entry == handle) { 180 *curr = entry->next; 181 // free(entry); 182 } else 183 curr = &entry->next; 184 } 185 } 186 187 /** 188 * @brief background ticks, timer repeat invoking interval 5ms. 189 * @param None. 190 * @retval None 191 */ 192 void button_ticks() 193 { 194 struct Button* target; 195 for(target=head_handle; target; target=target->next) { 196 button_handler(target); 197 } 198 }
example