diff --git a/README.md b/README.md index b6cf825..58cb3bf 100644 --- a/README.md +++ b/README.md @@ -64,13 +64,13 @@ void timer_5ms_isr(void) ## State Machine ``` - +-- long hold --> [LONG_HOLD] - | | -[IDLE] -- press --> [PRESS] release - ^ | | - | release | - | v | - | [RELEASE] <---------------------+ + +------------- release --------- [LONG_HOLD] + v ^ +[IDLE] -- press --> [PRESS] --long hold--+ + ^ | + | release + | v + | [RELEASE] | | ^ | timeout| | quick press | | | diff --git a/README_CN.md b/README_CN.md index 4cd0979..57711d1 100644 --- a/README_CN.md +++ b/README_CN.md @@ -265,13 +265,13 @@ void on_long_hold(Button* btn, void* user_data) ## 状态机说明 ``` - +-- 长按 --> [LONG_HOLD] - | | -[IDLE] -- 按下 --> [PRESS] 抬起 - ^ | | - | 抬起 | - | v | - | [RELEASE] <-----------------+ + +------------- 抬起 --------- [LONG_HOLD] + v ^ +[IDLE] -- 按下 --> [PRESS] ----- 长按 ----+ + ^ | + | 抬起 + | v + | [RELEASE] | | ^ | 超时| | 快速按下 | | | diff --git a/multi_button.c b/multi_button.c index e79c2b7..b4d03ec 100644 --- a/multi_button.c +++ b/multi_button.c @@ -177,6 +177,9 @@ static void button_handler(Button* handle) handle->event = (uint8_t)BTN_LONG_PRESS_START; EVENT_CB(BTN_LONG_PRESS_START); handle->state = BTN_STATE_LONG_HOLD; + #if LONG_CALLBACK_TICKS > 1 // if LONG_CALLBACK_TICKS is 1, we will call BTN_LONG_PRESS_HOLD immediately in the next tick, no need to reset ticks here + handle->ticks = 0; // reset for long-press hold timing + #endif } break; @@ -228,6 +231,9 @@ static void button_handler(Button* handle) if (handle->button_level == handle->active_level) { // Continue holding handle->event = (uint8_t)BTN_LONG_PRESS_HOLD; + #if LONG_CALLBACK_TICKS > 1 + if(handle->ticks % LONG_CALLBACK_TICKS != 0) break; // only call callback at defined intervals + #endif EVENT_CB(BTN_LONG_PRESS_HOLD); } else { // Released from long press diff --git a/multi_button.h b/multi_button.h index 3372a7a..96c9ef8 100644 --- a/multi_button.h +++ b/multi_button.h @@ -19,12 +19,18 @@ #define DEBOUNCE_TICKS 3 // MAX 7 (0 ~ 7) - debounce filter depth #define SHORT_TICKS (300 / TICKS_INTERVAL) // short press threshold #define LONG_TICKS (1000 / TICKS_INTERVAL) // long press threshold +#define LONG_CALLBACK_TICKS 5 // minimum TICKS interval between two BTN_LONG_PRESS_HOLD event callback. LONG_CALLBACK_TICKS * TICKS_INTERVAL = minimum interval in ms. #define PRESS_REPEAT_MAX_NUM 15 // maximum repeat counter value // Compile-time check: debounce_cnt is a 3-bit field, max value is 7 #if DEBOUNCE_TICKS > 7 #error "DEBOUNCE_TICKS exceeds 3-bit field maximum (7)" #endif +// Compile-time check: avoid div-0 problem +#if LONG_CALLBACK_TICKS < 1 + #error "LONG_CALLBACK_TICKS must be at least 1" +#endif + // Forward declaration typedef struct _Button Button; diff --git a/tests/test_button.c b/tests/test_button.c index 043c85c..98f1100 100644 --- a/tests/test_button.c +++ b/tests/test_button.c @@ -366,7 +366,7 @@ static int test_ticks_saturation(void) /* Press and hold the button */ mock_gpio_value = 1; - tick_n(DEBOUNCE_TICKS + 5); + tick_n(DEBOUNCE_TICKS + 5 + LONG_TICKS); /* Manually set ticks near UINT16_MAX to test saturation */ test_btn.ticks = UINT16_MAX - 2;