暂存flexibleButton不太行?

This commit is contained in:
stark1898y 2024-12-14 16:00:58 +08:00
parent 3791a5d416
commit f8cec39611
14 changed files with 731 additions and 56 deletions

View File

@ -15,7 +15,8 @@
"cstddef": "cpp", "cstddef": "cpp",
"type_traits": "cpp", "type_traits": "cpp",
"shell.h": "c", "shell.h": "c",
"ch59x_common.h": "c" "ch59x_common.h": "c",
"flexible_button.h": "c"
}, },
"marscode.chatLanguage": "cn" "marscode.chatLanguage": "cn"
} }

View File

@ -25,7 +25,7 @@
#include "log.h" #include "log.h"
#undef LOG_ENABLE #undef LOG_ENABLE
#define LOG_ENABLE 1 #define LOG_ENABLE 0
#undef LOG_TAG #undef LOG_TAG
#define LOG_TAG "peripheral" #define LOG_TAG "peripheral"

View File

@ -36,9 +36,29 @@
// static uint8_t main_task_id = INVALID_TASK_ID; // static uint8_t main_task_id = INVALID_TASK_ID;
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4]; __attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];
// void app_task_handler(TeAppEvtType app_evt_type)
// {
// switch(app_evt_type)
// {
// case kKeyShort:{
// PRINT("button short press\r\n");
// break;
// }
// case kKeyLong:
// PRINT("button long press\r\n");
// break;
// case kKeyRelease:
// PRINT("gpio relase\r\n");
// break;
// default:
// break;
// }
// }
/********************************************************************* /*********************************************************************
* @fn Main_Circulation * @fn Main_Circulation
* *
@ -53,8 +73,9 @@ void Main_Circulation()
while (1) while (1)
{ {
TMOS_SystemProcess(); TMOS_SystemProcess();
// BSP_UART1_TxLoop(); KEY_ProcessLoop();
#if 0 // BSP_UART1_TxLoop();
#if 0
if (GPIOB_ReadPortPin(GPIO_Pin_7) == 0) if (GPIOB_ReadPortPin(GPIO_Pin_7) == 0)
{ {
// 12V_EN // 12V_EN
@ -118,7 +139,7 @@ void Main_Circulation()
EMV_CHARGE_OFF_DEINIT; EMV_CHARGE_OFF_DEINIT;
EMV_OFF_DEINIT; EMV_OFF_DEINIT;
} }
#endif #endif
} }
} }
@ -167,7 +188,7 @@ int main(void)
logError("中文测试 %2.2f", 123.456); logError("中文测试 %2.2f", 123.456);
#endif #endif
DelayMs(1000 * 3); // DelayMs(1000 * 3);
BOOST_OFF_DEINIT; BOOST_OFF_DEINIT;
BEEP_OFF_DEINIT; BEEP_OFF_DEINIT;
@ -175,9 +196,7 @@ int main(void)
EMV_CHARGE_OFF_DEINIT; EMV_CHARGE_OFF_DEINIT;
EMV_OFF_DEINIT; EMV_OFF_DEINIT;
// BSP_KEY_Init(); // BSP_ADC_Init();
BSP_ADC_Init();
CH59x_BLEInit(); CH59x_BLEInit();
logDebug("%s\n", VER_LIB); logDebug("%s\n", VER_LIB);
uint8_t MacAddr[6]; uint8_t MacAddr[6];
@ -190,7 +209,7 @@ int main(void)
LL_AdvertiseEventRegister(BLE_AdvertiseEventCB); LL_AdvertiseEventRegister(BLE_AdvertiseEventCB);
// DelayMs(100); // DelayMs(100);
GXHTC3C_Init(); // GXHTC3C_Init();
// while (1) // while (1)
// { // {
// DelayMs(100); // DelayMs(100);

View File

@ -6,11 +6,10 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#define KEY_SCAN_EVT (0x0001 << 0) #define KEY_SCAN_EVT (0x0001 << 0)
#define DEMO_TASK_TMOS_EVT_TEST_2 (0x0001 << 1) #define KEY_WAKEUP_EVT (0x0001 << 1)
#define DEMO_TASK_TMOS_EVT_TEST_3 (0x0001 << 2) #define KEY_RELEASE_EVT (0x0001 << 2)
#define DEMO_TASK_TMOS_EVT_TEST_4 (0x0001 << 3) #define KEY_IDLE_TIMEOUT_EVT (0x0001 << 2)
#define DEMO_TASK_TMOS_EVT_TEST_5 (0x0001 << 4)
// KEY_B_PIN at PB7,low->active // KEY_B_PIN at PB7,low->active
#define KEY_B_PIN GPIO_Pin_7 #define KEY_B_PIN GPIO_Pin_7
@ -22,7 +21,7 @@ typedef enum
kKeyShort = 0, kKeyShort = 0,
kKeyLong, kKeyLong,
kKeyRelease, kKeyRelease,
} TeKeyEvtType; } TeAppEvtType;
void BSP_KEY_EnterLowpower(void); void BSP_KEY_EnterLowpower(void);
@ -30,4 +29,7 @@ void BSP_KEY_ExitLowpower(void);
void BSP_KEY_Init(void); void BSP_KEY_Init(void);
void KEY_ProcessLoop(void);
#endif // !__BSP_KEY_H__ #endif // !__BSP_KEY_H__

View File

@ -5,6 +5,8 @@
#include "bsp_uart.h" #include "bsp_uart.h"
#include "log.h" #include "log.h"
#include "SLEEP.h"
// https://www.cnblogs.com/iot-fan/p/14304943.html // https://www.cnblogs.com/iot-fan/p/14304943.html
#undef LOG_ENABLE #undef LOG_ENABLE
@ -14,7 +16,6 @@
#define LOG_TAG "key" #define LOG_TAG "key"
typedef enum typedef enum
{ {
USER_BUTTON_0 = 0, USER_BUTTON_0 = 0,
@ -48,7 +49,8 @@ static flex_button_t user_button[USER_BUTTON_MAX];
tmosTaskID key_task_id = INVALID_TASK_ID; tmosTaskID key_task_id = INVALID_TASK_ID;
volatile uint8_t key_process_flag = 0; volatile uint8_t key_wakeup_flag = 0;
volatile uint8_t key_timeout_flag = 0;
static void KEY_Task_ProcessTmosMsg(tmos_event_hdr_t *pMsg) static void KEY_Task_ProcessTmosMsg(tmos_event_hdr_t *pMsg)
{ {
@ -136,7 +138,7 @@ static uint16_t KEY_Task_ProcessEvent(uint8_t task_id, uint16_t events)
// 由按键中断唤醒后开启按键扫描 // 由按键中断唤醒后开启按键扫描
void BSP_KEY_EnterLowpower(void) void BSP_KEY_EnterLowpower(void)
{ {
key_process_flag = 0; key_wakeup_flag = 0;
tmos_stop_task(key_task_id, KEY_SCAN_EVT); tmos_stop_task(key_task_id, KEY_SCAN_EVT);
// R16_PB_INT_MODE |= KEY_B_PIN; // edge mode // R16_PB_INT_MODE |= KEY_B_PIN; // edge mode
@ -154,23 +156,40 @@ void BSP_KEY_EnterLowpower(void)
// 开启GPIOB中断 // 开启GPIOB中断
PFIC_EnableIRQ(GPIO_B_IRQn); PFIC_EnableIRQ(GPIO_B_IRQn);
BSP_RequestSleep();
} }
void BSP_KEY_ExitLowpower(void) void BSP_KEY_ExitLowpower(void)
{ {
BSP_BlockSleep();
// 关闭GPIOB中断 // 关闭GPIOB中断
PFIC_DisableIRQ(GPIO_B_IRQn); PFIC_DisableIRQ(GPIO_B_IRQn);
PWR_PeriphWakeUpCfg(DISABLE, RB_GPIO_WAKE_MODE | RB_SLP_GPIO_WAKE, Long_Delay); PWR_PeriphWakeUpCfg(DISABLE, RB_GPIO_WAKE_MODE | RB_SLP_GPIO_WAKE, Long_Delay);
tmos_set_event(key_task_id, KEY_SCAN_EVT); // tmos_set_event(key_task_id, KEY_SCAN_EVT);
key_process_flag = 1; // tmos_start_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(30));
// tmos_start_reload_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(30));
} }
__HIGH_CODE
__attribute__((noinline))
void KEY_ProcessLoop(void) void KEY_ProcessLoop(void)
{ {
if (key_process_flag) // if (R16_PB_INT_IF & KEY_B_PIN)
// {
// R16_PB_INT_IF = KEY_B_PIN;
// tmos_set_event(key_task_id, KEY_SCAN_EVT);
// logDebug("KEY_ProcessLoop");
// }
if (key_wakeup_flag)
{ {
/* code */ key_wakeup_flag = 0;
tmos_set_event(key_task_id, KEY_SCAN_EVT);
// tmos_start_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(20));
// tmos_start_task(key_task_id, KEY_IDLE_TIMEOUT_EVT, MS1_TO_SYSTEM_TIME(1000 * 10));
logDebug("key_wakeup_flag");
} }
} }
@ -182,11 +201,11 @@ static uint8_t common_btn_read(void *arg)
switch (btn->id) switch (btn->id)
{ {
case USER_BUTTON_0: case USER_BUTTON_0:
value = GPIOB_ReadPortPin(KEY_B_PIN); value = (uint8_t)GPIOB_ReadPortPin(KEY_B_PIN);
break; break;
default: default:
logAssert(0,while(1)); logAssert(0, while (1));
} }
return value; return value;
@ -197,9 +216,24 @@ static void common_btn_evt_cb(void *arg)
flex_button_t *btn = (flex_button_t *)arg; flex_button_t *btn = (flex_button_t *)arg;
logDebug("id: [%d - %s] event: [%d - %30s] repeat: %d", logDebug("id: [%d - %s] event: [%d - %30s] repeat: %d",
btn->id, enum_btn_id_string[btn->id], btn->id, enum_btn_id_string[btn->id],
btn->event, enum_event_string[btn->event], btn->event, enum_event_string[btn->event],
btn->click_cnt); btn->click_cnt);
if (flex_button_event_read(&user_button[USER_BUTTON_0]) == FLEX_BTN_PRESS_CLICK)
{
logDebug("USER_BUTTON_0 PRESS_CLICK");
BSP_KEY_EnterLowpower();
}
else if (flex_button_event_read(&user_button[USER_BUTTON_0]) == FLEX_BTN_PRESS_DOUBLE_CLICK)
{
logDebug("USER_BUTTON_0 PRESS_LONG_HOLD")
BSP_KEY_EnterLowpower();
}
else if (flex_button_event_read(&user_button[USER_BUTTON_0]) == FLEX_BTN_PRESS_LONG_START)
{
logDebug("USER_BUTTON_0 FLEX_BTN_PRESS_LONG_START");
BSP_KEY_EnterLowpower();
}
} }
static uint16_t KEY_Task_ProcessEvent(uint8_t task_id, uint16_t events) static uint16_t KEY_Task_ProcessEvent(uint8_t task_id, uint16_t events)
@ -216,13 +250,45 @@ static uint16_t KEY_Task_ProcessEvent(uint8_t task_id, uint16_t events)
// return unprocessed events // return unprocessed events
return (events ^ SYS_EVENT_MSG); return (events ^ SYS_EVENT_MSG);
} }
// if (events & KEY_WAKEUP_EVT)
// {
// logDebug("KEY_WAKEUP_EVT");
// BSP_KEY_ExitLowpower();
// return (events ^ KEY_WAKEUP_EVT);
// }
if (events & KEY_SCAN_EVT) if (events & KEY_SCAN_EVT)
{ {
if (0 == key_timeout_flag)
{
if (IS_KEY_Vaild())
{
tmos_stop_task(key_task_id, KEY_IDLE_TIMEOUT_EVT);
tmos_start_task(key_task_id, KEY_IDLE_TIMEOUT_EVT, MS1_TO_SYSTEM_TIME(1000 * 5));
}
else
{
logDebug("0");
}
tmos_start_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(20));
}
else
{
logDebug("KEY_SCAN_EVT timeout");
BSP_KEY_EnterLowpower();
}
// logDebug("KEY_SCAN_EVT");
flex_button_scan(); flex_button_scan();
tmos_start_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(30));
return (events ^ KEY_SCAN_EVT); return (events ^ KEY_SCAN_EVT);
} }
if (events & KEY_IDLE_TIMEOUT_EVT)
{
logDebug("KEY_IDLE_TIMEOUT_EVT");
key_timeout_flag = 1;
return (events ^ KEY_IDLE_TIMEOUT_EVT);
}
// Discard unknown events // Discard unknown events
return 0; return 0;
@ -235,36 +301,64 @@ void BSP_KEY_Init(void)
// 由外部上拉电阻了 // 由外部上拉电阻了
// 设置为浮空输入模式 // 设置为浮空输入模式
GPIOB_SetBits(KEY_B_PIN);
GPIOB_ModeCfg(KEY_B_PIN, GPIO_ModeIN_PU); GPIOB_ModeCfg(KEY_B_PIN, GPIO_ModeIN_PU);
for (uint8_t i = 0; i < USER_BUTTON_MAX; i ++) for (uint8_t i = 0; i < USER_BUTTON_MAX; i++)
{ {
user_button[i].id = i; user_button[i].id = i;
user_button[i].usr_button_read = common_btn_read; user_button[i].usr_button_read = common_btn_read;
user_button[i].cb = common_btn_evt_cb; user_button[i].cb = common_btn_evt_cb;
user_button[i].pressed_logic_level = 0; user_button[i].pressed_logic_level = 0;
user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500); 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_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000);
user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500); // user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500);
flex_button_register(&user_button[i]); flex_button_register(&user_button[i]);
} }
// 下降沿触发
GPIOB_ITModeCfg(KEY_B_PIN, GPIO_ITMode_FallEdge);
// 开启GPIO的睡眠唤醒,如果需要的话
// PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay);
PWR_PeriphWakeUpCfg(ENABLE, RB_GPIO_WAKE_MODE | RB_SLP_GPIO_WAKE, Long_Delay);
// 开启GPIOB中断
PFIC_EnableIRQ(GPIO_B_IRQn);
key_task_id = TMOS_ProcessEventRegister(KEY_Task_ProcessEvent); key_task_id = TMOS_ProcessEventRegister(KEY_Task_ProcessEvent);
tmos_start_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(30)); // tmos_start_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(20));
//开始一个定时事件,不断的执行,除非运行tmos_stop_task关掉,
//tmosTimer具体是 1600 = 1s
// tmos_start_reload_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(20));
// BSP_KEY_EnterLowpower();
} }
__INTERRUPT // 告诉编译器使用硬件压栈 __INTERRUPT // 告诉编译器使用硬件压栈
__HIGH_CODE // 放到RAM里 __HIGH_CODE // 放到RAM里
void GPIOB_IRQHandler(void) void GPIOB_IRQHandler(void)
{ {
if (R16_PB_INT_IF & KEY_B_PIN) // 阻止睡眠
{ BSP_BlockSleep();
R16_PB_INT_IF = KEY_B_PIN; // 关按键中断
tmos_set_event(key_task_id, KEY_SCAN_EVT); BSP_KEY_ExitLowpower();
BSP_KEY_ExitLowpower();
logDebug("KEY IRQ"); logDebug("KEY IRQ");
}
// GPIOB_ClearITFlagBit(KEY_B_PIN); GPIOB_ClearITFlagBit(KEY_B_PIN);
key_wakeup_flag = 1;
key_timeout_flag = 0;
// BSP_BlockSleep();
// if (R16_PB_INT_IF & KEY_B_PIN)
// {
// R16_PB_INT_IF = KEY_B_PIN;
// // tmos_set_event(key_task_id, KEY_SCAN_EVT);
// BSP_KEY_ExitLowpower();
// }
// tmos_set_event(key_task_id,KEY_SCAN_EVT); // tmos_set_event(key_task_id,KEY_SCAN_EVT);
} }

View File

@ -16,8 +16,28 @@
#include "bsp_key.h" #include "bsp_key.h"
#include "log.h"
#include "bsp_uart.h"
#undef LOG_ENABLE
#define LOG_ENABLE 1
#undef LOG_TAG
#define LOG_TAG "sleep"
static volatile bool block_sleep_flag = false;
void BSP_RequestSleep(void)
{
block_sleep_flag = false;
}
void BSP_BlockSleep(void)
{
block_sleep_flag = true;
}
/******************************************************************************* /*******************************************************************************
* @fn CH59x_LowPower * @fn CH59x_LowPower
* *
@ -29,6 +49,11 @@
*/ */
uint32_t CH59x_LowPower(uint32_t time) uint32_t CH59x_LowPower(uint32_t time)
{ {
if( true == block_sleep_flag)
{
// logDebug("block_sleep");
return 0;
}
#if (defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE) #if (defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
volatile uint32_t i; volatile uint32_t i;
uint32_t time_sleep, time_curr; uint32_t time_sleep, time_curr;
@ -87,7 +112,7 @@ uint32_t CH59x_LowPower(uint32_t time)
i = RTC_GetCycle32k(); i = RTC_GetCycle32k();
while (i == RTC_GetCycle32k()); while (i == RTC_GetCycle32k());
// BSP_KEY_ExitLowpower();
return 0; return 0;
} }

View File

@ -6,7 +6,7 @@
* Description : * Description :
********************************************************************************* *********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for * Attention: This software (modified or not) and binary are used for
* microcontroller manufactured by Nanjing Qinheng Microelectronics. * microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/ *******************************************************************************/
@ -22,6 +22,9 @@ extern "C" {
* GLOBAL VARIABLES * GLOBAL VARIABLES
*/ */
void BSP_RequestSleep(void);
void BSP_BlockSleep(void);
/********************************************************************* /*********************************************************************
* FUNCTIONS * FUNCTIONS
*/ */

View File

@ -2,8 +2,8 @@
* @Author : stark1898y 1658608470@qq.com * @Author : stark1898y 1658608470@qq.com
* @Date : 2024-07-04 16:13:57 * @Date : 2024-07-04 16:13:57
* @LastEditors : stark1898y 1658608470@qq.com * @LastEditors : stark1898y 1658608470@qq.com
* @LastEditTime : 2024-09-25 14:33:23 * @LastEditTime : 2024-12-14 15:56:11
* @FilePath : \JT-DT-YD4N02A_RTT_MRS\packages\FlexibleButton-2.0.1\flexible_button.h * @FilePath : \BLE_TYQ_CH592F\common\FlexibleButton-2.0.1\flexible_button.h
* @Description : * @Description :
* *
* Copyright (c) 2024 by yzy, All Rights Reserved. * Copyright (c) 2024 by yzy, All Rights Reserved.
@ -43,8 +43,8 @@
#include "stdint.h" #include "stdint.h"
#define FLEX_BTN_SCAN_FREQ_HZ 40 // How often flex_button_scan () is called #define FLEX_BTN_SCAN_FREQ_HZ 50 // How often flex_button_scan () is called
#define FLEX_MS_TO_SCAN_CNT(ms) (ms / (1000 / FLEX_BTN_SCAN_FREQ_HZ)) // #define FLEX_MS_TO_SCAN_CNT(ms) (ms / (1000 / FLEX_BTN_SCAN_FREQ_HZ)) //
/* Multiple clicks interval, default 300ms */ /* Multiple clicks interval, default 300ms */
#define MAX_MULTIPLE_CLICKS_INTERVAL (FLEX_MS_TO_SCAN_CNT(300)) #define MAX_MULTIPLE_CLICKS_INTERVAL (FLEX_MS_TO_SCAN_CNT(300))

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Zibin Zheng
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,131 @@
# MultiButton
## 简介
MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。
## 使用方法
1.先申请一个按键结构
```c
struct Button 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_);
BtnCallback 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)
{}
}
```

View File

@ -0,0 +1,65 @@
#include "multi_button.h"
enum Button_IDs {
btn1_id,
btn2_id,
};
struct Button btn1;
struct Button btn2;
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);
case btn2_id:
return HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin);
default:
return 0;
}
}
int main()
{
button_init(&btn1, read_button_GPIO, 0, btn1_id);
button_init(&btn2, read_button_GPIO, 0, btn2_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_attach(&btn2, PRESS_DOWN, BTN2_PRESS_DOWN_Handler);
button_attach(&btn2, PRESS_UP, BTN2_PRESS_UP_Handler);
button_attach(&btn2, PRESS_REPEAT, BTN2_PRESS_REPEAT_Handler);
button_attach(&btn2, SINGLE_CLICK, BTN2_SINGLE_Click_Handler);
button_attach(&btn2, DOUBLE_CLICK, BTN2_DOUBLE_Click_Handler);
button_attach(&btn2, LONG_PRESS_START, BTN2_LONG_PRESS_START_Handler);
button_attach(&btn2, LONG_PRESS_HOLD, BTN2_LONG_PRESS_HOLD_Handler);
button_start(&btn1);
button_start(&btn2);
//make the timer invoking the button_ticks() interval 5ms.
//This function is implemented by yourself.
__timer_start(button_ticks, 0, 5);
while(1)
{}
}
void BTN1_PRESS_DOWN_Handler(void* btn)
{
//do something...
}
void BTN1_PRESS_UP_Handler(void* btn)
{
//do something...
}

View File

@ -0,0 +1,44 @@
#include "multi_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);
default:
return 0;
}
}
int main()
{
static PressEvent btn1_event_val;
button_init(&btn1, read_button_GPIO, 0, btn1_id);
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)
{
if(btn1_event_val != get_button_event(&btn1)) {
btn1_event_val = get_button_event(&btn1);
if(btn1_event_val == PRESS_DOWN) {
//do something
} else if(btn1_event_val == PRESS_UP) {
//do something
} else if(btn1_event_val == LONG_PRESS_HOLD) {
//do something
}
}
}
}

View File

@ -0,0 +1,208 @@
/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* All rights reserved
*/
#include "multi_button.h"
#define EVENT_CB(ev) if(handle->cb[ev])handle->cb[ev]((void*)handle)
#define PRESS_REPEAT_MAX_NUM 15 /*!< The maximum value of the repeat counter */
//button handle list head.
static struct Button* head_handle = NULL;
static void button_handler(struct Button* 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(struct Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id)
{
memset(handle, 0, sizeof(struct Button));
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: trigger event type.
* @param cb: callback function.
* @retval None
*/
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb)
{
handle->cb[event] = cb;
}
/**
* @brief Inquire the button event happen.
* @param handle: the button handle struct.
* @retval button event.
*/
PressEvent get_button_event(struct Button* handle)
{
return (PressEvent)(handle->event);
}
/**
* @brief Button driver core function, driver state machine.
* @param handle: the button handle struct.
* @retval None
*/
static void button_handler(struct Button* 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;
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;
EVENT_CB(PRESS_UP);
handle->ticks = 0;
handle->state = 2;
} else if(handle->ticks > LONG_TICKS) {
handle->event = (uint8_t)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;
EVENT_CB(PRESS_DOWN);
if(handle->repeat != PRESS_REPEAT_MAX_NUM) {
handle->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;
EVENT_CB(SINGLE_CLICK);
} else if(handle->repeat == 2) {
handle->event = (uint8_t)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;
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;
EVENT_CB(LONG_PRESS_HOLD);
} else { //released
handle->event = (uint8_t)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(struct Button* handle)
{
struct Button* 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(struct Button* handle)
{
struct Button** curr;
for(curr = &head_handle; *curr; ) {
struct Button* entry = *curr;
if(entry == handle) {
*curr = entry->next;
// free(entry);
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)
{
struct Button* target;
for(target=head_handle; target; target=target->next) {
button_handler(target);
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2016 Zibin Zheng <znbin@qq.com>
* All rights reserved
*/
#ifndef _MULTI_BUTTON_H_
#define _MULTI_BUTTON_H_
#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 void (*BtnCallback)(void*);
typedef enum {
PRESS_DOWN = 0,
PRESS_UP,
PRESS_REPEAT,
SINGLE_CLICK,
DOUBLE_CLICK,
LONG_PRESS_START,
LONG_PRESS_HOLD,
number_of_event,
NONE_PRESS
}PressEvent;
typedef 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_);
BtnCallback cb[number_of_event];
struct Button* next;
}Button;
#ifdef __cplusplus
extern "C" {
#endif
void button_init(struct Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id);
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb);
PressEvent get_button_event(struct Button* handle);
int button_start(struct Button* handle);
void button_stop(struct Button* handle);
void button_ticks(void);
#ifdef __cplusplus
}
#endif
#endif