MCU之按键驱动 -剥离按键驱动和事件处理
ButtonDrive
自己写的一个按键驱动,支持单双击、连按、长按;采用回调处理按键事件(自定义消抖时间),使用只需3步,创建按键,按键事件与回调处理函数链接映射,周期检查按键。
源码地址:https://github.com/jiejieTop/ButtonDrive
前言
前几天写了个按键驱动,参考了MulitButton的数据结构的用法,逻辑实现并不一样。
在这里感谢所有的开源开发者,让我从中学到了很多,同时网络也是一个好平台,也希望所有的开发者能形成良性循环,从网络中学知识,回馈到网络中去。感谢MulitButton的作者0x1abin,感谢两位rtt的大佬:大法师、流光。
Button_drive简介
Button_drive是一个小巧的按键驱动,支持单击、双击、长按、连续触发等(后续可以在按键控制块中添加触发事件),理论上可无限量扩展Button,Button_drive采用按键触发事件回调方式处理业务逻辑,支持在RTOS中使用,我目前仅在RT-Thread上测试过。
写按键驱动的目的是想要将用户按键逻辑与按键处理事件分离,用户无需处理复杂麻烦的逻辑事件。
Button_drive使用效果
- 单击与长按
- 双击
- 连按
4. 连按释放
使用方法
- 创建按键句柄
Button_t Button1;
Button_t Button2;
- 1
- 2
- 创建按键,初始化按键信息,包括按键名字、按键电平检测函数接口、按键触发电平。
Button_Create("Button1", //按键名字&Button1, //按键句柄Read_Button1_Level, //按键电平检测函数接口BTN_TRIGGER); //触发电平
......
- 1
- 2
- 3
- 4
- 5
- 6
- 按键触发事件与事件回调函数链接映射,当按键事件被触发的时候,自动跳转回调函数中处理业务逻辑。
Button_Attach(&Button1,BUTTON_DOWM,Btn2_Dowm_CallBack); //按键单击Button_Attach(&Button1,BUTTON_DOUBLE,Btn2_Double_CallBack); //双击Button_Attach(&Button1,BUTTON_LONG,Btn2_Long_CallBack); //长按
.......
- 1
- 2
- 3
- 4
- 5
- 周期调用回调按键处理函数即可,建议调用周期20-50ms。
Button_Process(); //需要周期调用按键处理函数
- 1
需要用户实现的 2 个函数:
- 按键电平检测接口:
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上简单测试的伪代码,以实际源码为准
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 按键逻辑处理
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();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
特点
Button_drive开放源码,按键控制块采用数据结构方式,按键事件采用枚举类型,确保不会重复,也便于添加用户需要逻辑,采用宏定义方式定义消抖时间、连按触发时间、双击时间间隔、长按时间等,便于修改。
同时所有被创建的按键采用单链表方式连击,用户只管创建,无需理会按键处理,只需调用Button_Process()
即可,在函数中会自动遍历所有被创建的按键。
支持按键删除操作,用户无需在代码中删除对应的按键创建于映射链接代码,也无需删除关于按键的任何回调事件处理函数,只需调用Button_Delete()
函数即可,这样子,就不会处理关于被删除按键的任何状态。当然目前按键内存不会释放,如果使用os的话,建议释放按键内存。
按键控制块
/*每个按键对应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;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
触发事件
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;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
宏定义选择
#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_Functionevent
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
例子
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);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
后续
流光大佬的要求,让我玩一玩RTT的rtkpgs,打算用Button_drive练一练手吧。
ButtonDrive在env使用
目前我已将按键驱动做成软件包(packages),如果使用RT-Thread操作系统的话,可以在env中直接配置使用!
步骤如下:
- 选择在线软件包
- 选择软件包属性为外设相关
- 选择button_drive
- 进入驱动的选项配置(自带默认属性)
如果不懂按键的配置是什么意思,按下“shift+?”,即可有解释
编译生成mdk/iar工程
关于rtkpgs
简介 (English)
buildpkg 是用于生成 RT-Thread package 的快速构建工具。
一个优秀的 package 应该是这样的:
- 代码优雅, 规范化。
- examples 例程,提供通俗易懂的使用例程。
- SConscript 文件,用于和 RT-Thread 环境一起进行编译。
- README.md 文档,向用户提供必要的功能说明。
- docs 文件夹, 放置除了 README 之外的其他细节文档。
- license 许可文件,版权说明。
为了方便快速的生成 RT-Thread package 规范化模板 以及 减轻开源仓库迁移 RT-Thread 的前期准备工作的负担,基于此目的的 buildpkg 应运而生,为开发 Rt-Thread 的 package 的开发者提供辅助开发工具。
序号 | 支持功能 | 描述 |
---|---|---|
1 | 构建 package 模板 | 创建指定名称 package , 自动添加 readme /版本号/ github ci脚本/demo/开源协议文件 |
2 | 迁移开源仓库 | 从指定 git 仓库构建 package , 自动添加readme/版本号/ github ci脚本/demo/开源协议文件, 但是迁移的仓库需要用户自己按照实际情况修改 |
3 | 更新 package | 生成package后可以再次更新之前设定的版本号,开源协议或者scons脚本等 |
使用说明
1. 构建package
buildpkg.exe make pkgdemo
2. 迁移开源仓库
buildpkg.exe make cstring https://github.com/liu2guang/cstring.git
3. 更新package
buildpkg.exe update pkgname
4. 可选配置
长参数 | 短参数 | 描述 |
---|---|---|
–version=v1.0.0 | -v v1.0.0 | 设置 package 的版本 |
–license=MIT | -l MIT | 设置 package 所遵循的版权协议 |
–submodule | -s | 删除 git 子模块 |
测试平台
序号 | 测试平台 | 测试结果 |
---|---|---|
1 | win10 | exe测试通过, py测试通过 |
2 | win7 | exe待测试, py待测试 |
3 | mac | py脚本不知道是否兼容, 没有测试条件, 后面维护下 |
4 | linux | py脚本不知道是否兼容, 没有测试条件, 后面维护下 |
联系人
- 邮箱:1004383796@qq.com
- 主页:liu2guang
- 仓库:Github, Gitee
MCU之按键驱动 -剥离按键驱动和事件处理相关推荐
- 字符设备驱动(四)按键中断
目录 字符设备驱动(四)按键中断 硬件IO 程序设计 中断配置 中断关闭 中断函数 共享中断号 测试 完整的程序 title: 字符设备驱动(四)按键中断 tags: linux date: 2018 ...
- 从ARM裸机看驱动之按键中断方式控制LED(二)
硬件环境:Samsung Cortex-A9 Exynos4412 BSP 软件环境:Linux3.14 =============================================== ...
- 从ARM裸机看驱动之按键中断方式控制LED(一)
硬件环境:Samsung Cortex-A9 Exynos4412 BSP + JTAG ARM 仿真器 软件环境:Eclipse ================================== ...
- 按键控制c51单片机驱动unl2003控制步进电机正反转停止及程序调速-萌新入门
** 按键控制c51单片机驱动unl2003控制步进电机正反转停止及程序调速 ** 分享一个萌新入门小工程 一.原件连接: 第一种直接用51开发板 第二种用最小单元加unl2003驱动 二.开发板电路 ...
- 【Proteus仿真】Arduino UNO+uln2003驱动步进电机+按键启保停正反转控制
[Proteus仿真]Arduino UNO+uln2003驱动步进电机+按键启保停正反转控制 Proteus仿真演示 功能说明 正反转采用2和3 引脚外部中断,3和4引脚调节加减速. 示例程序代码 ...
- 触摸屏驱动和按键驱动冲突-----解决方法
我的开发板上原先移植的有触摸屏的驱动,后来我有添加了以按键驱动.出问题了: 在我添加上按键驱动后,我的触摸屏驱动不能用了,在我按下按键时终端报错说:selected device not a Touc ...
- 高级驱动——(驱动所有按键)
我们用一种更为高级的方法去驱动所有的按键----理论上按键最多可以驱动768个,但是我的板子只有三个按键 所以现在只能驱动三个,但是驱动三个和驱动768个都是一样的. 首先我们要利用起设备树文件了,如 ...
- Linux驱动_按键输入
一.修改设备树文件 (1)添加pinctrl节点 打开imx6ull-alientek-emmc.dts文件,在 iomuxc 节点的 imx6ul-evk 子节点下创建一个名为"pinct ...
- 【STM32】步进电机及其驱动(ULN2003驱动28BYJ-48丨按键控制电机旋转)
本篇文章包含的内容 一.步进电机的结构和工作原理 1.1 步进控制系统的组成 1.2 步进电机简介 1.3 步进电机的分类 1.4 步进电机的工作原理 1.4.1 单极性步进电机(5线4相) 1.4. ...
最新文章
- dorado listener属性
- webpack+vue搭建基础
- 足坛绝代双骄全面数据对比,梅西30岁以后不如C罗?
- DynamipsGUI
- 使用lucene实现简单的全文检索
- 单链表的合并算法_图解算法:单链表两两反转 | 眼睛会了手就会系列
- [20171106]配置客户端连接注意.txt
- 2021年高考传媒校考成绩查询,中国传媒大学2021年艺术校考合格线及成绩什么时候公布(附查询入口)...
- linux basename学习
- MATLAB R2021b v9.11.0.1769968中文版for Mac
- signature=b28f8fc969e82dcca916aa6ef86476cb,Method for verifying redundancy of secure systems
- 浅谈JSON数据解析方法
- ZigBee(CC2530)(03)数据手册分享(英文+中文)
- 深度学习(二),终于理解了深度学习原理--SPGD(SGD)优化算法的实现原理
- .net remoting和wcf自托管——一个bug引发的警示
- SEO教程:网站优化时站内优化应该怎么做?
- 快传号怎么过新手期,快传号新手期转正条件是什么
- CUDA C/C++ 从入门到入土 第一步——让你的CUDA跑起来
- Android中播放本地SD卡中歌曲须要的加入的权限
- 婚庆APP开发解决方案
热门文章
- STM32F4通过U盘升级程序
- 客快物流大数据项目(九十八):ClickHouse的SQL函数
- [规划酱@国土空间] ArcGIS符号系统|新的用地用海分类
- 大豆技术面分析_外汇交易分析之技术面分析
- 小程序看完激励视频发放奖励(含解决重复发放奖励的bug)
- STM32读写24C02遇到的问题
- 安卓打包工具_【安卓+ios】追书神器爱阅书香182个书源配置更新~~
- HTML-CSS_Day_1:CSS要点补充说明、项目演练
- 诸神之眼——nmap入门教程
- 明明PCB拼了板,为什么SMD焊接还要开托盘