(转)开源按键处理项目:状态事件驱动按键驱动模块,按键事件的回调处理方式可以简化你的程序逻辑【MultiButton】

前言:

按键事件绑定是项目中非常常用的功能,以前就想好好设计下,现在可以直接使用这个开源的了! 再次拜谢[MultiButton]


简介:

        MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调处理方式可以简化你的程序逻辑,去除冗余的按键处理硬编码,专注你的程序思路。

该模块已稳定用于公司多款量产智能硬件产品。

使用方法:

        1. 先申请一个按键结构

 struct Button button1;

2. 初始化按键对象,绑定按键连接的GPIO引脚,read_button_pin() 为按键的GPIO读取函数,后一个参数为设置触发电平

button_init(&button1, read_button_pin, 0);

3. 注册按键事件,共有以下5种事件:

CLICK                        //每次按下都会触发
                        PRESSED                   //单击触发
                        DOUBLE_CLICK           //双击触发
                        LONG_RRESS_START   //长按开始触发一次
                        LONG_PRESS_HOLD    //长按过程一直触发
                        LONG_PRESS_STOP    //长按松手触发

                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  state : 3;
    uint8_t  debounce_cnt : 3; 
    uint8_t  active_level : 1;
    uint8_t  button_level : 1;
    uint8_t  (*hal_button_Level)(void);
    CallBackFunc  cb[number_of_event];
    struct Button* next;
};

这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。

Examples

#include "button.h"

struct Button button1;
struct Button button2;

int read_button1_pin()
{
    return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);  //HAL GPIO read.
}
...

int main()
{
    button_init(&button1, read_button1_pin, 0);  //初始化,绑定按键GPIO电平读取接口
    button_init(&button2, read_button2_pin, 0);

    button_attach(&button1, PRESSED, BTN1_SINGLE_CLICK_Handler);    //绑定 按键1 的单击事件回调
    button_attach(&button1, DOUBLE_CLICK, BTN1_DOUBLE_Click_Handler);    //双击事件回调
    button_attach(&button2, LONG_RRESS_START, BTN2_LONG_RRESS_START_Handler);  //绑定 按键2 长按开始事件回调
    button_attach(&button2, LONG_PRESS_HOLD,  BTN2_LONG_PRESS_HOLD_Handler);
    button_attach(&button2, LONG_PRESS_STOP,  BTN2_LONG_PRESS_STOP_Handler);

    button_start(&button1);  //启动
    button_start(&button2);
    
    //定时循环调用button_ticks() 后台处理函数,该调用方法由你的平台自行实现。
    __timer_start(button_ticks, 0, 5);  
    
    while(ture) 
    {
     ...
    }
}

void BTN1_SINGLE_CLICK_Handler()
{
    //do something..
}

void BTN1_DOUBLE_Click_Handler()
{
    //do something..
}
...

模块下载地址:
https://github.com/0x1abin/MultiButton


另本站百度网盘有转载,文件名:MultiButton按键处理事件程序.zip


本文引用自:http://www.amobbs.com/thread-5658940-1-1.html

感谢:半导体


这样处理的好处:

一个按键一份占用一份数据结构的RAM,所以占用空间还是比较弹性的,其实也不需要多大,可根据你的项目需求做一些小裁剪。

再说了,现在程序空间几乎是我们不需要担心,更多是考虑健壮易维护的程序结构。


核心部分代码:还是状态机

/**
  * @brief  Button driver core function, driver state machine.
  * @param  handle: the button handle strcut.
  * @retval None
  */
void button_handler(struct Button* handle)
{
        uint8_t read_gpio_level = handle->hal_button_Level();

        //ticks counter working..
        if((handle->state) > 0) handle->ticks++;

        /*------------button debounce handle---------------*/
        if(read_gpio_level != handle->button_level) { //not equal to prev one
                //continue read 3 times same new level change
                if(++(handle->debounce_cnt) >= kDebounceTicks) {
                        handle->button_level = read_gpio_level;
                        handle->debounce_cnt = 0;
                }

        } else { //leved not change ,counter reset.
                handle->debounce_cnt = 0;
        }

        /*-----------------State machine-------------------*/
        switch (handle->state) {
        case 0:
                if(handle->button_level == handle->active_level) {        //start press
                        if(handle->cb[CLICK]) handle->cb[CLICK]();
                        
                        handle->ticks = 0;
                        handle->state = 1;
                }
                break;

        case 1:
                if(handle->button_level != handle->active_level) { //released
                        handle->state = 2;

                } else if(handle->ticks > kLongTicks) {
                        if(handle->cb[LONG_RRESS_START]) handle->cb[LONG_RRESS_START]();

                        handle->state = 5;
                }
                break;

        case 2:
                if(handle->ticks > kClickTicks) {        //released
                        //press event
                        if(handle->cb[PRESSED]) handle->cb[PRESSED]();        //press event

                        handle->state = 0;        //reset

                } else if(handle->button_level == handle->active_level) { //press again
                        if(handle->cb[CLICK]) handle->cb[CLICK]();
                        handle->state = 3;
                }
                break; 

        case 3:        //repeat press pressing
                if(handle->button_level != handle->active_level) {        //double releasd
                        //double click event
                        if(handle->cb[DOUBLE_CLICK]) handle->cb[DOUBLE_CLICK]();

                        handle->state = 0;
                }
                break;

        case 5:
                if(handle->button_level == handle->active_level) {
                        //continue hold trigger
                        if(handle->cb[LONG_PRESS_HOLD]) handle->cb[LONG_PRESS_HOLD]();

                } else { //releasd
                        if(handle->cb[LONG_PRESS_STOP]) handle->cb[LONG_PRESS_STOP]();
                        handle->state = 0; //reset
                }
                break;
        }
}


已邀请:

等。。。待

赞同来自:

可以加一个buf,每次都对同一个buf进行读写 到最后就整合为一个安静读取的函数了
//获取按键键值
uint8_t bsp_GetKey(void) //获取键值
{
uint8_t key_val;
button_ticks();//按键 检测
if(read_key_loop_buf(&key_val) == 1) //读取队列成功
{
// printf("%d\r\n",key_val);
return key_val;
}
else
{
return 0;
}
}

°別敷衍涐

赞同来自:

这模块针对芯片么?51内核能不能用?

要回复问题请先登录注册