硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1688|回复: 7
收起左侧

[技术文档] EmbeddedButton,嵌入式按键处理框架

[复制链接]

2

主题

5

回帖

11

积分

新手上路

积分
11
发表于 2024-8-7 23:05:05 | 显示全部楼层 |阅读模式

<h1 align="center">EmbeddedButton,嵌入式按键处理框架</h1>


- [视频介绍](https://www.bilibili.com/video/B ... id_from=333.999.0.0)
- [项目链接](https://github.com/530china/EmbeddedButton)
<h2>&#128075; 简介</h2>
EmbeddedButton是一个轻量级简单易用的嵌入式按键处理框架,可无限拓展按键;

- 支持多连击、长按、短按长按等多种按键事件;
- 模块通过几个简单原则完成了整个代码逻辑的支撑;
- 核心处理采取数据驱动方式,支持位运算键值匹配,仅内置基本键值定义,其他键值含义由用户通过**配置键值匹配规则**自行定义,而不用侵入式修改代码,灵活性极强;

## &#127793; 特性

> 1.依靠简单几个原则,支持起整个按键判断逻辑
- 只要键值非零,时间tick++
- 只要按键状态发生变化,改变一次键值(**__append_bit()**),tick时间清零(确保tick为按下或抬起的时间)
- 以tick时间的长短及按键抬起作为一次状态结束的判断依据,可以很好的实现短按长按等操作;

> 2.使用C语言实现,巧妙利用位运算来实现每个按键键值的二进制记录表示,1代表按下,0代表松开

键值 | 说明
--- | ---
0b0 | 未按下
0b010 | 单击
0b01010 | 双击
0b01010...n | n连击
0b011 | 长按开始
0b0111| 长按保持
0b01110|长按结束
0b01011|短按然后长按
0b0101011 | 双击然后长按
0b01010..n11 | n连击然后长按

> 3.核心处理采取数据驱动方式,支持位运算键值匹配:
- 关键数据结构,键值匹配规则配置表:
```c
typedef struct {
    key_value_type_t operand;           // 操作数
    kv_match_operator_type_t operator;  // 操作符
    key_value_type_t tar_result;        // 目标结果
    void (*kv_func_cb)(void*);          // 符合匹配后调用的回调函数
} key_value_match_map_t;

```
- 关键算法:
```c
key_value_type_t operand_origin = button->kv_match_map_ptr.operand;
key_value_type_t operand_result = button->kv_match_map_ptr.operand;
kv_match_operator_type_t operator =button->kv_match_map_ptr.operator;
key_value_type_t tar_result = button->kv_match_map_ptr.tar_result;

if(operator == KV_MATCH_OPERATOR_NULL)
    operand_result = button->key_value;
else if(operator & KV_MATCH_OPERATOR_BITWISE_AND)
    operand_result = (operand_origin & button->key_value);
else if(operator & KV_MATCH_OPERATOR_BITWISE_OR)
    operand_result = (operand_origin | button->key_value);
else if(operator & KV_MATCH_OPERATOR_BITWISE_NOT)
    operand_result = ~(button->key_value);
else if(operator & KV_MATCH_OPERATOR_BITWISE_XOR)
    operand_result = (operand_origin ^ button->key_value);

if(operand_result == tar_result)
{
    button->kv_match_map_ptr.kv_func_cb(button);
}
```

- 支持的操作符:
```c
#define KV_MATCH_OPERATOR_NULL             (0)      // 无操作符,仅通过(key_value == tar_result)?判断, 默认是这个
#define KV_MATCH_OPERATOR_BITWISE_AND      (1 << 0) // 按位与操作符,(operand & key_value == tar_result)?
#define KV_MATCH_OPERATOR_BITWISE_OR       (1 << 1) // 按位或操作符,(operand | key_value == tar_result)?
#define KV_MATCH_OPERATOR_BITWISE_NOT      (1 << 2) // 按位取反操作符,(~ key_value == tar_result)?
#define KV_MATCH_OPERATOR_BITWISE_XOR      (1 << 2) // 按位异或操作符,(operand ^ key_value == tar_result)?
```

> 4.基于面向对象方式设计思路,每个按键对象单独用一份数据结构管理

## &#128203; 如何食用

### 1)使用
<details>
<summary>点击展开/折叠C代码<img src="https://img-blog.csdnimg.cn/img_convert/d8e9b8565a53e9bc02877440a4dd6749.gif" width="30"></summary>

- 以使用callback方式为例:
```c
// 1.包含头文件
#include "embedded_button.h"

// 2.定义按键实体
struct button_obj_t button1;

// 3.GPIO电平读取接口设置
uint8_t read_button_pin(uint8_t button_id)
{
    // you can share the GPIO read function with multiple Buttons
    switch(button_id)
    {
        case 0:
            return get_button1_value(); // 用户自行实现
            break;

        default:
            return 0;
            break;
    }

    return 0;
}

// 4. 配置键值匹配规则(设置回调事件)
void single_click_handle(void* btn)
{
    //do something...
    printf("/****single click****/\r\n");
}

void double_click_handle(void* btn)
{
    //do something...
    printf("/****double click****/\r\n");
}

void long_press_handle(void* btn)
{
    //do something...
    printf("/****long press****/\r\n");
}

void single_click_then_long_press_handle(void* btn)
{
    //do something...
    printf("/****single click and long press****/\r\n");
}

void quintuple_click_handle(void* btn)
{
    //do something...
    if(check_is_repeat_click_mode(btn))
        printf("/****quintuple click****/\r\n");
}

const key_value_match_map_t button1_map[] =
{
    {
        .tar_result = SINGLE_CLICK_KV,
        .kv_func_cb = single_click_handle
    },
    {
        .tar_result = DOUBLE_CLICK_KV,
        .kv_func_cb = double_click_handle
    },
    {
        .tar_result = LONG_PRESEE_START,
        .kv_func_cb = long_press_handle
    },
    {
        .tar_result = SINGLE_CLICK_THEN_LONG_PRESS_KV,
        .kv_func_cb = single_click_then_long_press_handle
    },
    {
        .operand = 0b1010101010,
        .operator = KV_MATCH_OPERATOR_BITWISE_AND,
        .tar_result = 0b1010101010,
        .kv_func_cb = quintuple_click_handle
    }
};
...

int main()
{
/************************************************
****5.初始化按键对象,参数含义分别为
****
****- 按键实体
****- 绑定按键的GPIO电平读取接口**read_button1_pin()**
****- 设置有效触发电平
****- 按键ID
****- 键值匹配规则配置表
****- 键值匹配规则配置表大小
*************************************************/
    button_init(&button1, read_button_pin, 0, 0, button1_map, ARRAY_SIZE(button1_map));
    // 6.启动按键
    button_start(&button1);

    // 7. 设置一个5ms间隔的定时器循环调用按键后台处理函数 button_ticks()
    __timer_start(button_ticks, 0, 5);

    while(1)
    {}
}
```
![在这里插入图片描述]()

<br></details>

### 2)调试

<details>
<summary>点击展开/折叠<img src="https://img-blog.csdnimg.cn/img_convert/d8e9b8565a53e9bc02877440a4dd6749.gif" width="30"></summary>

- 定义EB_DEBUG_PRINTF宏后将会开启键值打印,例如下面,需要将printf换成你的打印函数:
```c
#define EB_DEBUG_PRINTF printf
```
![在这里插入图片描述]()

<br></details>

## &#9889; 其他
- 本项目基于本人实际开发中遇到的一些按键驱动使用体验问题,在他人项目(见参考链接)的思想基础上,开发的此按键驱动模块,之前提到了本模块的优势,下面说下有待改进的地方:对于多按键时组合按键的表示方式,目前还没有想到比较优雅的实现方式,后续有头绪后会进一步改进,补齐这一环。最后,感谢帮助思考我的小伙伴[shawnfeng0](https://github.com/shawnfeng0)以及正在使用此模块的小伙伴,欢迎一起开发改进!
- 更多高级用法见 [examples](https://github.com/530china/Embe ... /examples/README.md)

## &#128172; 参考链接
- [MultiButton](https://github.com/0x1abin/MultiButton)
- [FlexibleButton](https://github.com/murphyzhao/FlexibleButton/tree/master)
- [安富莱按键FIFO思想](https://forum.anfulai.cn/forum.p ... hlight=%B0%B4%BC%FC)


评分

参与人数 1金币 +100 收起 理由
eric2013 + 100 很给力!

查看全部评分

回复

使用道具 举报

2

主题

5

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 2024-8-7 23:10:16 | 显示全部楼层
欢迎大家交流使用中不爽的地方,如果觉得该项目实现的思路还不错,希望大家能给项目点个start

https://github.com/530china/EmbeddedButton
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
117564
QQ
发表于 2024-8-8 08:45:30 | 显示全部楼层
谢谢楼主分享。
回复

使用道具 举报

4

主题

412

回帖

424

积分

高级会员

积分
424
发表于 2024-8-8 09:30:21 | 显示全部楼层
MultiButton用户路过,请问有什么主要区别呢
回复

使用道具 举报

2

主题

5

回帖

11

积分

新手上路

积分
11
 楼主| 发表于 2024-8-8 23:32:34 | 显示全部楼层
cctv180 发表于 2024-8-8 09:30
MultiButton用户路过,请问有什么主要区别呢

实现思路已经很不一样了,这个项目支持更灵活的按键定义而不用取修改框架的代码,支持位运算匹配,可以看看视频介绍:https://www.bilibili.com/video/BV1dRv9etEo7/
配合github的readme体会会更深
回复

使用道具 举报

0

主题

51

回帖

51

积分

初级会员

积分
51
发表于 2024-8-9 13:51:54 | 显示全部楼层
520China 发表于 2024-8-8 23:32
实现思路已经很不一样了,这个项目支持更灵活的按键定义而不用取修改框架的代码,支持位运算匹配,可以看 ...

看简介是带fifo的吗
回复

使用道具 举报

0

主题

36

回帖

36

积分

新手上路

积分
36
发表于 2024-8-11 08:37:47 | 显示全部楼层
不支持组合按键?
回复

使用道具 举报

10

主题

21

回帖

51

积分

初级会员

积分
51
发表于 2024-8-12 23:40:39 | 显示全部楼层
cctv180 发表于 2024-8-8 09:30
MultiButton用户路过,请问有什么主要区别呢

我也一直在用这个模块,真心不错
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-14 19:02 , Processed in 0.065759 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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