EmbeddedButton嵌入式按键驱动设计实现

电子说

1.3w人已加入

描述

EmbeddedButton

简介

EmbeddedButton是一个轻量级简单易用的嵌入式按键驱动模块,可无限拓展按键,支持多连击、长按、短按长按等多种按键事件;该模块通过异步回调方式来简化程序结构,根据几个简单原则完成了整个代码逻辑的支撑。

使用方法

1.定义按键实体

struct button_obj_t button1;

2.建立键值映射表(设置回调事件)

const key_value_map_t button1_map[] =
{
{
.key_value = SINGLE_CLICK_KV,
.kv_func_cb = single_press_handle
},
{
.key_value = LONG_PRESEE_START,
.kv_func_cb = long_press_handle
},
{
.key_value = SINGLE_CLICK_THEN_LONG_PRESS_KV,
.kv_func_cb = single_press_then_long_press_handle
},
};

3.初始化按键对象,参数含义分别为

按键实体
绑定按键的GPIO电平读取接口read_button1_pin()
设置有效触发电平
按键ID
键值映射表
键值映射表大小
button_init(&button1, read_button1_pin, 0, 0, button1_map, ARRAY_SIZE(button1_map));

4.启动按键

button_start(&button1);
5.设置一个5ms间隔的定时器循环调用按键后台处理函数

while(1) {
...
if(timer_ticks == 5) {
timer_ticks = 0;
button_ticks();
}
}

特性

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

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

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

定时器

3.利用数据驱动思想完成对应按键事件的调用:

typedef struct {
key_value_type_t key_value;
void ( kv_func_cb)(void );
} key_value_map_t;
const key_value_map_t button1_map[] =
{
{
.key_value = SINGLE_CLICK_KV,
.kv_func_cb = single_press_handle
},
{
.key_value = LONG_PRESEE_START,
.kv_func_cb = long_press_handle
},
{
.key_value = SINGLE_CLICK_THEN_LONG_PRESS_KV,
.kv_func_cb = single_press_then_long_press_handle
},
};
for(size_t i = 0; i < button->map_size; i++) {
if((button->map_ptr[i].key_value == button->key_value)
&& (button->map_ptr[i].kv_func_cb))
{
button->map_ptr[i].kv_func_cb(button);
}
}

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

typedef struct button_obj_t {
uint8_t debounce_cnt : 4;
uint8_t active_level : 1;
uint8_t read_level : 1;
uint8_t read_level_update : 1;
uint8_t event_analyze_en : 1;
uint8_t id;
uint16_t ticks;
state_bits_type_t state_bits;
key_value_type_t key_value;
uint8_t (* read_button_func_ptr)(uint8_t button_id );
const key_value_map_t map_ptr;
size_t map_size;
struct button_obj_t
next;
}button_obj_t;
Examples
#include "embedded_button.h"
struct button_obj_t button1;
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(); //Require self implementation
break;
default:
return 0;
break;
}
return 0;
}
void single_click_handle(void* btn)
{
//do something...
printf("/ single click /rn");
}
void double_click_handle(void* btn)
{
//do something...
printf("/ double click /rn");
}
void long_press_handle(void* btn)
{
//do something...
printf("/ long press /rn");
}
void single_click_then_long_press_handle(void* btn)
{
//do something...
printf("/ single click and long press /rn");
}
void double_click_then_long_press_handle(void* btn)
{
//do something...
printf("/ double click and long press /rn");
}
const key_value_map_t button1_map[] =
{
{
.key_value = SINGLE_CLICK_KV,
.kv_func_cb = single_click_handle
},
{
.key_value = DOUBLE_CLICK_KV,
.kv_func_cb = double_click_handle
},
{
.key_value = LONG_PRESEE_START,
.kv_func_cb = long_press_handle
},
{
.key_value = SINGLE_CLICK_THEN_LONG_PRESS_KV,
.kv_func_cb = single_click_then_long_press_handle
},
{
.key_value = DOUBLE_CLICK_THEN_LONG_PRESS_KV,
.kv_func_cb = double_click_then_long_press_handle
}
};
...
int main()
{
button_init(&button1, read_button_pin, 0, 0, button1_map, ARRAY_SIZE(button1_map));
button_start(&button1);
//make the timer invoking the button_ticks() interval 5ms.
//This function is implemented by yourself.
__timer_start(button_ticks, 0, 5);
while(1)
{}
}

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分