From 799d8e43b54f68c61c7b63e43d4a3487754dfe60 Mon Sep 17 00:00:00 2001 From: Dien-Nhung Nguyen-Phu Date: Sun, 2 Jun 2024 18:27:36 +0700 Subject: button: add basic button functionalities - Provided a way to set handler for each button one-press/long-press - Debouncing with RC filter and Schmitt trigger --- src/button.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/button.c (limited to 'src/button.c') diff --git a/src/button.c b/src/button.c new file mode 100644 index 0000000..6adb495 --- /dev/null +++ b/src/button.c @@ -0,0 +1,89 @@ +#include "button.h" + +#define DEBOUNCE_HIGH_THRES (200) // 0-255 +#define DEBOUNCE_LOW_THRES (55) // 0-255 +#define LONGPRESS_THRES (25) // Hz +#define BUTTON_SCAN_FREQ (50) // Hz + +static volatile void (*onePressHandler[KEY_INDEX])(void) = { NULL }; +static volatile void (*longPressHandler[KEY_INDEX])(void) = { NULL }; + +void btn_init() +{ + GPIOA_ModeCfg(KEY1_PIN, GPIO_ModeIN_PD); + GPIOB_ModeCfg(KEY2_PIN, GPIO_ModeIN_PU); + + TMR3_TimerInit(FREQ_SYS/BUTTON_SCAN_FREQ); + TMR3_ITCfg(ENABLE, TMR0_3_IT_CYC_END); + PFIC_EnableIRQ(TMR3_IRQn); +} + +void btn_onOnePress(int key, void (*handler)(void)) +{ + if (key >= KEY_INDEX) return; + onePressHandler[key] = handler; +} + +void btn_onLongPress(int key, void (*handler)(void)) +{ + if (key >= KEY_INDEX) return; + longPressHandler[key] = handler; +} + +__HIGH_CODE +static int debounce(int key, int is_press) +{ + static int y[KEY_INDEX], flag[KEY_INDEX]; + if (key >= KEY_INDEX) return 0; + + // RC filter + y[key] -= y[key] >> 2; + y[key] += is_press ? 0x3F : 0; + + // Schmitt trigger + if ((y[key] > DEBOUNCE_HIGH_THRES) && (flag[key] == 0)) + flag[key] = 1; + if ((y[key] < DEBOUNCE_LOW_THRES) && (flag[key] == 1)) + flag[key] = 0; + + return flag[key]; +} + +__HIGH_CODE +static void check(int k) +{ + static int hold[KEY_INDEX], is_longpress[KEY_INDEX]; + if (k >= KEY_INDEX) return; // TODO: assert instead + + if (debounce(k, isPressed(k))) { + hold[k]++; + if (hold[k] >= LONGPRESS_THRES && is_longpress[k] == 0) { + is_longpress[k] = 1; + if (longPressHandler[k]) longPressHandler[k](); + } + } else { + if (hold[k] > 0 && hold[k] < LONGPRESS_THRES) { + if (onePressHandler[k]) onePressHandler[k](); + } + is_longpress[k] = 0; + hold[k] = 0; + } +} + +__HIGH_CODE +static void check_keys() +{ + for (int k=0; k