EmbeddedButton,嵌入式按键处理框架

EmbeddedButton,嵌入式按键处理框架

👋 简介

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

🌱 特性

1.依靠简单几个原则,支持起整个按键判断逻辑

  • 只要键值非零,时间tick++
  • 只要按键状态发生变化,改变一次键值(__append_bit()),tick时间清零(确保tick为按下或抬起的时间)
  • 以tick时间的长短及按键抬起作为一次状态结束的判断依据,可以很好的实现短按长按等操作;

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

键值说明
0b0未按下
0b010单击
0b01010双击
0b01010…nn连击
0b011长按开始
0b0111长按保持
0b01110长按结束
0b01011短按然后长按
0b0101011双击然后长按
0b01010…n11n连击然后长按

3.核心处理采取数据驱动方式,支持位运算键值匹配:

  • 关键数据结构,键值匹配规则配置表:
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;

  • 关键算法:
key_value_type_t operand_origin = button->kv_match_map_ptr[i].operand;
key_value_type_t operand_result = button->kv_match_map_ptr[i].operand;
kv_match_operator_type_t operator =button->kv_match_map_ptr[i].operator;
key_value_type_t tar_result = button->kv_match_map_ptr[i].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[i].kv_func_cb(button);
}
  • 支持的操作符:
#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.基于面向对象方式设计思路,每个按键对象单独用一份数据结构管理

📋 如何食用

1)使用

点击展开/折叠C代码
  • 以使用callback方式为例:
// 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)
    {}
}

在这里插入图片描述


2)调试

点击展开/折叠
  • 定义EB_DEBUG_PRINTF宏后将会开启键值打印,例如下面,需要将printf换成你的打印函数:
#define EB_DEBUG_PRINTF printf

在这里插入图片描述


⚡ 其他

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

💬 参考链接

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值