#include "key.h" #include "stdio.h" static uint16_t msTicks = 0; // updated every 1ms in SysTick interrupt #define DEBOUNCE_TIME 10 // 消抖时间 10ms #define LONG_HOLD_TIME 500 // 长按时间 500ms #define ULTRA_LONG_HOLD_TIME 1000 // 超长按时间 1000ms #define DOUBLE_CLICK_INTERVAL 200 // 双击间隔时间 250ms // 定义按键状态 typedef enum { KEY_STATE_RELEASED, KEY_STATE_DEBOUNCE_PRESS, KEY_STATE_PRESSED, KEY_STATE_DEBOUNCE_RELEASE, KEY_STATE_MAY_DOUBLE_CLICK = 4, KEY_STATE_MAX = 0XFF } keyState; // 定义按键结构体 typedef struct { keyState state; // 按键状态 uint16_t clickedTime; // 保存最后一次按下的时间 uint16_t releasedTime; // 保存最后一次释放的时间 uint8_t clickCount; // 计数器 uint8_t debounceTime; // 消抖时间 uint16_t longHoldTime; // 长按时间 uint16_t ultraLongHoldTime; // 超长按时间 uint16_t doubleClikeInterval; // 双击间隔时间 uint8_t longHoldTriggered; // 长按标志 char (*readKeyPin)(void); void (*clickHandler)(void); // 单击事件处理函数 void (*doubleClickHandler)(void); // 双击处理函数 void (*longHoldHandler)(void); // 长按事件处理函数 void (*ultraLongHoldHandler)(void); // 超长按事件处理函数 } KeyHandle_t; // 功能按键 char readFuncKeyPin(void) { return KEY_FUNCTION_LEVE ? 1 : 0; } // 增加键 char readAddKeyPin(void) { return KEY_ADD_LEVE ? 1 : 0; } // 减少键 char readReduceKeyPin(void) { return KEY_REDUCE_LEVE ? 1 : 0; } extern void printLongHold(void); extern void printDoubleClicked(void); extern void printClicked(void); // 定义三个物理按键 KeyHandle_t xdata keyhs[] = { // 功能按键 {KEY_STATE_RELEASED, 0, 0, 0, DEBOUNCE_TIME, LONG_HOLD_TIME, ULTRA_LONG_HOLD_TIME, DOUBLE_CLICK_INTERVAL, 0, readFuncKeyPin, printClicked, printDoubleClicked, printLongHold, NULL}, // 增加按键 {KEY_STATE_RELEASED, 0, 0, 0, DEBOUNCE_TIME, LONG_HOLD_TIME, ULTRA_LONG_HOLD_TIME, DOUBLE_CLICK_INTERVAL, 0, readAddKeyPin, printClicked, printDoubleClicked, printLongHold, NULL}, // 减少按键 {KEY_STATE_RELEASED, 0, 0, 0, DEBOUNCE_TIME, LONG_HOLD_TIME, ULTRA_LONG_HOLD_TIME, DOUBLE_CLICK_INTERVAL, 0, readReduceKeyPin, printClicked, printDoubleClicked, printLongHold, NULL}, }; void Key_Init(void) { // 初始化引脚 KEY_FUNCTION_LEVE = 1; KEY_ADD_LEVE = 1; KEY_REDUCE_LEVE = 1; } void Key_Process(KeyHandle_t *key, uint16_t now); void keyTask(void) { uint8_t i = 0; for (; i < sizeof(keyhs) / sizeof(keyhs[0]); i++) { Key_Process(&keyhs[i], msTicks); } } // 这些函数在ram区有用 void registerClickCallBack(KeyHandle_t *key, void (*cb)(void)) { key->doubleClickHandler = cb; } void registerDoubleClickCallBack(KeyHandle_t *key, void (*cb)(void)) { key->doubleClickHandler = cb; } void registerLongHoldCallBack(KeyHandle_t *key, void (*cb)(void)) { key->doubleClickHandler = cb; } void key_Ticks(void) { msTicks++; } void Key_Process(KeyHandle_t const *key, uint16_t now) { uint16_t elapsedTime; char isPressed = 0; if (key->readKeyPin != NULL) isPressed = !key->readKeyPin(); switch (key->state) { case KEY_STATE_RELEASED: if (isPressed) { // 检测到引脚是低电平,进入消抖状态 key->state = KEY_STATE_DEBOUNCE_PRESS; key->clickedTime = now; } break; case KEY_STATE_DEBOUNCE_PRESS: elapsedTime = now - key->clickedTime; if (isPressed) { if (elapsedTime >= key->debounceTime) { // 超过消抖时间,确认按键被按下 key->state = KEY_STATE_PRESSED; } } else { // 干扰或者抖动重新检测 key->state = KEY_STATE_RELEASED; } break; case KEY_STATE_PRESSED: if (!isPressed) { // 在按键被按下的状态下,检测引脚释放,切换到等待释放状态,因为有可能是抖动。 key->releasedTime = now; key->state = KEY_STATE_DEBOUNCE_RELEASE; } else { elapsedTime = now - key->clickedTime; if (elapsedTime >= key->ultraLongHoldTime) { // 超过最长时间 key->state = KEY_STATE_RELEASED; key->clickCount = 0; if (key->ultraLongHoldHandler != NULL) key->ultraLongHoldHandler(); } else if (elapsedTime >= key->longHoldTime) { key->state = KEY_STATE_RELEASED; key->clickCount = 0; key->longHoldTriggered = 1; if (key->longHoldHandler != NULL) key->longHoldHandler(); } } break; case KEY_STATE_DEBOUNCE_RELEASE: elapsedTime = now - key->releasedTime; if (!isPressed) { if (elapsedTime >= key->debounceTime) { // 按键确实释放了 if (key->clickCount == 0) { // 有可能是双击事件,需要进一步确认 key->state = KEY_STATE_MAY_DOUBLE_CLICK; key->clickCount++; } else { // 双击事件 key->state = KEY_STATE_RELEASED; key->clickCount = 0; if (key->doubleClickHandler != NULL) key->doubleClickHandler(); } } } else { key->state = KEY_STATE_PRESSED; } break; case KEY_STATE_MAY_DOUBLE_CLICK: elapsedTime = now - key->releasedTime; if (isPressed) { key->state = KEY_STATE_DEBOUNCE_PRESS; key->clickedTime = now; // 重新记录按键按下的时间点 } else { if (elapsedTime >= DOUBLE_CLICK_INTERVAL) { // 释放的时间超过双击间隔 if (!key->longHoldTriggered) { if (key->clickHandler != NULL) key->clickHandler(); } else key->longHoldTriggered = 0; key->clickCount = 0; key->state = KEY_STATE_RELEASED; } } break; default: break; } }