# FlexibleButton
FlexibleButton 是一个基于标准 C 语言的小巧灵活的按键处理库,支持单击、连击、短按、长按、自动消抖,可以自由设置组合按键,可用于中断和低功耗场景。
该按键库解耦了具体的按键硬件结构,理论上支持轻触按键与自锁按键,并可以无限扩展按键数量。另外,FlexibleButton 使用扫描的方式一次性读取所有所有的按键状态,然后通过事件回调机制上报按键事件。核心的按键扫描代码仅有三行,没错,就是经典的 **三行按键扫描算法**。使用 C 语言标准库 API 编写,也使得该按键库可以无缝兼容任意的处理器平台,并且支持任意 OS 和 non-OS(裸机编程)。
## 获取
### Git 方式
```SHELL
git clone https://github.com/murphyzhao/FlexibleButton.git
```
### RT-Thread menuconfig 方式
```
RT-Thread online packages --->
miscellaneous packages --->
[*] FlexibleButton: Small and flexible button driver --->
[*] Enable flexible button demo
version (latest) --->
```
配置完成后,输入 `pkgs --update` 下载软件包。
## 资源统计
ARMCC -O0 优化的情况下,FlexibleButton 资源占用如下:
- CODE:798 字节
- RO DATA:0
- RW DATA:13 字节
- ZI DATA:0
## 快速体验
FlexibleButton 库中提供了一个测试例程 [`./examples/demo_rtt_iotboard.c`](./examples/demo_rtt_iotboard.c),该例程基于 RT-Thread OS 进行测试,硬件平台选择了 *RT-Thread IoT Board Pandora v2.51* 开发板。当然你可以选择使用其他的 OS,或者使用裸机测试,只需要移除 OS 相关的特性即可。
如果你使用自己的硬件平台,只需要将 FlexibleButton 库源码和例程加入你既有的工程下即可。
## DEMO 程序说明
该示例程序可以直接在 RT-Thread [`stm32l475-atk-pandora`](https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32l475-atk-pandora) BSP 中运行,可以在该 BSP 目录下,使用 menuconfig 获取本软件包。
### 确定用户按键
```C
typedef enum
{
USER_BUTTON_0 = 0, // 对应 IoT Board 开发板的 PIN_KEY0
USER_BUTTON_1, // 对应 IoT Board 开发板的 PIN_KEY1
USER_BUTTON_2, // 对应 IoT Board 开发板的 PIN_KEY2
USER_BUTTON_3, // 对应 IoT Board 开发板的 PIN_WK_UP
USER_BUTTON_MAX
} user_button_t;
static flex_button_t user_button[USER_BUTTON_MAX];
```
上述代码定义了 4 个按键,数据结构存储在 `user_button` 数组中。
### 程序入口
```C
int flex_button_main(void)
{
rt_thread_t tid = RT_NULL;
user_button_init();
/* 创建按键扫描线程 flex_btn,线程栈 1024 byte,优先级 10 */
tid = rt_thread_create("flex_btn", button_scan, RT_NULL, 1024, 10, 10);
if(tid != RT_NULL)
{
rt_thread_startup(tid);
}
return 0;
}
/* 使用 RT-Thread 的自动初始化 */
INIT_APP_EXPORT(flex_button_main);
```
如上代码所示,首先使用 `user_button_init();` 初始化用户按键硬件,该步骤将用户按键绑定到 FlexibleButton 库。然后,使用 RT-Thread 的 `INIT_APP_EXPORT` 接口导出为上电自动初始化,创建了一个 “flex_btn” 名字的按键扫描线程,线程里扫描检查按键事件。
### 按键初始化代码
`user_button_init();` 初始化代码如下所示:
```C
static void user_button_init(void)
{
int i;
/* 初始化按键数据结构 */
rt_memset(&user_button[0], 0x0, sizeof(user_button));
/* 初始化 IoT Board 按键引脚,使用 rt-thread PIN 设备框架 */
rt_pin_mode(PIN_KEY0, PIN_MODE_INPUT_PULLUP); /* 设置 GPIO 为上拉输入模式 */
rt_pin_mode(PIN_KEY1, PIN_MODE_INPUT_PULLUP); /* 设置 GPIO 为上拉输入模式 */
rt_pin_mode(PIN_KEY2, PIN_MODE_INPUT_PULLUP); /* 设置 GPIO 为上拉输入模式 */
rt_pin_mode(PIN_WK_UP, PIN_MODE_INPUT_PULLDOWN); /* 设置 GPIO 为下拉输入模式 */
for (i = 0; i < USER_BUTTON_MAX; i ++)
{
user_button[i].id = i;
user_button[i].usr_button_read = common_btn_read;
user_button[i].cb = common_btn_evt_cb;
user_button[i].pressed_logic_level = 0;
user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500);
user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000);
user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500);
if (i == USER_BUTTON_3)
{
user_button[USER_BUTTON_3].pressed_logic_level = 1;
}
flex_button_register(&user_button[i]);
}
}
```
核心的配置如下:
|配置项|说明|
| :---- | :----|
| id | 按键编号 |
| usr_button_read | 设置按键读值回调函数 |
| cb | 设置按键事件回调函数 |
| pressed_logic_level | 设置按键按下时的逻辑电平 |
| short_press_start_tick | 短按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 |
| long_press_start_tick | 长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 |
| long_hold_start_tick | 超长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 |
注意,short_press_start_tick、long_press_start_tick 和 long_hold_start_tick 必须使用 `FLEX_MS_TO_SCAN_CNT` 将毫秒时间转化为扫描次数。
`user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500);` 表示按键按下开始计时,1500 ms 后按键依旧是按下状态的话,就断定为短按开始。
### 事件处理代码
```C
static void common_btn_evt_cb(void *arg)
{
flex_button_t *btn = (flex_button_t *)arg;
rt_kprintf("id: [%d - %s] event: [%d - %30s] repeat: %d\n",
btn->id, enum_btn_id_string[btn->id],
btn->event, enum_event_string[btn->event],
btn->click_cnt);
if (flex_button_event_read(&user_button[USER_BUTTON_0]) == flex_button_event_read(&user_button[USER_BUTTON_1]) == FLEX_BTN_PRESS_CLICK)
{
rt_kprintf("[combination]: button 0 and button 1\n");
}
}
```
示例代码中,将所有的按键事件回调均绑定到 `common_btn_evt_cb` 函数,在该函数中打印了按键 ID 和按键事件,以及按键连击次数,并演示了如何使用组合按键。
## FlexibleButton 代码说明
### 按键事件定义
按键事件的定义并没有使用 Windows 驱动上的定义,主要是方便嵌入式设备中的应用场景(也可能是我理解的偏差),按键事件定义如下:
```C
typedef enum
{
FLEX_BTN_PRESS_DOWN = 0, // 按下事件
FLEX_BTN_PRESS_CLICK, // 单击事件
FLEX_BTN_PRESS_DOUBLE_CLICK, // 双击事件
FLEX_BTN_PRESS_REPEAT_CLICK, // 连击事件,使用 flex_button_t 中的 click_cnt 断定连击次数
FLEX_BTN_PRESS_SHORT_START, // 短按开始事件
FLEX_BTN_PRESS_SHORT_UP, // 短按抬起事件
FLEX_BTN_PRESS_LONG_START, // 长按开始事件
FLEX_BTN_PRESS_LONG_UP, // 长按抬起事件
FLEX_BTN_PRESS_LONG_HOLD, // 长按保持事件
FLEX_BTN_PRESS_LONG_HOLD_UP, // 长按保持的抬起事件
FLEX_BTN_PRESS_MAX,
FLEX_BTN_PRESS_NONE,
} flex_button_event_t;
```
其中 `FLEX_BTN_PRESS_LONG_HOLD` 事件可以用来实现长按累加的应用场景。
### 按键数据结构
```C
typedef struct flex_button
{
struct flex_button* next;
uint8_t (*usr_button_read)(void *);
flex_button_response_callback cb;
uint16_t scan_cnt;
uint16_t click_cnt;
uint16_t max_multiple_clicks_interval;
uint16_t debounce_tick;
uint16_t short_press_start_tick;
uint16_t long_press_start_tick;
uint16_t long_hold_start_tick;
uint8_t id;
uint8_t pressed_logic_level : 1;
uint8_t event : 4;
uint8_t status : 3;
} flex_button_t;
```
| 序号 | 数据成员 | 是否需要用户初始化 | 说明 |
| :----: | :---- | :----: | :---- |
| 1 | next | 否 | 按键库使用�
没有合适的资源?快使用搜索试试~ 我知道了~
按键事件驱动,支持长按、短按、多按键捕获,c语言实现
共8个文件
c:3个
sconscript:1个
yml:1个
需积分: 5 0 下载量 119 浏览量
2023-09-22
16:31:57
上传
评论
收藏 19KB ZIP 举报
温馨提示
按键事件驱动,支持长按、短按、多按键捕获
资源推荐
资源详情
资源评论
收起资源包目录
FlexibleButton-master.zip (8个子文件)
.github
FUNDING.yml 682B
LICENSE 11KB
examples
demo_tos_evb_mx_plus.c 5KB
demo_rtt_iotboard.c 5KB
flexible_button.c 10KB
flexible_button.h 5KB
README.md 14KB
SConscript 347B
共 8 条
- 1
资源评论
陈大本事er
- 粉丝: 510
- 资源: 9
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功