diff --git a/.vscode/settings.json b/.vscode/settings.json index a6d558b..6da6f11 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" } diff --git a/APP/peripheral.c b/APP/peripheral.c index e1e7378..88fd6a6 100644 --- a/APP/peripheral.c +++ b/APP/peripheral.c @@ -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" diff --git a/APP/peripheral_main.c b/APP/peripheral_main.c index 09fdf1c..7e85650 100644 --- a/APP/peripheral_main.c +++ b/APP/peripheral_main.c @@ -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); diff --git a/BSP/inc/bsp_key.h b/BSP/inc/bsp_key.h index f6a70c5..f60e049 100644 --- a/BSP/inc/bsp_key.h +++ b/BSP/inc/bsp_key.h @@ -6,11 +6,10 @@ #include #include -#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__ diff --git a/BSP/src/bsp_key.c b/BSP/src/bsp_key.c index 39a720a..4cf6a84 100644 --- a/BSP/src/bsp_key.c +++ b/BSP/src/bsp_key.c @@ -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); } diff --git a/HAL/SLEEP.c b/HAL/SLEEP.c index e7164ec..6ebd406 100644 --- a/HAL/SLEEP.c +++ b/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; } diff --git a/HAL/include/SLEEP.h b/HAL/include/SLEEP.h index ffacb5e..6488466 100644 --- a/HAL/include/SLEEP.h +++ b/HAL/include/SLEEP.h @@ -6,7 +6,7 @@ * Description : ********************************************************************************* * 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. *******************************************************************************/ @@ -22,6 +22,9 @@ extern "C" { * GLOBAL VARIABLES */ +void BSP_RequestSleep(void); +void BSP_BlockSleep(void); + /********************************************************************* * FUNCTIONS */ diff --git a/common/FlexibleButton-2.0.1/flexible_button.h b/common/FlexibleButton-2.0.1/flexible_button.h index f53c8e5..2456610 100644 --- a/common/FlexibleButton-2.0.1/flexible_button.h +++ b/common/FlexibleButton-2.0.1/flexible_button.h @@ -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)) diff --git a/common/MultiButton/LICENSE b/common/MultiButton/LICENSE new file mode 100644 index 0000000..1603075 --- /dev/null +++ b/common/MultiButton/LICENSE @@ -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. diff --git a/common/MultiButton/README.md b/common/MultiButton/README.md new file mode 100644 index 0000000..41ee54d --- /dev/null +++ b/common/MultiButton/README.md @@ -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) + {} +} +``` diff --git a/common/MultiButton/examples/example_callback.c b/common/MultiButton/examples/example_callback.c new file mode 100644 index 0000000..99ffff2 --- /dev/null +++ b/common/MultiButton/examples/example_callback.c @@ -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... +} diff --git a/common/MultiButton/examples/example_poll.c b/common/MultiButton/examples/example_poll.c new file mode 100644 index 0000000..8dec531 --- /dev/null +++ b/common/MultiButton/examples/example_poll.c @@ -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 + } + } + } +} diff --git a/common/MultiButton/multi_button.c b/common/MultiButton/multi_button.c new file mode 100644 index 0000000..66d1020 --- /dev/null +++ b/common/MultiButton/multi_button.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2016 Zibin Zheng + * 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); + } +} diff --git a/common/MultiButton/multi_button.h b/common/MultiButton/multi_button.h new file mode 100644 index 0000000..2974168 --- /dev/null +++ b/common/MultiButton/multi_button.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Zibin Zheng + * All rights reserved + */ + +#ifndef _MULTI_BUTTON_H_ +#define _MULTI_BUTTON_H_ + +#include +#include + +//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