野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 38365|回复: 88

纯C语言实现的一个按键驱动-ButtonDrive

  [复制链接]
发表于 2018-10-25 12:34:19 | 显示全部楼层 |阅读模式
本帖最后由 杰杰 于 2018-10-28 19:29 编辑

ButtonDrive
纯C语言实现的一个按键驱动,可移植性强,支持单双击、连按、连按释放、长按;采用回调处理按键事件(自定义消抖时间),使用只需3步。
1:创建按键
2:按键事件与回调处理函数链接映射。
3:周期检查按键。

前言
前几天写了个按键驱动,参考了MulitButton的数据结构的用法,逻辑实现并不一样。 在这里感谢所有的开源开发者,让我从中学到了很多,同时网络也是一个好平台,也希望所有的开发者能形成良性循环,从网络中学知识,回馈到网络中去。感谢MulitButton的作者0x1abin,感谢两位rtt的大佬:**师流光

Button_drive简介
Button_drive是一个小巧的按键驱动,支持单击、双击、长按、连续触发等(后续可以在按键控制块中添加触发事件),理论上可无限量扩展Button,Button_drive采用按键触发事件回调方式处理业务逻辑,支持在RTOS中使用,我目前仅在RT-Thread上测试过。 写按键驱动的目的是想要将用户按键逻辑与按键处理事件分离,用户无需处理复杂麻烦的逻辑事件。

Button_drive使用效果
单击与长按
1.png
双击
2.png
连按
3.png
连按释放
4.png

ButtonDrive使用方法
1:创建按键,初始化按键信息,包括按键名字、按键电平检测函数接口、按键触发电平。
[mw_shl_code=c,true]Button_t Button1;
Button_t Button2;   
Button_Create("Button1",                                //按键名字
                &Button1,                                 //按键句柄
                Read_Button1_Level,         //按键电平检测函数接口
                BTN_TRIGGER);                           //触发电平
               
                ......[/mw_shl_code]

2:按键触发事件与事件回调函数链接映射,当按键事件被触发的时候,自动跳转回调函数中处理业务逻辑。
[mw_shl_code=c,true]  Button_Attach(&Button1,BUTTON_DOWM,Btn2_Dowm_CallBack);                //按键单击
  Button_Attach(&Button1,BUTTON_DOUBLE,Btn2_Double_CallBack);        //双击
  Button_Attach(&Button1,BUTTON_LONG,Btn2_Long_CallBack);                //长按
                                
                                .......[/mw_shl_code]

3:周期调用回调按键处理函数即可,建议调用周期20-50ms。
[mw_shl_code=c,true]Button_Process();     //需要周期调用按键处理函数[/mw_shl_code]

需要用户实现的 2 个函数:
  • 按键电平检测接口:按键逻辑处理
[mw_shl_code=c,true]uint8_t Read_Button1_Level(void)
{
  return GPIO_ReadInputDataBit(BTN1_GPIO_PORT,BTN1_GPIO_PIN);
}

uint8_t Read_Button2_Level(void)
{
  return GPIO_ReadInputDataBit(BTN2_GPIO_PORT,BTN2_GPIO_PIN);
}

// 这是我在stm32上简单测试的伪代码,以实际源码为准[/mw_shl_code]

  • 按键逻辑处理

[mw_shl_code=c,true]void Btn1_Dowm_CallBack(void *btn)
{
  PRINT_INFO("Button1 单击!");
}

void Btn1_Double_CallBack(void *btn)
{
  PRINT_INFO("Button1 双击!");
}

void Btn1_Long_CallBack(void *btn)
{
  PRINT_INFO("Button1 长按!");
  
  Button_Delete(&Button2);
  PRINT_INFO("删除Button1");
  Search_Button();
}[/mw_shl_code]

特点

Button_drive开放源码,按键控制块采用数据结构方式,按键事件采用枚举类型,确保不会重复,也便于添加用户需要逻辑,采用宏定义方式定义消抖时间、连按触发时间、双击时间间隔、长按时间等,便于修改。 同时所有被创建的按键采用单链表方式连击,用户只管创建,无需理会按键处理,只需调用Button_Process()即可,在函数中会自动遍历所有被创建的按键。
支持按键删除操作,用户无需在代码中删除对应的按键创建于映射链接代码,也无需删除关于按键的任何回调事件处理函数,只需调用Button_Delete()函数即可,这样子,就不会处理关于被删除按键的任何状态。
当然目前按键内存不会释放,如果使用os的话,建议释放按键内存。
ps:杰杰写这个按键驱动是为了将用户的按键事件与处理逻辑分离开,通过宏定义根据自己需要选择

按键控制块
[mw_shl_code=c,true]/*
        每个按键对应1个全局的结构体变量。
        其成员变量是实现消抖和多种按键状态所必须的
*/
typedef struct button
{
        /* 下面是一个函数指针,指向判断按键手否按下的函数 */
        uint8_t (*Read_Button_Level)(void); /* 读取按键电平函数,需要用户实现 */
  
  char Name[BTN_NAME_MAX];
         
  uint8_t Button_State              :   4;          /* 按键当前状态(按下还是弹起) */
  uint8_t Button_Last_State         :   4;          /* 上一次的按键状态,用于判断双击 */
  uint8_t Button_Trigger_Level      :   2;    /* 按键触发电平 */
  uint8_t Button_Last_Level         :   2;    /* 按键当前电平 */
  
  uint8_t Button_Trigger_Event;     /* 按键触发事件,单击,双击,长按等 */
  
  Button_CallBack CallBack_Function[number_of_event];
  
  uint8_t Button_Cycle;                   /* 连续按键周期 */
  
  uint8_t Timer_Count;                        /* 计时 */
  uint8_t Debounce_Time;                /* 消抖时间 */
  
  uint8_t Long_Time;                  /* 按键按下持续时间 */
  
  struct button *Next;
  
}Button_t;[/mw_shl_code]

触发事件
[mw_shl_code=c,true]typedef enum {
  BUTTON_DOWM = 0,
  BUTTON_UP,
  BUTTON_DOUBLE,
  BUTTON_LONG,
  BUTTON_CONTINUOS,
  BUTTON_CONTINUOS_FREE,
  BUTTON_ALL_RIGGER,
  number_of_event, /* 触发回调的事件 */
  NONE_TRIGGER
}Button_Event;[/mw_shl_code]

宏定义选择
[mw_shl_code=c,true]#define BTN_NAME_MAX  32     //名字最大为32字节

/* 按键消抖时间40ms, 建议调用周期为20ms
只有连续检测到40ms状态不变才认为有效,包括弹起和按下两种事件
*/

#define CONTINUOS_TRIGGER             0  //是否支持连续触发,连发的话就不要检测单双击与长按了        

/* 是否支持单击&双击同时存在触发,如果选择开启宏定义的话,单双击都回调,只不过单击会延迟响应,
   因为必须判断单击之后是否触发了双击否则,延迟时间是双击间隔时间 BUTTON_DOUBLE_TIME。
   而如果不开启这个宏定义,建议工程中只存在单击/双击中的一个,否则,在双击响应的时候会触发一次单击,
   因为双击必须是有一次按下并且释放之后才产生的 */
#define SINGLE_AND_DOUBLE_TRIGGER     1

/* 是否支持长按释放才触发,如果打开这个宏定义,那么长按释放之后才触发单次长按,
   否则在长按指定时间就一直触发长按,触发周期由 BUTTON_LONG_CYCLE 决定 */
#define LONG_FREE_TRIGGER             0

#define BUTTON_DEBOUNCE_TIME           2   //消抖时间      (n-1)*调用周期
#define BUTTON_CONTINUOS_CYCLE  1          //连按触发周期时间  (n-1)*调用周期  
#define BUTTON_LONG_CYCLE       1          //长按触发周期时间  (n-1)*调用周期
#define BUTTON_DOUBLE_TIME      15         //双击间隔时间  (n-1)*调用周期  建议在200-600ms
#define BUTTON_LONG_TIME               50                /* 持续n秒((n-1)*调用周期 ms),认为长按事件 */

#define TRIGGER_CB(event)   \
        if(btn->CallBack_Function[event]) \
          btn->CallBack_Function[event]((Button_t*)btn)

typedef void (*Button_CallBack)(void*);   /* 按键触发回调函数,需要用户实现 */
[/mw_shl_code]

例子
[mw_shl_code=c,true]Button_Create("Button1",
              &Button1,
              Read_KEY1_Level,
              KEY_ON);
  Button_Attach(&Button1,BUTTON_DOWM,Btn1_Dowm_CallBack);                       //单击
  Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack);                   //双击
  Button_Attach(&Button1,BUTTON_CONTINUOS,Btn1_Continuos_CallBack);             //连按  
  Button_Attach(&Button1,BUTTON_CONTINUOS_FREE,Btn1_ContinuosFree_CallBack);    //连按释放  
  Button_Attach(&Button1,BUTTON_LONG,Btn1_Long_CallBack);                       //长按


  Button_Create("Button2",
              &Button2,
              Read_KEY2_Level,
              KEY_ON);
  Button_Attach(&Button2,BUTTON_DOWM,Btn2_Dowm_CallBack);                     //单击
  Button_Attach(&Button2,BUTTON_DOUBLE,Btn2_Double_CallBack);                 //双击
  Button_Attach(&Button2,BUTTON_CONTINUOS,Btn2_Continuos_CallBack);           //连按
  Button_Attach(&Button2,BUTTON_CONTINUOS_FREE,Btn2_ContinuosFree_CallBack);  //连按释放
  Button_Attach(&Button2,BUTTON_LONG,Btn2_Long_CallBack);                     //长按

  Get_Button_Event(&Button1);
  Get_Button_Event(&Button2);[/mw_shl_code]

源码下载
ButtonDrive源码.zip (20.17 KB, 下载次数: 114)



10-27更新:
目前我已将按键驱动做成软件包(packages),如果使用RT-Thread操作系统的话,可以在env中直接配置使用

步骤如下:
1.选择在线软件包
1.png
2.选择外设相关软件包
2.png
3.选择button_drive
3.png
4.进入驱动的选项配置(自带默认属性)
4.png
5.如果不懂按键的配置是什么意思,按下“shift+?”,即可有解释
5‘’.png
6.编译生成mdk工程
6.png
7.png





回复

使用道具 举报

发表于 2018-10-25 13:34:54 | 显示全部楼层
很好,很好
回复

使用道具 举报

发表于 2018-10-25 13:43:54 | 显示全部楼层
嗯,单击,双击,长按,让我想起了游戏机,
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-10-25 14:16:59 | 显示全部楼层

沙发本来还想自己留着的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-10-25 22:31:19 | 显示全部楼层
八戒 发表于 2018-10-25 13:43
嗯,单击,双击,长按,让我想起了游戏机,

用在哪都可以哈哈哈哈
回复 支持 反对

使用道具 举报

发表于 2018-10-27 13:09:18 来自手机 | 显示全部楼层
看看      
回复 支持 反对

使用道具 举报

发表于 2018-10-27 14:52:43 | 显示全部楼层
666666666666666666666
回复 支持 反对

使用道具 举报

发表于 2018-10-27 15:19:32 | 显示全部楼层
66666666666666+
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-10-27 15:43:02 | 显示全部楼层

77777777777777777777
回复 支持 反对

使用道具 举报

发表于 2018-10-27 16:56:12 | 显示全部楼层
楼主好人,,,,,
回复

使用道具 举报

 楼主| 发表于 2018-10-27 17:15:10 | 显示全部楼层
PK4 发表于 2018-10-27 16:56
楼主好人,,,,,

小师妹也说我是好人,ε=(′ο`*)))唉
回复 支持 反对

使用道具 举报

发表于 2018-10-27 19:46:57 | 显示全部楼层
多谢楼主,东西不错
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-10-27 21:39:41 | 显示全部楼层
txling216 发表于 2018-10-27 19:46
多谢楼主,东西不错

回复 支持 反对

使用道具 举报

发表于 2018-10-28 19:55:15 | 显示全部楼层
下载看一下
回复 支持 反对

使用道具 举报

发表于 2018-10-29 14:28:07 | 显示全部楼层
努力学习,天天向上
回复 支持 反对

使用道具 举报

发表于 2018-10-30 14:00:08 | 显示全部楼层
好資料,謝謝
回复 支持 反对

使用道具 举报

发表于 2018-10-31 10:03:25 | 显示全部楼层
学习学习6666666666666666
回复 支持 反对

使用道具 举报

发表于 2018-10-31 17:22:41 | 显示全部楼层
很不错,可以学习很多东西
回复 支持 反对

使用道具 举报

发表于 2018-11-1 09:45:37 | 显示全部楼层
谢谢分享,谢谢分享。
回复 支持 反对

使用道具 举报

发表于 2018-11-1 10:42:10 | 显示全部楼层
感谢分享
回复

使用道具 举报

发表于 2018-11-3 17:35:07 | 显示全部楼层
好資料,謝謝
回复 支持 反对

使用道具 举报

发表于 2018-11-5 19:50:51 | 显示全部楼层
666666666666666666666666666666666666,谢谢楼主
回复 支持 反对

使用道具 举报

发表于 2018-11-8 20:09:00 | 显示全部楼层
学习咯
回复

使用道具 举报

发表于 2018-11-8 20:31:25 | 显示全部楼层
看看,关注关注
回复 支持 反对

使用道具 举报

发表于 2018-11-9 14:08:25 | 显示全部楼层
666666666666666666666
回复 支持 反对

使用道具 举报

发表于 2018-11-9 20:23:04 | 显示全部楼层
学习学习                        
回复 支持 反对

使用道具 举报

发表于 2018-11-10 15:56:57 | 显示全部楼层
谢谢分享!!!
回复

使用道具 举报

发表于 2018-11-10 20:16:30 | 显示全部楼层
学习学习思路
回复 支持 反对

使用道具 举报

发表于 2018-11-23 13:59:12 | 显示全部楼层
围观              
回复 支持 反对

使用道具 举报

发表于 2018-11-23 17:24:29 | 显示全部楼层
学习一下。
回复

使用道具 举报

发表于 2018-11-24 00:37:22 | 显示全部楼层
收下勒  谢谢大佬
回复 支持 反对

使用道具 举报

发表于 2019-1-16 14:08:16 | 显示全部楼层
厉害厉害,感谢大神分享,多多向你们学习学习
回复 支持 反对

使用道具 举报

发表于 2019-1-16 14:21:51 | 显示全部楼层
哇,666,刚开始看有点吃力,新手,感谢大神
回复 支持 反对

使用道具 举报

发表于 2019-1-23 10:19:04 | 显示全部楼层
学习了,谢谢分享!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-1-23 13:35:56 | 显示全部楼层
MR-Xiong 发表于 2019-1-23 10:19
学习了,谢谢分享!

回复 支持 反对

使用道具 举报

发表于 2019-1-23 14:20:35 | 显示全部楼层
6666666666
回复 支持 反对

使用道具 举报

发表于 2019-1-24 15:22:56 来自手机 | 显示全部楼层
谢谢分享。支持矩阵键盘吗?
回复 支持 反对

使用道具 举报

发表于 2019-1-24 17:14:39 | 显示全部楼层
学习一下
坎坎坷坷


回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-1-25 08:38:24 | 显示全部楼层
hqgboy 发表于 2019-1-24 15:22
谢谢分享。支持矩阵键盘吗?

不支持矩阵键盘,但是理论上支持无限多个按键
回复 支持 反对

使用道具 举报

发表于 2019-1-26 12:17:58 | 显示全部楼层

666666666666666666666
回复 支持 反对

使用道具 举报

发表于 2019-1-27 19:09:37 | 显示全部楼层
学习。。。。。。。。。。。。
回复

使用道具 举报

发表于 2019-1-31 13:36:55 | 显示全部楼层
这个不错,mark!
回复 支持 反对

使用道具 举报

发表于 2019-2-8 11:37:30 | 显示全部楼层
very good very good very good very good
回复 支持 反对

使用道具 举报

发表于 2019-2-12 09:42:56 | 显示全部楼层
学习一下 不胜感激
回复 支持 反对

使用道具 举报

发表于 2019-2-19 14:32:32 | 显示全部楼层
楼主 威武                    
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-2-19 18:44:42 | 显示全部楼层

双击666
回复 支持 反对

使用道具 举报

发表于 2019-2-19 20:50:38 | 显示全部楼层
66666666666
回复 支持 反对

使用道具 举报

发表于 2019-2-24 19:12:04 | 显示全部楼层
优秀。。。。。。。。。。。
回复

使用道具 举报

发表于 2019-2-25 11:16:20 | 显示全部楼层
多谢楼主,东西不错
回复 支持 反对

使用道具 举报

发表于 2019-2-25 15:44:23 | 显示全部楼层
建议加入按下与弹起事件哈
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-6-8 00:12 , Processed in 0.071877 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表