一个好用的按键驱动模块
发现一个比较好用的按键驱动模块MultiButton 。以下是原文连接(尊重原创)
https://github.com/0x1abin/MultiButton
MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。
本文使用了该模块,在arduino开发板上简单的使用了一下,对代码进行了一点微小的更改。模块包含.h和.c两个文件,本文在arduino中使用,改为.cpp后缀。
.h文件
/** Copyright (c) 2016 Zibin Zheng <znbin@qq.com>* All rights reserved*/#ifndef _MULTI_BUTTON_H_
#define _MULTI_BUTTON_H_#include "stdint.h"
#include "string.h"#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif//According to your need to modify the constants.
#define TICKS_INTERVAL 5 //ms
#define DEBOUNCE_TICKS 3 //MAX 8
#define SHORT_TICKS (300 /TICKS_INTERVAL)
#define LONG_TICKS (1000 /TICKS_INTERVAL)typedef void (*BtnCallback)(void*);typedef enum {PRESS_DOWN = 0,PRESS_UP,PRESS_REPEAT,SINGLE_CLICK,DOUBLE_CLICK,LONG_PRESS_START,LONG_PRESS_HOLD,number_of_event,NONE_PRESS
}PressEvent;
typedef uint8_t(*pFpin_level)(uint8_t);typedef 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 button_id;pFpin_level hal_button_Level;//uint8_t (*hal_button_Level)(uint8_t button_id_);BtnCallback cb[number_of_event];struct Button* next;
}Button;#ifdef __cplusplus
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, pFpin_level pin_level, uint8_t active_level, uint8_t button_id);
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb);
PressEvent get_button_event(struct Button* handle);
int button_start(struct Button* handle);
void button_stop(struct Button* handle);
void button_ticks(void);#ifdef __cplusplus
}
#endif#endif
.c文件
/** Copyright (c) 2016 Zibin Zheng <znbin@qq.com>* All rights reserved*/#include "multi_button.h"#define EVENT_CB(ev) if(handle->cb[ev])handle->cb[ev]((Button*)handle)//button handle list head.
static struct Button* head_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, pFpin_level pin_level, uint8_t active_level, uint8_t button_id)
{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->active_level = active_level;handle->button_id = button_id;
}/*** @brief Attach the button event callback function.* @param handle: the button handle strcut.* @param event: trigger event type.* @param cb: callback function.* @retval None*/
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb)
{handle->cb[event] = cb;
}/*** @brief Inquire the button event happen.* @param handle: the button handle strcut.* @retval button event.*/
PressEvent get_button_event(struct Button* handle)
{return (PressEvent)(handle->event);
}/*** @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(handle->button_id);//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 changeif(++(handle->debounce_cnt) >= DEBOUNCE_TICKS) {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 downhandle->event = (uint8_t)PRESS_DOWN;EVENT_CB(PRESS_DOWN);handle->ticks = 0;handle->repeat = 1;handle->state = 1;} else {handle->event = (uint8_t)NONE_PRESS;}break;case 1:if(handle->button_level != handle->active_level) { //released press uphandle->event = (uint8_t)PRESS_UP;EVENT_CB(PRESS_UP);handle->ticks = 0;handle->state = 2;} else if(handle->ticks > LONG_TICKS) {handle->event = (uint8_t)LONG_PRESS_START;EVENT_CB(LONG_PRESS_START);handle->state = 5;}break;case 2:if(handle->button_level == handle->active_level) { //press down againhandle->event = (uint8_t)PRESS_DOWN;EVENT_CB(PRESS_DOWN);handle->repeat++;EVENT_CB(PRESS_REPEAT); // repeat hithandle->ticks = 0;handle->state = 3;} else if(handle->ticks > SHORT_TICKS) { //released timeoutif(handle->repeat == 1) {handle->event = (uint8_t)SINGLE_CLICK;EVENT_CB(SINGLE_CLICK);} else if(handle->repeat == 2) {handle->event = (uint8_t)DOUBLE_CLICK;EVENT_CB(DOUBLE_CLICK); // repeat hit}handle->state = 0;}break;case 3:if(handle->button_level != handle->active_level) { //released press uphandle->event = (uint8_t)PRESS_UP;EVENT_CB(PRESS_UP);if(handle->ticks < SHORT_TICKS) {handle->ticks = 0;handle->state = 2; //repeat press} else {handle->state = 0;}}else if(handle->ticks > SHORT_TICKS){ // long press uphandle->state = 0;}break;case 5:if(handle->button_level == handle->active_level) {//continue hold triggerhandle->event = (uint8_t)LONG_PRESS_HOLD;EVENT_CB(LONG_PRESS_HOLD);} else { //releasdhandle->event = (uint8_t)PRESS_UP;EVENT_CB(PRESS_UP);handle->state = 0; //reset}break;}
}/*** @brief Start the button work, add the handle into work list.* @param handle: target handle strcut.* @retval 0: succeed. -1: already exist.*/
int button_start(struct Button* handle)
{struct Button* target = head_handle;while(target) {if(target == handle) return -1; //already exist.target = target->next;}handle->next = head_handle;head_handle = handle;return 0;
}/*** @brief Stop the button work, remove the handle off work list.* @param handle: target handle strcut.* @retval None*/
void button_stop(struct Button* handle)
{struct Button** curr;for(curr = &head_handle; *curr; ) {struct Button* entry = *curr;if (entry == handle) {*curr = entry->next;
// free(entry);return;//glacier add 2021-8-18} elsecurr = &entry->next;}
}/*** @brief background ticks, timer repeat invoking interval 5ms.* @param None.* @retval None*/
void button_ticks()
{struct Button* target;for(target=head_handle; target; target=target->next) {button_handler(target);}
}
应用代码:
// userKey.h#ifndef _userKey_h
#define _userKey_h#if defined(ARDUINO) && ARDUINO >= 100#include "arduino.h"
#else#include "WProgram.h"
#endiftypedef enum
{but1_id = 0,but2_id,but3_id,but_id_max,
}EN_BUT_ID_T;#define BUTTON 2void KeyInitial(void);
#endif
#include "userKey.h"
#include "multi_button.h"
#include "HardwareSerial.h"void BTN1_PRESS_DOWN_Handler(void* btn);
void BTN1_PRESS_UP_Handler(void* btn);
void BTN1_PRESS_REPEAT_Handler(void* btn);
void BTN1_SINGLE_Click_Handler(void* btn);
void BTN1_DOUBLE_Click_Handler(void* btn);
void BTN1_LONG_PRESS_START_Handler(void* btn);
uint8_t read_button_pin(uint8_t id);struct Button btn1;void KeyInitial(void)
{button_init(&btn1, read_button_pin, 0, 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_PRESS_START, BTN1_LONG_PRESS_START_Handler);button_start(&btn1);
}uint8_t read_button_pin(uint8_t id)
{if (but1_id == id){return uint8_t(digitalRead(BUTTON));}}void BTN1_PRESS_DOWN_Handler(void* btn)
{Serial.println("press down!\n");
}void BTN1_PRESS_UP_Handler(void* btn)
{Serial.println("press up!\n");
}void BTN1_PRESS_REPEAT_Handler(void* btn)
{Serial.println("press repeat!");
}void BTN1_SINGLE_Click_Handler(void* btn)
{Serial.println("click!");
}void BTN1_DOUBLE_Click_Handler(void* btn)
{Serial.println("double click!");
}void BTN1_LONG_PRESS_START_Handler(void* btn)
{Serial.println("long press!");
}
#include "multi_button.h"
#include "userKey.h"
#define LED 13// the setup function runs once when you press reset or power the board
void setup() {KeyInitial();Serial.begin(9600);pinMode(LED, OUTPUT);
}// the loop function runs over and over again until power down or reset
void loop() {button_ticks();//digitalWrite(LED, HIGH);delay(5);//digitalWrite(LED, LOW);
}
按键驱动模块支持各种模式,基于回调函数编写,非常好用,感谢原作者。
一个好用的按键驱动模块相关推荐
- 【嵌入式开源库】MultiButton的使用,简单易用的事件驱动型按键驱动模块
MultiButton 简介 下载 使用介绍 工程移植 代码分析 完整使用流程 实验效果 简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步 ...
- C语言实现事件驱动型按键驱动模块MultiButton
C语言实现事件驱动型按键驱动模块MultiButton 文章目录 C语言实现事件驱动型按键驱动模块MultiButton 简介 使用方法 特性 按键事件 使用方法举例 核心代码分析 头文件声明 函数定 ...
- 苹果怎么设置手写键盘_Mac使用技巧:苹果键盘的一个或多个按键没有响应怎么解决?...
苹果键盘的一个或多个按键没有响应怎么解决??请先使用"虚拟键盘"测试键盘按键是否在按下时正常响应.具体步骤,请参考下方: 选取苹果菜单 >"系统偏好设置" ...
- 一个ADC做多个按键扫描检测
常用的按键有以下两种方式: 1.独立按键 独立按键直接用MCU的I/O管脚构成的单个按键电路,其特点式每个按键单独占用一个I/O,每个按键的工作不会影响其他I/O的状态.独立按键很浪费MCU管脚,但编 ...
- 给树莓派添加一个开、关机按键(改进版本)
声明 本文由晓宇(xiaoyu_ebox)原创,转载及引用内容请注明出处,并标明本站网址.文中程序仅供学习使用. 关键词 树莓派 开关键 开关机按键 修改开关键 GPIO17开关键 问题起因 一直以来 ...
- 做一个简单的根据按键不同改变盒子颜色
文章目录 前言 一.效果展示 二.步骤 1.搭建html+css 2.书写jQuery 前言 不知不觉过了这么久了,突然学完了js,进入jQuery的学习,后面也要继续努力啊! 一.效果展示 二.步骤 ...
- C#:光标通过上下键或者enter键从一个textBox移动到另一个textBox或实现按键click功能
//latitudeTbx-->GDPTbx:光标通过↓移动 private void latitudeTbx_KeyDown(object sender, KeyEventArgs e) ...
- 32怎么通过一个按键实现不同工作模式_stm32几种低功耗模式的实现和差别
点击上方蓝字关注我哦- 01 前言 按功耗由高到低排列,STM32具有运行.睡眠.停止和待机四种工作模式.上电复位后 STM32 处于运行状态,当内核不需要继续运行,就可以选择进入后面的三种低功耗模式 ...
- python 按键精灵脚本_[620]使用Python实现一个按键精灵
按键精灵想必很多人都玩过,使用录制功能将鼠标和键盘的操作录制下来,录制好后就可以通过回放自动执行之前录制的操作,可以设置重复执行的次数,这样就可以将一些重复的劳动交给脚本自动化去完成.使用Python ...
最新文章
- MPB:林科院袁志林组-一种简易的植物组织表面消毒装置
- continue和break语句的区别
- corosync+pacemaker+drbd构建mysql高可用平台的简单案例
- 多重背包2[二进制位优化]
- 直方图python高度_python – 子图中直方图的动画
- 小度拆卸_拆卸invokedynamic
- C++(STL):36---关联式容器multiset、multimap源码剖析
- Spring入门-框架搭建
- C获取当前Linux登录的用户名
- 查看-增强会话_会话助手平台-Hinglish Voice等!
- 设计师配色宝典:教你从零开始学配色
- 基于单片机GPS公交车自动语音报站系统设计
- trustedinstaller权限获取教程
- 学习zencart模板制作
- R语言中的Factor到底是什么?
- 自定义函数 | R语言偏相关分析及绘图
- RPA 百年简史 机器人流程自动化知多少
- Java线程状态总结
- wechat4j开发-菜单创建
- \Zane\Utils\Ary 开源代码阅读示例