当前位置:网站首页>[MCUKeys] 一个通用的、灵活的、可配置的、可移植的按键事件处理的实现
[MCUKeys] 一个通用的、灵活的、可配置的、可移植的按键事件处理的实现
2022-04-22 06:06:00 【静静流淌的柯溪】
MCUKeys
1 简介
MCUKeys完全使用C语言编写,是一个简洁小巧可配置的、灵活的、通用的的按键检测程序,全部源码都使用中文注释,方便阅读。有基于按键事件回调和按键缓冲区两种方式解决按键事件。截至到目前为止它可以检测如下输入事件:
- 按键按下
- 按键抬起
- 长按(时间可配置)
- 连击(时间可配置)
- 双击(时间可配置)
- 组合按键(可以实现以上五种状态)
同时,所有的事件都支持注册回调函数,在事件发生时执行。如果当前系统希望只检测按键按下事件,则可以屏蔽其他所有事件,对于其他按键事件亦然。
2 使用方法
2.1 先定义一个按键,如果是多个按键可以用数组来实现
enum
{
KEY_ID_UP = 0,
KEY_ID_DOWN,
KEY_ID_LEFT,
KEY_ID_RIGHT,
KEY_ID_ENTER,
KEY_ID_MAX,
};
static key my_key[KEY_ID_MAX];
KEY_ID是按键的唯一标识符,不可重复,可以使用enum来实现。
2.2 初始化按键
for (int i = 0; i < (KEY_ID_MAX); i++)
{
key_init(&my_key[i]);
my_key[i].e_key.id = i;
my_key[i].key_event_cb = key_event_cb; // 屏蔽这行表示不使用事件回调函数
my_key[i].get_key_status = get_key_state_cb;
key_add(&my_key[i]);
}
注意:这里的get_key_state_cb和硬件息息相关,是唯一需要移植的地方,我这里给出一个使用stm32HAL库开发的实例。
uint8_t get_key_state_cb(const event_key e_key)
{
uint8_t ret = KEY_LIFT;
switch (e_key.id)
{
case KEY_ID_UP:
{
if (HAL_GPIO_ReadPin(GPIOD, KEY0_Pin) == GPIO_PIN_RESET)
{
ret = KEY_PRESS;
}
else
{
ret = KEY_LIFT;
}
}
break;
case KEY_ID_DOWN:
{
if (HAL_GPIO_ReadPin(GPIOD, KEY1_Pin) == GPIO_PIN_RESET)
{
ret = KEY_PRESS;
}
else
{
ret = KEY_LIFT;
}
}
break;
case KEY_ID_LEFT:
{
if (HAL_GPIO_ReadPin(GPIOD, KEY2_Pin) == GPIO_PIN_RESET)
{
ret = KEY_PRESS;
}
else
{
ret = KEY_LIFT;
}
}
break;
case KEY_ID_RIGHT:
{
if (HAL_GPIO_ReadPin(GPIOD, KEY3_Pin) == GPIO_PIN_RESET)
{
ret = KEY_PRESS;
}
else
{
ret = KEY_LIFT;
}
}
break;
case KEY_ID_ENTER:
{
if (HAL_GPIO_ReadPin(GPIOB, KEY4_Pin) == GPIO_PIN_RESET)
{
ret = KEY_PRESS;
}
else
{
ret = KEY_LIFT;
}
}
break;
default:
break;
}
return ret;
}
其他类型的MCU需要根据自己的硬件来做相应的修改,我这里的硬件接法是按键按下低电平,按键抬起高电平。
2.3 在一个固定周期的函数中调用key_scan
这里的固定周期可以是定时器的中断服务函数,也可以是RTOS中的一个线程,周期应该是KEY_TICKS,
/* * 按键循环扫描周期(ms) key_scan()函数在哪个固定扫描周期中 该值就等于多少 一般设置为10ms */
#define KEY_TICKS 10
比如我在这里将它放在了RTOS的一个单独线程中:
void keys_thread_entry(void *param)
{
while (1)
{
key_scan();
rt_thread_mdelay(KEY_TICKS);
}
}
2.4 实现按键事件回调函数
如果初始化的时候,挂接了按键事件回调函数,则这里必须要实现该函数,当有对应的按键事件时,会回调该函数。
void key_event_cb(const event_key e_key)
{
LOG_D("e_key id = %d state = %d", e_key.id, e_key.state);
}
这里传入的参数中, e_key.id就是我们初始化时定义的按键ID,e_key.state就是按键的事件,用户可以在这里实现按键回调的具体逻辑。
实测输出如下:
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 4 state = 1
[D/key] e_key id = 4 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 1 state = 1
[D/key] e_key id = 1 state = 2
[D/key] e_key id = 3 state = 1
[D/key] e_key id = 3 state = 2
[D/key] e_key id = 2 state = 1
[D/key] e_key id = 2 state = 2
[D/key] e_key id = 4 state = 1
[D/key] e_key id = 4 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 0 state = 1
[D/key] e_key id = 0 state = 2
[D/key] e_key id = 1 state = 1
[D/key] e_key id = 1 state = 2
[D/key] e_key id = 1 state = 1
[D/key] e_key id = 1 state = 2
[D/key] e_key id = 1 state = 4
[D/key] e_key id = 2 state = 1
[D/key] e_key id = 2 state = 1
[D/key] e_key id = 2 state = 1
[D/key] e_key id = 2 state = 1
[D/key] e_key id = 2 state = 1
[D/key] e_key id = 2 state = 1
[D/key] e_key id = 2 state = 2
2.5 在main函数中轮询按键状态
当我们不使用按键的事件回调机制时,还可以使用FIFO缓冲机制,这样就不会漏掉任何一个按键事件。
int main(void)
{
/* 必要的初始化代码...*/
// ....
event_key e_key;
while (1)
{
e_key = key_out_fifo();
if(e_key.state != KEY_NONE)
{
LOG_D( "e_key id = %d state = %d",e_key.id, e_key.state);
}
rt_thread_delay(800);
}
}
实测输出:
[D/main] e_key id = 0 state = 2
[D/main] e_key id = 1 state = 1
[D/main] e_key id = 1 state = 2
[D/main] e_key id = 2 state = 1
[D/main] e_key id = 2 state = 2
[D/main] e_key id = 3 state = 1
[D/main] e_key id = 3 state = 2
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 2
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 2
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 1
[D/main] e_key id = 0 state = 2
[D/main] e_key id = 1 state = 1
[D/main] e_key id = 1 state = 1
[D/main] e_key id = 1 state = 1
[D/main] e_key id = 1 state = 2
在上述代码中,我在main函数的while(1)中特意加入了800ms延时,实测没有漏掉一个按键状态,如果在使用中有漏按键的情况,请将FIFO缓冲区开大一点。默认是50,即缓冲50个按键状态。
#define KEY_FIFO_SIZE 50 //按键FIFO缓冲大小
获取源码请点击这里,如果有帮助到你,请给star支持!
联系作者:xph
版权声明
本文为[静静流淌的柯溪]所创,转载请带上原文链接,感谢
https://blog.csdn.net/u014421520/article/details/83584231
边栏推荐
- Qt基础知识汇总(持续刷新)
- 如何在CMake项目中引入OpenCV
- 矩阵的分解——LU分解
- Keras bug collection (continuous update)
- Zotero如何在word中引用跳转到参考文献/建立超链接
- Display the up and down floating ripple animation according to the size of the sound shell
- 【数学建模】我的数模记忆
- C#窗体设计 鼠标任意 拖拽 窗体大小、控件联动
- win10没有本地组策略怎么办?
- DDR4 signal refers to the power layer. Will the impedance be affected?
猜你喜欢

ROS系列(四):ROS通信机制系列(5):服务通信实操

遇到数学公式中不认识的符号怎么办

How to use Anaconda to create a new environment for pycharm and use pycharm to create a new project in this environment

DDR4 signal refers to the power layer. Will the impedance be affected?

【AI视野·今日Sound 声学论文速览 第一期】Thu, 14 Apr 2022

知识图谱综述(二)

如果有一种设计不增加成本又能改善信号质量

Do you believe that one day BGA can't take the difference line?

The test posture should be rigorous

How to discover and learn the story hidden behind the published metagenome articles
随机推荐
PMSM FOC控制 Matlab/Simulink仿真之Clark变换
计数排序(C语言实现)------学习笔记
2021-09-03 爬虫模板(只支持静态页面)
Inverse Park transform of PMSM FOC control MATLAB / Simulink simulation
Very easy to use bar code and QR code recognition tool class zxing ZBar
深度解说信号孔旁边到底需要几个地过孔
DDR4 signal refers to the power layer. Will the impedance be affected?
机器学习基本名词介绍
【AI视野·今日Robot 机器人论文速览 第二十八期】Wed, 1 Dec 2021
Install Matplotlib and bug resolution in the specified environment
PolarMask is not in the models registry
进程七状态转换图
Win10下Photoshop cc 2019安装
[蓝桥杯复习] 鸣人的影分身
openvino只支持英特尔6代以上的cpu
Excel中使用VBA间隔抽取某列到另一列
Zotero如何在word中引用跳转到参考文献/建立超链接
[蓝桥杯复习] 生命之树
【Latex】公式组
Development of two stage target detection technology (I) r-cnn and spp net