发现一个比较好用的按键驱动模块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);
}

按键驱动模块支持各种模式,基于回调函数编写,非常好用,感谢原作者。

一个好用的按键驱动模块相关推荐

  1. 【嵌入式开源库】MultiButton的使用,简单易用的事件驱动型按键驱动模块

    MultiButton 简介 下载 使用介绍 工程移植 代码分析 完整使用流程 实验效果 简介 MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步 ...

  2. C语言实现事件驱动型按键驱动模块MultiButton

    C语言实现事件驱动型按键驱动模块MultiButton 文章目录 C语言实现事件驱动型按键驱动模块MultiButton 简介 使用方法 特性 按键事件 使用方法举例 核心代码分析 头文件声明 函数定 ...

  3. 苹果怎么设置手写键盘_Mac使用技巧:苹果键盘的一个或多个按键没有响应怎么解决?...

    苹果键盘的一个或多个按键没有响应怎么解决??请先使用"虚拟键盘"测试键盘按键是否在按下时正常响应.具体步骤,请参考下方: 选取苹果菜单 >"系统偏好设置" ...

  4. 一个ADC做多个按键扫描检测

    常用的按键有以下两种方式: 1.独立按键 独立按键直接用MCU的I/O管脚构成的单个按键电路,其特点式每个按键单独占用一个I/O,每个按键的工作不会影响其他I/O的状态.独立按键很浪费MCU管脚,但编 ...

  5. 给树莓派添加一个开、关机按键(改进版本)

    声明 本文由晓宇(xiaoyu_ebox)原创,转载及引用内容请注明出处,并标明本站网址.文中程序仅供学习使用. 关键词 树莓派 开关键 开关机按键 修改开关键 GPIO17开关键 问题起因 一直以来 ...

  6. 做一个简单的根据按键不同改变盒子颜色

    文章目录 前言 一.效果展示 二.步骤 1.搭建html+css 2.书写jQuery 前言 不知不觉过了这么久了,突然学完了js,进入jQuery的学习,后面也要继续努力啊! 一.效果展示 二.步骤 ...

  7. C#:光标通过上下键或者enter键从一个textBox移动到另一个textBox或实现按键click功能

    //latitudeTbx-->GDPTbx:光标通过↓移动 private void latitudeTbx_KeyDown(object sender, KeyEventArgs e)   ...

  8. 32怎么通过一个按键实现不同工作模式_stm32几种低功耗模式的实现和差别

    点击上方蓝字关注我哦- 01 前言 按功耗由高到低排列,STM32具有运行.睡眠.停止和待机四种工作模式.上电复位后 STM32 处于运行状态,当内核不需要继续运行,就可以选择进入后面的三种低功耗模式 ...

  9. python 按键精灵脚本_[620]使用Python实现一个按键精灵

    按键精灵想必很多人都玩过,使用录制功能将鼠标和键盘的操作录制下来,录制好后就可以通过回放自动执行之前录制的操作,可以设置重复执行的次数,这样就可以将一些重复的劳动交给脚本自动化去完成.使用Python ...

最新文章

  1. MPB:林科院袁志林组-一种简易的植物组织表面消毒装置
  2. continue和break语句的区别
  3. corosync+pacemaker+drbd构建mysql高可用平台的简单案例
  4. 多重背包2[二进制位优化]
  5. 直方图python高度_python – 子图中直方图的动画
  6. 小度拆卸_拆卸invokedynamic
  7. C++(STL):36---关联式容器multiset、multimap源码剖析
  8. Spring入门-框架搭建
  9. C获取当前Linux登录的用户名
  10. 查看-增强会话_会话助手平台-Hinglish Voice等!
  11. 设计师配色宝典:教你从零开始学配色
  12. 基于单片机GPS公交车自动语音报站系统设计
  13. trustedinstaller权限获取教程
  14. 学习zencart模板制作
  15. R语言中的Factor到底是什么?
  16. 自定义函数 | R语言偏相关分析及绘图
  17. RPA 百年简史 机器人流程自动化知多少
  18. Java线程状态总结
  19. wechat4j开发-菜单创建
  20. \Zane\Utils\Ary 开源代码阅读示例

热门文章

  1. PHP资源,库,工具大全
  2. 精通Java事务编程(8)-可串行化隔离级别之可串行化的快照隔离
  3. React中hover悬浮菜单的做法
  4. Tushare Pro判断股市是否开盘
  5. 转载:一篇文章看明白 Android 系统启动时都干了什么
  6. 高项(信息系统项目管理师)考试很难?如何备考?
  7. BufferQueue 学习总结(内附动态图)
  8. matlab sort三维_三维数组存储顺序
  9. python实现寻找最长回文子串
  10. reids3.0安装文档