更新按键驱动
This commit is contained in:
@@ -4,12 +4,13 @@ list(APPEND incs "../components/system/source")
|
|||||||
list(APPEND incs "../components/system/source/k_kit")
|
list(APPEND incs "../components/system/source/k_kit")
|
||||||
list(APPEND incs "../components/system/source/shell")
|
list(APPEND incs "../components/system/source/shell")
|
||||||
|
|
||||||
list(APPEND srcs "../app/app_main.c")
|
list(APPEND srcs "app_main.c")
|
||||||
list(APPEND srcs "../app/console.c")
|
list(APPEND srcs "console.c")
|
||||||
list(APPEND srcs "../app/drivers/data_port/sb_data_port.c")
|
list(APPEND srcs "drivers/data_port/sb_data_port.c")
|
||||||
list(APPEND srcs "../app/drivers/data_port/uart/uart_port.c")
|
list(APPEND srcs "drivers/data_port/uart/uart_port.c")
|
||||||
list(APPEND srcs "../app/button/button_event.c")
|
list(APPEND srcs "button/button.c")
|
||||||
list(APPEND srcs "../app/config/board_config.c")
|
list(APPEND srcs "button/multi_button.c")
|
||||||
|
list(APPEND srcs "config/board_config.c")
|
||||||
|
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
INCLUDE_DIRS ${incs}
|
INCLUDE_DIRS ${incs}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
|
|
||||||
/* 通用模块 */
|
/* 通用模块 */
|
||||||
#include "button/button_event.h"
|
#include "button/button.h"
|
||||||
|
|
||||||
/* 应用模块 */
|
/* 应用模块 */
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ nvs_handle g_nvs_hdl; // nvs 句柄
|
|||||||
os_work_q_t g_work_q_hdl_low; // 低于 default_os_work_q_hdl 优先级的工作队列
|
os_work_q_t g_work_q_hdl_low; // 低于 default_os_work_q_hdl 优先级的工作队列
|
||||||
|
|
||||||
static void _init_nvs(void);
|
static void _init_nvs(void);
|
||||||
static int _change_mode_event_button(const button_event_t *event);
|
static void _change_mode_event_button(button_hdl_t *handle, press_event_t event);
|
||||||
static void _vset_cb(sh_t *sh_hdl);
|
static void _vset_cb(sh_t *sh_hdl);
|
||||||
|
|
||||||
void work_app_main(void *arg)
|
void work_app_main(void *arg)
|
||||||
@@ -39,9 +39,7 @@ void work_app_main(void *arg)
|
|||||||
_init_nvs();
|
_init_nvs();
|
||||||
|
|
||||||
/* 初始化按键检测和控制 */
|
/* 初始化按键检测和控制 */
|
||||||
button_init(PIN_BIT(g_cfg_board->key_boot.pin), g_cfg_board->key_boot.en_lev);
|
btn_attach(&g_cfg_board->key_boot, _change_mode_event_button, EVENT_PRESS_UP | EVENT_PRESS_DOWN | EVENT_LONG_PRESS_HOLD);
|
||||||
|
|
||||||
button_event_add_callback(g_cfg_board->key_boot.pin, _change_mode_event_button);
|
|
||||||
|
|
||||||
/* 启动 shell */
|
/* 启动 shell */
|
||||||
SYS_LOG_INF("app start");
|
SYS_LOG_INF("app start");
|
||||||
@@ -59,19 +57,17 @@ static void _init_nvs(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _change_mode_event_button(const button_event_t *event)
|
static void _change_mode_event_button(button_hdl_t *handle, press_event_t event)
|
||||||
{
|
{
|
||||||
static const char *const stat_tab[] = {
|
static const char *const stat_tab[] = {
|
||||||
[BUTTON_UP] = "up",
|
[PRESS_UP] = "up",
|
||||||
[BUTTON_DOWN] = "down",
|
[PRESS_DOWN] = "down",
|
||||||
[BUTTON_HELD] = "held",
|
[LONG_PRESS_HOLD] = "held",
|
||||||
};
|
};
|
||||||
if (event->event < __ARRAY_SIZE(stat_tab))
|
if (event < __ARRAY_SIZE(stat_tab) && stat_tab[event])
|
||||||
{
|
{
|
||||||
SYS_LOG_DBG("button stat: %s", stat_tab[event->event]);
|
SYS_LOG_DBG("button stat: %s", stat_tab[event]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _vset_cb(sh_t *sh_hdl)
|
static void _vset_cb(sh_t *sh_hdl)
|
||||||
|
|||||||
131
app/button/README.md
Normal file
131
app/button/README.md
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# MultiButton
|
||||||
|
|
||||||
|
## 简介
|
||||||
|
MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
1.先申请一个按键结构
|
||||||
|
|
||||||
|
```c
|
||||||
|
button_hdl_t button1;
|
||||||
|
```
|
||||||
|
2.初始化按键对象,绑定按键的GPIO电平读取接口**read_button_pin()** ,后一个参数设置有效触发电平
|
||||||
|
|
||||||
|
```c
|
||||||
|
button_init(&button1, read_button_pin, 0, 0);
|
||||||
|
```
|
||||||
|
3.注册按键事件
|
||||||
|
|
||||||
|
```c
|
||||||
|
button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler);
|
||||||
|
button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler);
|
||||||
|
...
|
||||||
|
```
|
||||||
|
4.启动按键
|
||||||
|
|
||||||
|
```c
|
||||||
|
button_start(&button1);
|
||||||
|
```
|
||||||
|
5.设置一个5ms间隔的定时器循环调用后台处理函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
while(1) {
|
||||||
|
...
|
||||||
|
if(timer_ticks == 5) {
|
||||||
|
timer_ticks = 0;
|
||||||
|
|
||||||
|
button_ticks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
MultiButton 使用C语言实现,基于面向对象方式设计思路,每个按键对象单独用一份数据结构管理:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Button {
|
||||||
|
uint16_t ticks;
|
||||||
|
uint8_t repeat: 4;
|
||||||
|
uint8_t event : 4;
|
||||||
|
uint8_t state : 3;
|
||||||
|
uint8_t debounce_cnt : 3;
|
||||||
|
uint8_t active_level : 1;
|
||||||
|
uint8_t button_level : 1;
|
||||||
|
uint8_t button_id;
|
||||||
|
uint8_t (*hal_button_Level)(uint8_t button_id_);
|
||||||
|
button_callback_fn cb[number_of_event];
|
||||||
|
struct Button* next;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。
|
||||||
|
|
||||||
|
|
||||||
|
## 按键事件
|
||||||
|
|
||||||
|
事件 | 说明
|
||||||
|
---|---
|
||||||
|
PRESS_DOWN | 按键按下,每次按下都触发
|
||||||
|
PRESS_UP | 按键弹起,每次松开都触发
|
||||||
|
PRESS_REPEAT | 重复按下触发,变量repeat计数连击次数
|
||||||
|
SINGLE_CLICK | 单击按键事件
|
||||||
|
DOUBLE_CLICK | 双击按键事件
|
||||||
|
LONG_PRESS_START | 达到长按时间阈值时触发一次
|
||||||
|
LONG_PRESS_HOLD | 长按期间一直触发
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "button.h"
|
||||||
|
|
||||||
|
unit8_t btn1_id = 0;
|
||||||
|
|
||||||
|
struct Button btn1;
|
||||||
|
|
||||||
|
uint8_t read_button_GPIO(uint8_t button_id)
|
||||||
|
{
|
||||||
|
// you can share the GPIO read function with multiple Buttons
|
||||||
|
switch(button_id)
|
||||||
|
{
|
||||||
|
case btn1_id:
|
||||||
|
return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void BTN1_PRESS_DOWN_Handler(void* btn)
|
||||||
|
{
|
||||||
|
//do something...
|
||||||
|
}
|
||||||
|
|
||||||
|
void BTN1_PRESS_UP_Handler(void* btn)
|
||||||
|
{
|
||||||
|
//do something...
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
button_init(&btn1, read_button_GPIO, 0, btn1_id);
|
||||||
|
button_attach(&btn1, PRESS_DOWN, BTN1_PRESS_DOWN_Handler);
|
||||||
|
button_attach(&btn1, PRESS_UP, BTN1_PRESS_UP_Handler);
|
||||||
|
button_attach(&btn1, PRESS_REPEAT, BTN1_PRESS_REPEAT_Handler);
|
||||||
|
button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_Click_Handler);
|
||||||
|
button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_Click_Handler);
|
||||||
|
button_attach(&btn1, LONG_PRESS_START, BTN1_LONG_PRESS_START_Handler);
|
||||||
|
button_attach(&btn1, LONG_PRESS_HOLD, BTN1_LONG_PRESS_HOLD_Handler);
|
||||||
|
button_start(&btn1);
|
||||||
|
|
||||||
|
//make the timer invoking the button_ticks() interval 5ms.
|
||||||
|
//This function is implemented by yourself.
|
||||||
|
__timer_start(button_ticks, 0, 5);
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
```
|
||||||
69
app/button/button.c
Normal file
69
app/button/button.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include "button.h"
|
||||||
|
#include "multi_button.h"
|
||||||
|
|
||||||
|
#include "drivers/chip/gpio.h"
|
||||||
|
#include "os/os.h"
|
||||||
|
|
||||||
|
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
|
||||||
|
#define SYS_LOG_DOMAIN "BUTTON"
|
||||||
|
#include "sys_log.h"
|
||||||
|
|
||||||
|
static os_work_t s_work_hdl;
|
||||||
|
|
||||||
|
static uint8_t _port_pin_level(uint8_t button_id);
|
||||||
|
static void _work_handler_button(void *pvParameter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 添加一个按键
|
||||||
|
*
|
||||||
|
* @param pin 引脚配置
|
||||||
|
* @param cb 回调函数
|
||||||
|
* @param event_mask 触发事件源。 @ref EVENT_MASK
|
||||||
|
* @retval handler
|
||||||
|
*/
|
||||||
|
button_hdl_t *btn_attach(const cfg_board_pin_io_t *pin,
|
||||||
|
button_callback_fn cb,
|
||||||
|
uint8_t event_mask)
|
||||||
|
{
|
||||||
|
button_hdl_t *handle = os_malloc(sizeof(button_hdl_t));
|
||||||
|
if (handle == NULL)
|
||||||
|
{
|
||||||
|
SYS_LOG_WRN("operation fail");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv_gpio_pin_configure(pin->pin, _GPIO_DIR_IN, pin->en_lev ? _GPIO_PUD_PULL_DOWN : _GPIO_PUD_PULL_UP);
|
||||||
|
|
||||||
|
button_init(handle, _port_pin_level, pin->en_lev, pin->pin);
|
||||||
|
button_attach(handle, event_mask, cb);
|
||||||
|
button_start(handle);
|
||||||
|
|
||||||
|
os_work_create_default(&s_work_hdl, "", _work_handler_button, NULL, OS_PRIORITY_HIGHEST, 10);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void btn_delete(button_hdl_t *handler)
|
||||||
|
{
|
||||||
|
if (handler)
|
||||||
|
{
|
||||||
|
button_stop(handler);
|
||||||
|
os_free(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
press_event_t btn_get_event(button_hdl_t *handle)
|
||||||
|
{
|
||||||
|
return get_button_event(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _work_handler_button(void *pvParameter)
|
||||||
|
{
|
||||||
|
os_work_later(TICKS_INTERVAL);
|
||||||
|
button_ticks();
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t _port_pin_level(uint8_t button_id)
|
||||||
|
{
|
||||||
|
return drv_gpio_pin_read(button_id);
|
||||||
|
}
|
||||||
23
app/button/button.h
Normal file
23
app/button/button.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* @file button.h
|
||||||
|
* @author LokLiang
|
||||||
|
* @brief 按键接口,是结合 board_config 并对 multi_button 模块的封装
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-04-23
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "multi_button.h"
|
||||||
|
#include "config/board_config.h"
|
||||||
|
|
||||||
|
button_hdl_t *btn_attach(const cfg_board_pin_io_t *pin,
|
||||||
|
button_callback_fn cb,
|
||||||
|
uint8_t event_mask);
|
||||||
|
|
||||||
|
void btn_delete(button_hdl_t *handler);
|
||||||
|
|
||||||
|
press_event_t btn_get_event(button_hdl_t *handle);
|
||||||
@@ -1,395 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
|
|
||||||
#include "os/os.h"
|
|
||||||
|
|
||||||
#include "button_event.h"
|
|
||||||
|
|
||||||
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_WRN
|
|
||||||
#define SYS_LOG_DOMAIN "BUTTON"
|
|
||||||
#include "sys_log.h"
|
|
||||||
|
|
||||||
#define VOLTAGE_HIGH 1 // 高电平有效
|
|
||||||
#define VOLTAGE_LOW 0 // 高电平有效
|
|
||||||
|
|
||||||
#define DEBOUNCE_CHECK_VOLTAGE_CHANGED 1
|
|
||||||
#define DEBOUNCE_CHECK_VOLTAGE_DID_NOT_CHANGED 0
|
|
||||||
|
|
||||||
#define DEBOUCE_CHECK_MAX_TIMES 5
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t pin;
|
|
||||||
uint8_t is_inverted; // 是否反向,如果为真的话,则当按钮按下后,引脚为低电平
|
|
||||||
uint16_t history;
|
|
||||||
uint32_t down_time;
|
|
||||||
uint32_t next_long_time;
|
|
||||||
int current_voltage; // 当前引脚电平
|
|
||||||
int debounce_check_counter;
|
|
||||||
uint8_t allow_multiple_long_press_event;
|
|
||||||
uint8_t long_press_event_sent;
|
|
||||||
} debounce_t;
|
|
||||||
|
|
||||||
int pin_count = -1;
|
|
||||||
debounce_t *debounce;
|
|
||||||
static os_queue_t s_event_queue; // 当出现按键变化时被传送到的队列对象
|
|
||||||
static button_callback_t *g_callback_list_head = NULL;
|
|
||||||
static button_callback_t *g_callback_list_tail = NULL;
|
|
||||||
static os_work_t s_work_hdl;
|
|
||||||
|
|
||||||
static os_queue_t *_pulled_button_init(unsigned long long pin_select, gpio_pull_mode_t pull_mode);
|
|
||||||
|
|
||||||
static uint32_t millis()
|
|
||||||
{
|
|
||||||
return os_get_sys_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int send_event(debounce_t *db, button_event_e ev)
|
|
||||||
{
|
|
||||||
static char *const ev_tbl[] = {
|
|
||||||
[BUTTON_UP] = "release",
|
|
||||||
[BUTTON_DOWN] = "press",
|
|
||||||
[BUTTON_HELD] = "held"};
|
|
||||||
SYS_ASSERT(ev < sizeof(ev_tbl), "ev: %d", ev);
|
|
||||||
SYS_LOG_DBG("event happend: pinnum: %d, ev: %s", db->pin, ev_tbl[ev]);
|
|
||||||
|
|
||||||
button_event_t event = {
|
|
||||||
.pin = db->pin,
|
|
||||||
.event = ev,
|
|
||||||
};
|
|
||||||
|
|
||||||
os_queue_send(&s_event_queue, &event, 0);
|
|
||||||
|
|
||||||
button_callback_t *tmp = g_callback_list_head;
|
|
||||||
button_callback_t *callback_list = NULL;
|
|
||||||
button_callback_t *callback_list_it = NULL;
|
|
||||||
while (tmp != NULL)
|
|
||||||
{
|
|
||||||
if (tmp->pin == db->pin)
|
|
||||||
{
|
|
||||||
button_callback_t *new_callback = NULL;
|
|
||||||
if (callback_list == NULL)
|
|
||||||
{
|
|
||||||
callback_list = os_malloc(sizeof(button_callback_t));
|
|
||||||
callback_list_it = callback_list;
|
|
||||||
new_callback = callback_list_it;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
new_callback = os_malloc(sizeof(button_callback_t));
|
|
||||||
}
|
|
||||||
new_callback->pin = db->pin;
|
|
||||||
new_callback->event_callback = tmp->event_callback;
|
|
||||||
new_callback->next = NULL;
|
|
||||||
|
|
||||||
if (new_callback != callback_list_it)
|
|
||||||
{
|
|
||||||
callback_list_it->next = new_callback;
|
|
||||||
callback_list_it = new_callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = callback_list;
|
|
||||||
int stop_forward_event = 0;
|
|
||||||
while (tmp != NULL)
|
|
||||||
{
|
|
||||||
if (tmp->pin == db->pin)
|
|
||||||
{
|
|
||||||
SYS_LOG_DBG("do call back: pinnum: %d, ev: %s", db->pin, ev_tbl[ev]);
|
|
||||||
stop_forward_event = tmp->event_callback(&event);
|
|
||||||
if (stop_forward_event)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 释放临时遍历对象
|
|
||||||
tmp = callback_list;
|
|
||||||
while (tmp)
|
|
||||||
{
|
|
||||||
button_callback_t *next_obj = tmp->next;
|
|
||||||
|
|
||||||
os_free(tmp);
|
|
||||||
tmp = next_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stop_forward_event;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int update_debounce_counter(int pin_index)
|
|
||||||
{
|
|
||||||
debounce_t *button_event_info = &debounce[pin_index];
|
|
||||||
int level = gpio_get_level(button_event_info->pin);
|
|
||||||
if (button_event_info->current_voltage != level)
|
|
||||||
{
|
|
||||||
button_event_info->debounce_check_counter += 1;
|
|
||||||
}
|
|
||||||
else if (button_event_info->current_voltage == level && button_event_info->debounce_check_counter > 0)
|
|
||||||
{
|
|
||||||
button_event_info->debounce_check_counter -= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 防抖检测已经连续多次检测到相同的电平,则改变按钮当前的电平
|
|
||||||
if (button_event_info->debounce_check_counter == DEBOUCE_CHECK_MAX_TIMES)
|
|
||||||
{
|
|
||||||
button_event_info->current_voltage = level;
|
|
||||||
button_event_info->debounce_check_counter = 0;
|
|
||||||
SYS_LOG_DBG("button voltage changed, pin:%d, voltage:%d", button_event_info->pin, level);
|
|
||||||
return DEBOUNCE_CHECK_VOLTAGE_CHANGED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DEBOUNCE_CHECK_VOLTAGE_DID_NOT_CHANGED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_button_down(int pin_index)
|
|
||||||
{
|
|
||||||
debounce_t *button_event_info = &debounce[pin_index];
|
|
||||||
|
|
||||||
if (button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_LOW)
|
|
||||||
{
|
|
||||||
// 如果电平是反向的,并且当前是低电平,则认为按钮按下了
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (!button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_HIGH)
|
|
||||||
{
|
|
||||||
// 如果电平不是反向的,并且当前是高电平,则认为按钮按下了
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_button_up(int pin_index)
|
|
||||||
{
|
|
||||||
debounce_t *button_event_info = &debounce[pin_index];
|
|
||||||
|
|
||||||
if (button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_HIGH)
|
|
||||||
{
|
|
||||||
// 如果电平是反向的,并且当前是高电平,则认为按钮释放了
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (!button_event_info->is_inverted && button_event_info->current_voltage == VOLTAGE_LOW)
|
|
||||||
{
|
|
||||||
// 如果电平不是反向的,并且当前是低电平,则认为按钮释放了
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _work_handler_button(void *pvParameter)
|
|
||||||
{
|
|
||||||
static uint8_t cancel_laster_event = 1;
|
|
||||||
|
|
||||||
for (int idx = 0; idx < pin_count; idx++)
|
|
||||||
{
|
|
||||||
debounce_t *button_event_info = &debounce[idx];
|
|
||||||
|
|
||||||
int check_result = update_debounce_counter(idx); // 防抖处理
|
|
||||||
if (check_result == DEBOUNCE_CHECK_VOLTAGE_DID_NOT_CHANGED)
|
|
||||||
{
|
|
||||||
// 如果allow_multiple_long_press_event为false,则一次长按无论长按多久,只会触发一次长按事件
|
|
||||||
if (!button_event_info->allow_multiple_long_press_event && button_event_info->long_press_event_sent != 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 电平没有变化,则检查按钮是否已经按下,以开始检查长按操作
|
|
||||||
if (button_event_info->down_time && millis() >= button_event_info->next_long_time)
|
|
||||||
{
|
|
||||||
button_event_info->next_long_time = millis() + LONG_PRESS_REPEAT;
|
|
||||||
button_event_info->long_press_event_sent = 1;
|
|
||||||
cancel_laster_event = send_event(&debounce[idx], BUTTON_HELD);
|
|
||||||
if (cancel_laster_event)
|
|
||||||
{
|
|
||||||
button_event_info->down_time = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 电平有变化,检查是按下还是松开
|
|
||||||
if (button_event_info->down_time == 0 && is_button_down(idx))
|
|
||||||
{
|
|
||||||
cancel_laster_event = 0;
|
|
||||||
SYS_LOG_DBG("update downtime for pin:%d", button_event_info->pin);
|
|
||||||
button_event_info->down_time = millis();
|
|
||||||
button_event_info->next_long_time = button_event_info->down_time + LONG_PRESS_DURATION;
|
|
||||||
cancel_laster_event = send_event(&debounce[idx], BUTTON_DOWN);
|
|
||||||
if (cancel_laster_event)
|
|
||||||
{
|
|
||||||
button_event_info->down_time = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (button_event_info->down_time && is_button_up(idx))
|
|
||||||
{
|
|
||||||
button_event_info->down_time = 0;
|
|
||||||
button_event_info->long_press_event_sent = 0;
|
|
||||||
cancel_laster_event = send_event(&debounce[idx], BUTTON_UP);
|
|
||||||
if (cancel_laster_event)
|
|
||||||
{
|
|
||||||
button_event_info->down_time = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
os_work_later(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化按电平式的按键检测。
|
|
||||||
* 这将创建一个用于扫描按键的线程,当检测到按键变化时,将在线程中产生两种通知:
|
|
||||||
* 1. 发送到内部创建的队列中(提示:如果使用了 os_queue_regist() 注册工作项,该工作项将被自动唤醒)
|
|
||||||
* 2. 执行由 button_event_add_callback() 设置的回调函数(提示:同一引脚可设置多个回调)
|
|
||||||
*
|
|
||||||
* @param pin_select 按位表示 MCU 的引脚呈
|
|
||||||
* @param en_lev 触发电平
|
|
||||||
* @return os_queue_t* 由内部创建的消息队列
|
|
||||||
*/
|
|
||||||
os_queue_t *button_init(unsigned long long pin_select, uint8_t en_lev)
|
|
||||||
{
|
|
||||||
return _pulled_button_init(pin_select, en_lev == 0 ? GPIO_PULLUP_ONLY : GPIO_PULLDOWN_ONLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
static os_queue_t *_pulled_button_init(unsigned long long pin_select, gpio_pull_mode_t pull_mode)
|
|
||||||
{
|
|
||||||
if (pin_count != -1)
|
|
||||||
{
|
|
||||||
SYS_LOG_WRN("Already initialized");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the pins
|
|
||||||
gpio_config_t io_conf;
|
|
||||||
io_conf.mode = GPIO_MODE_INPUT;
|
|
||||||
io_conf.pull_up_en = (pull_mode == GPIO_PULLUP_ONLY || pull_mode == GPIO_PULLUP_PULLDOWN);
|
|
||||||
io_conf.pull_down_en = (pull_mode == GPIO_PULLDOWN_ONLY || pull_mode == GPIO_PULLUP_PULLDOWN);
|
|
||||||
io_conf.pin_bit_mask = pin_select;
|
|
||||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
|
|
||||||
// Scan the pin map to determine number of pins
|
|
||||||
pin_count = 0;
|
|
||||||
int pin = 0;
|
|
||||||
for (pin = 0; pin < sizeof(pin_select) * 8; pin++)
|
|
||||||
{
|
|
||||||
if ((1ULL << pin) & pin_select)
|
|
||||||
{
|
|
||||||
pin_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize global state and s_event_queue
|
|
||||||
debounce = os_calloc(sizeof(debounce_t) * pin_count);
|
|
||||||
// s_event_queue = xQueueCreate(4, sizeof(button_event_t));
|
|
||||||
os_queue_create(&s_event_queue, 4, sizeof(button_event_t));
|
|
||||||
|
|
||||||
// Scan the pin map to determine each pin number, populate the state
|
|
||||||
uint32_t idx = 0;
|
|
||||||
for (pin = 0; pin < sizeof(pin_select) * 8; pin++)
|
|
||||||
{
|
|
||||||
if ((1ULL << pin) & pin_select)
|
|
||||||
{
|
|
||||||
SYS_LOG_DBG("Registering button input: %d", pin);
|
|
||||||
debounce_t *button_event_info = &debounce[idx];
|
|
||||||
|
|
||||||
button_event_info->pin = pin;
|
|
||||||
button_event_info->down_time = 0;
|
|
||||||
button_event_info->allow_multiple_long_press_event = 1;
|
|
||||||
button_event_info->is_inverted = (pull_mode == GPIO_PULLUP_ONLY);
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
os_work_create(&s_work_hdl, "", _work_handler_button, NULL, OS_PRIORITY_HIGHEST);
|
|
||||||
os_work_submit(default_os_work_q_hdl, &s_work_hdl, 1000);
|
|
||||||
|
|
||||||
SYS_LOG_INF("Initialized");
|
|
||||||
|
|
||||||
return &s_event_queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 添加回调函数:当由 button_init() 设置的对应的引脚号产生按键状态变化时,由内部线程创建执行的回调函数。
|
|
||||||
*
|
|
||||||
* @param pin 0..n
|
|
||||||
* @param callback int (*)(const button_event_t *event)
|
|
||||||
*/
|
|
||||||
void button_event_add_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback)
|
|
||||||
{
|
|
||||||
button_callback_t *callback_obj = os_malloc(sizeof(button_callback_t));
|
|
||||||
callback_obj->pin = pin;
|
|
||||||
callback_obj->event_callback = callback;
|
|
||||||
callback_obj->next = NULL;
|
|
||||||
if (g_callback_list_head == NULL)
|
|
||||||
{
|
|
||||||
g_callback_list_head = callback_obj;
|
|
||||||
g_callback_list_tail = g_callback_list_head;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_callback_list_tail->next = callback_obj;
|
|
||||||
g_callback_list_tail = callback_obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void button_event_remove_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback)
|
|
||||||
{
|
|
||||||
button_callback_t *tmp = g_callback_list_head;
|
|
||||||
button_callback_t *previous_item = NULL;
|
|
||||||
SYS_LOG_DBG("remove pin:%d", pin);
|
|
||||||
while (tmp != NULL)
|
|
||||||
{
|
|
||||||
if (tmp->event_callback == callback && tmp->pin == pin)
|
|
||||||
{
|
|
||||||
if (previous_item)
|
|
||||||
{
|
|
||||||
previous_item->next = tmp->next; // 断开当前点节,并将前一个和后一个连接起来
|
|
||||||
os_free(tmp);
|
|
||||||
SYS_LOG_DBG("found item");
|
|
||||||
tmp = previous_item->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 没有上一个节点,则将头部节点,设置为待移除节点的下一个节点
|
|
||||||
if (tmp->next)
|
|
||||||
{
|
|
||||||
g_callback_list_head = tmp->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_callback_list_head = NULL;
|
|
||||||
SYS_LOG_DBG("####!!!!#####!!!!");
|
|
||||||
}
|
|
||||||
os_free(tmp);
|
|
||||||
tmp = g_callback_list_head;
|
|
||||||
SYS_LOG_DBG("case111");
|
|
||||||
}
|
|
||||||
SYS_LOG_DBG("2222");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previous_item = tmp;
|
|
||||||
tmp = tmp->next;
|
|
||||||
SYS_LOG_DBG("1111");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新g_callback_list_tail指针
|
|
||||||
while (tmp != NULL)
|
|
||||||
{
|
|
||||||
g_callback_list_tail = tmp;
|
|
||||||
tmp = tmp->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
SYS_LOG_DBG("doneeee1");
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file button_event.h
|
|
||||||
* @author your name (you@domain.com)
|
|
||||||
* @brief
|
|
||||||
* @version 0.1
|
|
||||||
* @date 2023-09-04
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2023
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "os/os.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
|
|
||||||
#define PIN_BIT(x) (1ULL << x)
|
|
||||||
|
|
||||||
#define LONG_PRESS_DURATION (1000)
|
|
||||||
#define LONG_PRESS_REPEAT (200)
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
BUTTON_UP,
|
|
||||||
BUTTON_DOWN,
|
|
||||||
BUTTON_HELD
|
|
||||||
} button_event_e;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint32_t pin;
|
|
||||||
button_event_e event;
|
|
||||||
} button_event_t;
|
|
||||||
|
|
||||||
typedef int (*BUTTON_EVENT_CALLBACK)(const button_event_t *event);
|
|
||||||
|
|
||||||
typedef struct button_callback_s
|
|
||||||
{
|
|
||||||
struct button_callback_s *next;
|
|
||||||
uint32_t pin;
|
|
||||||
BUTTON_EVENT_CALLBACK event_callback;
|
|
||||||
} button_callback_t;
|
|
||||||
|
|
||||||
os_queue_t *button_init(unsigned long long pin_select, uint8_t en_lev);
|
|
||||||
|
|
||||||
void button_event_add_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback);
|
|
||||||
void button_event_remove_callback(uint32_t pin, BUTTON_EVENT_CALLBACK callback);
|
|
||||||
264
app/button/multi_button.c
Normal file
264
app/button/multi_button.c
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
|
||||||
|
* All rights reserved
|
||||||
|
* https://github.com/0x1abin/MultiButton
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "multi_button.h"
|
||||||
|
|
||||||
|
#define CONFIG_SYS_LOG_LEVEL SYS_LOG_LEVEL_ERR
|
||||||
|
#define SYS_LOG_DOMAIN "MAIN"
|
||||||
|
#include "sys_log.h"
|
||||||
|
|
||||||
|
#define EVENT_CB(ev) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if ((1U << ev) & handle->event_cb) \
|
||||||
|
handle->cb((void *)handle, ev); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define PRESS_REPEAT_MAX_NUM 15 /*!< The maximum value of the repeat counter */
|
||||||
|
|
||||||
|
// button handle list head.
|
||||||
|
static button_hdl_t *head_handle = NULL;
|
||||||
|
|
||||||
|
static void button_handler(button_hdl_t *handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the button struct handle.
|
||||||
|
* @param handle: the button handle struct.
|
||||||
|
* @param pin_level: read the HAL GPIO of the connected button level.
|
||||||
|
* @param active_level: pressed GPIO level.
|
||||||
|
* @param button_id: the button id.
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void button_init(button_hdl_t *handle, uint8_t (*pin_level)(uint8_t button_id), uint8_t active_level, uint8_t button_id)
|
||||||
|
{
|
||||||
|
memset(handle, 0, sizeof(button_hdl_t));
|
||||||
|
handle->event = (uint8_t)NONE_PRESS;
|
||||||
|
handle->hal_button_Level = pin_level;
|
||||||
|
handle->button_level = !active_level;
|
||||||
|
handle->active_level = active_level;
|
||||||
|
handle->button_id = button_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attach the button event callback function.
|
||||||
|
* @param handle: the button handle struct.
|
||||||
|
* @param event_mask: trigger event type. @ref EVENT_MASK
|
||||||
|
* @param cb: callback function.
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void button_attach(button_hdl_t *handle, uint8_t event_mask, button_callback_fn cb)
|
||||||
|
{
|
||||||
|
handle->cb = cb;
|
||||||
|
handle->event_cb = event_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Inquire the button event happen.
|
||||||
|
* @param handle: the button handle struct.
|
||||||
|
* @retval button event.
|
||||||
|
*/
|
||||||
|
press_event_t get_button_event(button_hdl_t *handle)
|
||||||
|
{
|
||||||
|
return (press_event_t)(handle->event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Button driver core function, driver state machine.
|
||||||
|
* @param handle: the button handle struct.
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
static void button_handler(button_hdl_t *handle)
|
||||||
|
{
|
||||||
|
uint8_t read_gpio_level = handle->hal_button_Level(handle->button_id);
|
||||||
|
|
||||||
|
// ticks counter working..
|
||||||
|
if ((handle->state) > 0)
|
||||||
|
handle->ticks++;
|
||||||
|
|
||||||
|
/*------------button debounce handle---------------*/
|
||||||
|
if (read_gpio_level != handle->button_level)
|
||||||
|
{ // not equal to prev one
|
||||||
|
// continue read 3 times same new level change
|
||||||
|
if (++(handle->debounce_cnt) >= DEBOUNCE_TICKS)
|
||||||
|
{
|
||||||
|
handle->button_level = read_gpio_level;
|
||||||
|
handle->debounce_cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // level not change ,counter reset.
|
||||||
|
handle->debounce_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------State machine-------------------*/
|
||||||
|
switch (handle->state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (handle->button_level == handle->active_level)
|
||||||
|
{ // start press down
|
||||||
|
handle->event = (uint8_t)PRESS_DOWN;
|
||||||
|
SYS_LOG_INF("PRESS_DOWN");
|
||||||
|
EVENT_CB(PRESS_DOWN);
|
||||||
|
handle->ticks = 0;
|
||||||
|
handle->repeat = 1;
|
||||||
|
handle->state = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handle->event = (uint8_t)NONE_PRESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
if (handle->button_level != handle->active_level)
|
||||||
|
{ // released press up
|
||||||
|
handle->event = (uint8_t)PRESS_UP;
|
||||||
|
SYS_LOG_INF("PRESS_UP");
|
||||||
|
EVENT_CB(PRESS_UP);
|
||||||
|
handle->ticks = 0;
|
||||||
|
handle->state = 2;
|
||||||
|
}
|
||||||
|
else if (handle->ticks > LONG_TICKS)
|
||||||
|
{
|
||||||
|
handle->event = (uint8_t)LONG_PRESS_START;
|
||||||
|
SYS_LOG_INF("LONG_PRESS_START");
|
||||||
|
EVENT_CB(LONG_PRESS_START);
|
||||||
|
handle->state = 5;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if (handle->button_level == handle->active_level)
|
||||||
|
{ // press down again
|
||||||
|
handle->event = (uint8_t)PRESS_DOWN;
|
||||||
|
SYS_LOG_INF("PRESS_DOWN");
|
||||||
|
EVENT_CB(PRESS_DOWN);
|
||||||
|
if (handle->repeat != PRESS_REPEAT_MAX_NUM)
|
||||||
|
{
|
||||||
|
handle->repeat++;
|
||||||
|
}
|
||||||
|
SYS_LOG_INF("PRESS_REPEAT");
|
||||||
|
EVENT_CB(PRESS_REPEAT); // repeat hit
|
||||||
|
handle->ticks = 0;
|
||||||
|
handle->state = 3;
|
||||||
|
}
|
||||||
|
else if (handle->ticks > SHORT_TICKS)
|
||||||
|
{ // released timeout
|
||||||
|
if (handle->repeat == 1)
|
||||||
|
{
|
||||||
|
handle->event = (uint8_t)SINGLE_CLICK;
|
||||||
|
SYS_LOG_INF("SINGLE_CLICK");
|
||||||
|
EVENT_CB(SINGLE_CLICK);
|
||||||
|
}
|
||||||
|
else if (handle->repeat == 2)
|
||||||
|
{
|
||||||
|
handle->event = (uint8_t)DOUBLE_CLICK;
|
||||||
|
SYS_LOG_INF("DOUBLE_CLICK");
|
||||||
|
EVENT_CB(DOUBLE_CLICK); // repeat hit
|
||||||
|
}
|
||||||
|
handle->state = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
if (handle->button_level != handle->active_level)
|
||||||
|
{ // released press up
|
||||||
|
handle->event = (uint8_t)PRESS_UP;
|
||||||
|
SYS_LOG_INF("PRESS_UP");
|
||||||
|
EVENT_CB(PRESS_UP);
|
||||||
|
if (handle->ticks < SHORT_TICKS)
|
||||||
|
{
|
||||||
|
handle->ticks = 0;
|
||||||
|
handle->state = 2; // repeat press
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handle->state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (handle->ticks > SHORT_TICKS)
|
||||||
|
{ // SHORT_TICKS < press down hold time < LONG_TICKS
|
||||||
|
handle->state = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
if (handle->button_level == handle->active_level)
|
||||||
|
{
|
||||||
|
// continue hold trigger
|
||||||
|
handle->event = (uint8_t)LONG_PRESS_HOLD;
|
||||||
|
SYS_LOG_INF("LONG_PRESS_HOLD");
|
||||||
|
EVENT_CB(LONG_PRESS_HOLD);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // released
|
||||||
|
handle->event = (uint8_t)PRESS_UP;
|
||||||
|
SYS_LOG_INF("PRESS_UP");
|
||||||
|
EVENT_CB(PRESS_UP);
|
||||||
|
handle->state = 0; // reset
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
handle->state = 0; // reset
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start the button work, add the handle into work list.
|
||||||
|
* @param handle: target handle struct.
|
||||||
|
* @retval 0: succeed. -1: already exist.
|
||||||
|
*/
|
||||||
|
int button_start(button_hdl_t *handle)
|
||||||
|
{
|
||||||
|
button_hdl_t *target = head_handle;
|
||||||
|
while (target)
|
||||||
|
{
|
||||||
|
if (target == handle)
|
||||||
|
return -1; // already exist.
|
||||||
|
target = target->next;
|
||||||
|
}
|
||||||
|
handle->next = head_handle;
|
||||||
|
head_handle = handle;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop the button work, remove the handle off work list.
|
||||||
|
* @param handle: target handle struct.
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void button_stop(button_hdl_t *handle)
|
||||||
|
{
|
||||||
|
button_hdl_t **curr;
|
||||||
|
for (curr = &head_handle; *curr;)
|
||||||
|
{
|
||||||
|
button_hdl_t *entry = *curr;
|
||||||
|
if (entry == handle)
|
||||||
|
{
|
||||||
|
*curr = entry->next;
|
||||||
|
return; // glacier add 2021-8-18
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr = &entry->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief background ticks, timer repeat invoking interval 5ms.
|
||||||
|
* @param None.
|
||||||
|
* @retval None
|
||||||
|
*/
|
||||||
|
void button_ticks(void)
|
||||||
|
{
|
||||||
|
button_hdl_t *target;
|
||||||
|
for (target = head_handle; target; target = target->next)
|
||||||
|
{
|
||||||
|
button_handler(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
73
app/button/multi_button.h
Normal file
73
app/button/multi_button.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
|
||||||
|
* All rights reserved
|
||||||
|
* https://github.com/0x1abin/MultiButton
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// According to your need to modify the constants.
|
||||||
|
#define TICKS_INTERVAL 5 // ms
|
||||||
|
#define DEBOUNCE_TICKS 3 // MAX 7 (0 ~ 7)
|
||||||
|
#define SHORT_TICKS (300 / TICKS_INTERVAL)
|
||||||
|
#define LONG_TICKS (1000 / TICKS_INTERVAL)
|
||||||
|
|
||||||
|
typedef struct Button button_hdl_t;
|
||||||
|
|
||||||
|
typedef enum // 触发事件源
|
||||||
|
{
|
||||||
|
NONE_PRESS = 0,
|
||||||
|
PRESS_DOWN, // 按键按下,每次按下都触发
|
||||||
|
PRESS_UP, // 按键弹起,每次松开都触发
|
||||||
|
PRESS_REPEAT, // 重复按下触发,变量repeat计数连击次数
|
||||||
|
SINGLE_CLICK, // 单击按键事件
|
||||||
|
DOUBLE_CLICK, // 双击按键事件
|
||||||
|
LONG_PRESS_START, // 达到长按时间阈值时触发一次
|
||||||
|
LONG_PRESS_HOLD, // 长按期间一直触发
|
||||||
|
} press_event_t;
|
||||||
|
|
||||||
|
/* EVENT_MASK */
|
||||||
|
#define EVENT_PRESS_DOWN (1U << PRESS_DOWN) // 按键按下,每次按下都触发
|
||||||
|
#define EVENT_PRESS_UP (1U << PRESS_UP) // 按键弹起,每次松开都触发
|
||||||
|
#define EVENT_PRESS_REPEAT (1U << PRESS_REPEAT) // 重复按下触发,变量repeat计数连击次数
|
||||||
|
#define EVENT_SINGLE_CLICK (1U << SINGLE_CLICK) // 单击按键事件
|
||||||
|
#define EVENT_DOUBLE_CLICK (1U << DOUBLE_CLICK) // 双击按键事件
|
||||||
|
#define EVENT_LONG_PRESS_START (1U << LONG_PRESS_START) // 达到长按时间阈值时触发一次
|
||||||
|
#define EVENT_LONG_PRESS_HOLD (1U << LONG_PRESS_HOLD) // 长按期间一直触发
|
||||||
|
|
||||||
|
typedef void (*button_callback_fn)(button_hdl_t *handle, press_event_t event);
|
||||||
|
|
||||||
|
struct Button
|
||||||
|
{
|
||||||
|
struct Button *next;
|
||||||
|
uint16_t ticks;
|
||||||
|
uint8_t repeat : 4;
|
||||||
|
uint8_t event : 4;
|
||||||
|
uint8_t state : 3;
|
||||||
|
uint8_t debounce_cnt : 3;
|
||||||
|
uint8_t active_level : 1;
|
||||||
|
uint8_t button_level : 1;
|
||||||
|
uint8_t button_id;
|
||||||
|
uint8_t event_cb;
|
||||||
|
uint8_t (*hal_button_Level)(uint8_t button_id);
|
||||||
|
button_callback_fn cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void button_init(button_hdl_t *handle, uint8_t (*pin_level)(uint8_t button_id), uint8_t active_level, uint8_t button_id);
|
||||||
|
void button_attach(button_hdl_t *handle, uint8_t event_mask, button_callback_fn cb);
|
||||||
|
press_event_t get_button_event(button_hdl_t *handle);
|
||||||
|
int button_start(button_hdl_t *handle);
|
||||||
|
void button_stop(button_hdl_t *handle);
|
||||||
|
void button_ticks(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -19,7 +19,7 @@ static cfg_board_t const s_cfg_board_default = {
|
|||||||
|
|
||||||
/* 启动按键 */
|
/* 启动按键 */
|
||||||
.key_boot = {
|
.key_boot = {
|
||||||
.pin = 9, // 用于切换灯效
|
.pin = 0, // 用于切换灯效
|
||||||
.en_lev = 0, // 用于切换灯效
|
.en_lev = 0, // 用于切换灯效
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,18 +20,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "drivers/chip/_hal.h"
|
#include "drivers/chip/_hal.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
typedef struct // 按键配置
|
#define GPIO_USED(pin) ((pin) < 255)
|
||||||
|
|
||||||
|
typedef struct // 对应 GPIO 单个引脚的输入/输出配置的基础定义
|
||||||
{
|
{
|
||||||
uint8_t pin; // 引脚号
|
uint8_t pin; // 引脚号 (0~254, 255 表示不使用) --OK
|
||||||
uint8_t en_lev; // 触发电平
|
uint8_t en_lev; // 触发电平
|
||||||
} cfg_board_key_t;
|
} cfg_board_pin_io_t;
|
||||||
|
|
||||||
typedef struct // 数据结构一旦定下不可随意变更
|
typedef struct // 数据结构一旦定下不可随意变更
|
||||||
{
|
{
|
||||||
/* 硬件描述类 */
|
/* 硬件描述类 */
|
||||||
hal_uart_hdl_t uart_console; // 控制台
|
hal_uart_hdl_t uart_console; // 控制台
|
||||||
cfg_board_key_t key_boot; // 启动按键
|
cfg_board_pin_io_t key_boot; // 启动按键
|
||||||
|
|
||||||
/* 产品功能描述类 */
|
/* 产品功能描述类 */
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# INCS
|
# INCS
|
||||||
list(APPEND incs "../sal")
|
list(APPEND incs "../sal")
|
||||||
|
list(APPEND incs "../components/system/include")
|
||||||
|
|
||||||
|
|
||||||
# SRCS
|
# SRCS
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ list(APPEND srcs "esp32/kernel/os_semaphore.c")
|
|||||||
list(APPEND srcs "esp32/kernel/os_thread.c")
|
list(APPEND srcs "esp32/kernel/os_thread.c")
|
||||||
list(APPEND srcs "esp32/kernel/os_kit.c")
|
list(APPEND srcs "esp32/kernel/os_kit.c")
|
||||||
list(APPEND srcs "esp32/kernel/os_service.c")
|
list(APPEND srcs "esp32/kernel/os_service.c")
|
||||||
|
list(APPEND srcs "esp32/chip/gpio_esp32.c")
|
||||||
list(APPEND srcs "esp32/chip/uart_esp32.c")
|
list(APPEND srcs "esp32/chip/uart_esp32.c")
|
||||||
list(APPEND srcs "esp32/soc_shell.c")
|
list(APPEND srcs "esp32/soc_shell.c")
|
||||||
list(APPEND srcs "esp32/os_entry.c")
|
list(APPEND srcs "esp32/os_entry.c")
|
||||||
|
|||||||
63
sal/esp32/chip/gpio_esp32.c
Normal file
63
sal/esp32/chip/gpio_esp32.c
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#include "drivers/chip/gpio.h"
|
||||||
|
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
|
#define SYS_LOG_DOMAIN "gpio"
|
||||||
|
#include "sys_log.h"
|
||||||
|
|
||||||
|
void drv_gpio_enable_all(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void drv_gpio_disable_all(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int drv_gpio_pin_configure(uint8_t pin, gpio_dir_t dir, gpio_pud_t pull)
|
||||||
|
{
|
||||||
|
gpio_config_t io_conf;
|
||||||
|
static __typeof__(io_conf.mode) const mode_tab[] = {
|
||||||
|
[_GPIO_DIR_IN] = GPIO_MODE_INPUT,
|
||||||
|
[_GPIO_DIR_ANALOG] = GPIO_MODE_INPUT,
|
||||||
|
[_GPIO_DIR_OUT] = GPIO_MODE_OUTPUT,
|
||||||
|
[_GPIO_DIR_OPEN_DRAIN] = GPIO_MODE_OUTPUT_OD,
|
||||||
|
};
|
||||||
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||||
|
io_conf.mode = mode_tab[dir];
|
||||||
|
io_conf.pin_bit_mask = (1ULL << pin);
|
||||||
|
io_conf.pull_up_en = pull == _GPIO_PUD_PULL_UP;
|
||||||
|
io_conf.pull_down_en = pull == _GPIO_PUD_PULL_DOWN;
|
||||||
|
gpio_config(&io_conf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int drv_gpio_pin_read(uint8_t pin)
|
||||||
|
{
|
||||||
|
return gpio_get_level(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drv_gpio_pin_write(uint8_t pin, int value)
|
||||||
|
{
|
||||||
|
gpio_set_level(pin, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drv_gpio_exti_callback_enable(gpio_exti_cb_fn cb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void drv_gpio_exti_callback_disable(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void drv_gpio_exti_irq_enable(uint8_t pin, gpio_exti_edge_t polarity, int priority)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void drv_gpio_exti_irq_disable(uint8_t pin)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int drv_gpio_exti_get_pin(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user