XZHDJH

MultiButton

README.md

使用方法

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 }

 

 

 

 

multi_button.h

...

 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

 

multi_button.c

....

  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

 

分类:

技术点:

相关文章: