暂存flexibleButton不太行?
This commit is contained in:
parent
3791a5d416
commit
f8cec39611
|
@ -15,7 +15,8 @@
|
|||
"cstddef": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"shell.h": "c",
|
||||
"ch59x_common.h": "c"
|
||||
"ch59x_common.h": "c",
|
||||
"flexible_button.h": "c"
|
||||
},
|
||||
"marscode.chatLanguage": "cn"
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "log.h"
|
||||
|
||||
#undef LOG_ENABLE
|
||||
#define LOG_ENABLE 1
|
||||
#define LOG_ENABLE 0
|
||||
|
||||
#undef LOG_TAG
|
||||
#define LOG_TAG "peripheral"
|
||||
|
|
|
@ -36,9 +36,29 @@
|
|||
|
||||
// static uint8_t main_task_id = INVALID_TASK_ID;
|
||||
|
||||
|
||||
__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
|
||||
*
|
||||
|
@ -53,8 +73,9 @@ void Main_Circulation()
|
|||
while (1)
|
||||
{
|
||||
TMOS_SystemProcess();
|
||||
// BSP_UART1_TxLoop();
|
||||
#if 0
|
||||
KEY_ProcessLoop();
|
||||
// BSP_UART1_TxLoop();
|
||||
#if 0
|
||||
if (GPIOB_ReadPortPin(GPIO_Pin_7) == 0)
|
||||
{
|
||||
// 12V_EN
|
||||
|
@ -118,7 +139,7 @@ void Main_Circulation()
|
|||
EMV_CHARGE_OFF_DEINIT;
|
||||
EMV_OFF_DEINIT;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +188,7 @@ int main(void)
|
|||
logError("中文测试 %2.2f", 123.456);
|
||||
#endif
|
||||
|
||||
DelayMs(1000 * 3);
|
||||
// DelayMs(1000 * 3);
|
||||
|
||||
BOOST_OFF_DEINIT;
|
||||
BEEP_OFF_DEINIT;
|
||||
|
@ -175,9 +196,7 @@ int main(void)
|
|||
EMV_CHARGE_OFF_DEINIT;
|
||||
EMV_OFF_DEINIT;
|
||||
|
||||
// BSP_KEY_Init();
|
||||
|
||||
BSP_ADC_Init();
|
||||
// BSP_ADC_Init();
|
||||
CH59x_BLEInit();
|
||||
logDebug("%s\n", VER_LIB);
|
||||
uint8_t MacAddr[6];
|
||||
|
@ -190,7 +209,7 @@ int main(void)
|
|||
LL_AdvertiseEventRegister(BLE_AdvertiseEventCB);
|
||||
|
||||
// DelayMs(100);
|
||||
GXHTC3C_Init();
|
||||
// GXHTC3C_Init();
|
||||
// while (1)
|
||||
// {
|
||||
// DelayMs(100);
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define KEY_SCAN_EVT (0x0001 << 0)
|
||||
#define DEMO_TASK_TMOS_EVT_TEST_2 (0x0001 << 1)
|
||||
#define DEMO_TASK_TMOS_EVT_TEST_3 (0x0001 << 2)
|
||||
#define DEMO_TASK_TMOS_EVT_TEST_4 (0x0001 << 3)
|
||||
#define DEMO_TASK_TMOS_EVT_TEST_5 (0x0001 << 4)
|
||||
#define KEY_SCAN_EVT (0x0001 << 0)
|
||||
#define KEY_WAKEUP_EVT (0x0001 << 1)
|
||||
#define KEY_RELEASE_EVT (0x0001 << 2)
|
||||
#define KEY_IDLE_TIMEOUT_EVT (0x0001 << 2)
|
||||
|
||||
// KEY_B_PIN at PB7,low->active
|
||||
#define KEY_B_PIN GPIO_Pin_7
|
||||
|
@ -22,7 +21,7 @@ typedef enum
|
|||
kKeyShort = 0,
|
||||
kKeyLong,
|
||||
kKeyRelease,
|
||||
} TeKeyEvtType;
|
||||
} TeAppEvtType;
|
||||
|
||||
|
||||
void BSP_KEY_EnterLowpower(void);
|
||||
|
@ -30,4 +29,7 @@ void BSP_KEY_ExitLowpower(void);
|
|||
|
||||
void BSP_KEY_Init(void);
|
||||
|
||||
void KEY_ProcessLoop(void);
|
||||
|
||||
|
||||
#endif // !__BSP_KEY_H__
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "bsp_uart.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "SLEEP.h"
|
||||
|
||||
// https://www.cnblogs.com/iot-fan/p/14304943.html
|
||||
|
||||
#undef LOG_ENABLE
|
||||
|
@ -14,7 +16,6 @@
|
|||
#define LOG_TAG "key"
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USER_BUTTON_0 = 0,
|
||||
|
@ -48,7 +49,8 @@ static flex_button_t user_button[USER_BUTTON_MAX];
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -136,7 +138,7 @@ static uint16_t KEY_Task_ProcessEvent(uint8_t task_id, uint16_t events)
|
|||
// 由按键中断唤醒后开启按键扫描
|
||||
void BSP_KEY_EnterLowpower(void)
|
||||
{
|
||||
key_process_flag = 0;
|
||||
key_wakeup_flag = 0;
|
||||
tmos_stop_task(key_task_id, KEY_SCAN_EVT);
|
||||
|
||||
// R16_PB_INT_MODE |= KEY_B_PIN; // edge mode
|
||||
|
@ -154,23 +156,40 @@ void BSP_KEY_EnterLowpower(void)
|
|||
|
||||
// 开启GPIOB中断
|
||||
PFIC_EnableIRQ(GPIO_B_IRQn);
|
||||
|
||||
BSP_RequestSleep();
|
||||
}
|
||||
|
||||
void BSP_KEY_ExitLowpower(void)
|
||||
{
|
||||
BSP_BlockSleep();
|
||||
|
||||
// 关闭GPIOB中断
|
||||
PFIC_DisableIRQ(GPIO_B_IRQn);
|
||||
PWR_PeriphWakeUpCfg(DISABLE, RB_GPIO_WAKE_MODE | RB_SLP_GPIO_WAKE, Long_Delay);
|
||||
|
||||
tmos_set_event(key_task_id, KEY_SCAN_EVT);
|
||||
key_process_flag = 1;
|
||||
// tmos_set_event(key_task_id, KEY_SCAN_EVT);
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
case USER_BUTTON_0:
|
||||
value = GPIOB_ReadPortPin(KEY_B_PIN);
|
||||
break;
|
||||
default:
|
||||
logAssert(0,while(1));
|
||||
case USER_BUTTON_0:
|
||||
value = (uint8_t)GPIOB_ReadPortPin(KEY_B_PIN);
|
||||
break;
|
||||
default:
|
||||
logAssert(0, while (1));
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -197,9 +216,24 @@ static void common_btn_evt_cb(void *arg)
|
|||
flex_button_t *btn = (flex_button_t *)arg;
|
||||
|
||||
logDebug("id: [%d - %s] event: [%d - %30s] repeat: %d",
|
||||
btn->id, enum_btn_id_string[btn->id],
|
||||
btn->event, enum_event_string[btn->event],
|
||||
btn->click_cnt);
|
||||
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_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)
|
||||
|
@ -216,13 +250,45 @@ static uint16_t KEY_Task_ProcessEvent(uint8_t task_id, uint16_t events)
|
|||
// return unprocessed events
|
||||
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 (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();
|
||||
tmos_start_task(key_task_id, KEY_SCAN_EVT, MS1_TO_SYSTEM_TIME(30));
|
||||
|
||||
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
|
||||
return 0;
|
||||
|
@ -235,36 +301,64 @@ void BSP_KEY_Init(void)
|
|||
|
||||
// 由外部上拉电阻了
|
||||
// 设置为浮空输入模式
|
||||
GPIOB_SetBits(KEY_B_PIN);
|
||||
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].usr_button_read = common_btn_read;
|
||||
user_button[i].cb = common_btn_evt_cb;
|
||||
user_button[i].pressed_logic_level = 0;
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
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 // 告诉编译器使用硬件压栈
|
||||
__HIGH_CODE // 放到RAM里
|
||||
__HIGH_CODE // 放到RAM里
|
||||
void GPIOB_IRQHandler(void)
|
||||
{
|
||||
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();
|
||||
logDebug("KEY IRQ");
|
||||
}
|
||||
// GPIOB_ClearITFlagBit(KEY_B_PIN);
|
||||
// 阻止睡眠
|
||||
BSP_BlockSleep();
|
||||
// 关按键中断
|
||||
BSP_KEY_ExitLowpower();
|
||||
|
||||
logDebug("KEY IRQ");
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
27
HAL/SLEEP.c
27
HAL/SLEEP.c
|
@ -16,8 +16,28 @@
|
|||
|
||||
#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
|
||||
*
|
||||
|
@ -29,6 +49,11 @@
|
|||
*/
|
||||
uint32_t CH59x_LowPower(uint32_t time)
|
||||
{
|
||||
if( true == block_sleep_flag)
|
||||
{
|
||||
// logDebug("block_sleep");
|
||||
return 0;
|
||||
}
|
||||
#if (defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
|
||||
volatile uint32_t i;
|
||||
uint32_t time_sleep, time_curr;
|
||||
|
@ -87,7 +112,7 @@ uint32_t CH59x_LowPower(uint32_t time)
|
|||
i = RTC_GetCycle32k();
|
||||
while (i == RTC_GetCycle32k());
|
||||
|
||||
// BSP_KEY_ExitLowpower();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ extern "C" {
|
|||
* GLOBAL VARIABLES
|
||||
*/
|
||||
|
||||
void BSP_RequestSleep(void);
|
||||
void BSP_BlockSleep(void);
|
||||
|
||||
/*********************************************************************
|
||||
* FUNCTIONS
|
||||
*/
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
* @Author : stark1898y 1658608470@qq.com
|
||||
* @Date : 2024-07-04 16:13:57
|
||||
* @LastEditors : stark1898y 1658608470@qq.com
|
||||
* @LastEditTime : 2024-09-25 14:33:23
|
||||
* @FilePath : \JT-DT-YD4N02A_RTT_MRS\packages\FlexibleButton-2.0.1\flexible_button.h
|
||||
* @LastEditTime : 2024-12-14 15:56:11
|
||||
* @FilePath : \BLE_TYQ_CH592F\common\FlexibleButton-2.0.1\flexible_button.h
|
||||
* @Description :
|
||||
*
|
||||
* Copyright (c) 2024 by yzy, All Rights Reserved.
|
||||
|
@ -43,8 +43,8 @@
|
|||
|
||||
#include "stdint.h"
|
||||
|
||||
#define FLEX_BTN_SCAN_FREQ_HZ 40 // How often flex_button_scan () is called
|
||||
#define FLEX_MS_TO_SCAN_CNT(ms) (ms / (1000 / FLEX_BTN_SCAN_FREQ_HZ)) //
|
||||
#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)) //
|
||||
/* Multiple clicks interval, default 300ms */
|
||||
#define MAX_MULTIPLE_CLICKS_INTERVAL (FLEX_MS_TO_SCAN_CNT(300))
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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)
|
||||
{}
|
||||
}
|
||||
```
|
|
@ -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...
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue