#include "Int_Key.h" #include /* 单个按键扫描上下文: * raw_level 原始采样电平 * stable_level 去抖后的稳定电平 * long_started 是否已上报过长按开始事件 */ typedef struct { GPIO_TypeDef *port; uint16_t pin; Key_t key; uint8_t stable_level; uint8_t raw_level; uint8_t long_started; uint32_t last_change_ms; uint32_t press_ms; } KeyScanCtx_t; #define KEY_COUNT (5u) #define KEY_SCAN_PERIOD_MS (5u) #define KEY_DEBOUNCE_MS (20u) #define KEY_LONG_MS (400u) #define KEY_QUEUE_SIZE (12u) static KeyScanCtx_t s_keys[KEY_COUNT] = { {KEY1_GPIO_Port, KEY1_Pin, KEY_1, 1u, 1u, 0u, 0u, 0u}, {KEY2_GPIO_Port, KEY2_Pin, KEY_2, 1u, 1u, 0u, 0u, 0u}, {KEY3_GPIO_Port, KEY3_Pin, KEY_3, 1u, 1u, 0u, 0u, 0u}, {KEY4_GPIO_Port, KEY4_Pin, KEY_4, 1u, 1u, 0u, 0u, 0u}, {KEY5_GPIO_Port, KEY5_Pin, KEY_5, 1u, 1u, 0u, 0u, 0u}, }; static KeyAction_t s_queue[KEY_QUEUE_SIZE]; static uint8_t s_q_head = 0u; static uint8_t s_q_tail = 0u; static uint32_t s_last_scan_ms = 0u; static uint8_t queue_next(uint8_t v) { /* 环形队列下标递增。 */ v++; if (v >= KEY_QUEUE_SIZE) { v = 0u; } return v; } static void push_action(Key_t key, KeyEvt_t evt) { /* 队列满时丢弃新事件,避免阻塞主循环。 */ uint8_t next = queue_next(s_q_head); if (next == s_q_tail) { return; } s_queue[s_q_head].key = key; s_queue[s_q_head].evt = evt; s_q_head = next; } void Int_Key_Task(void) { uint32_t now = HAL_GetTick(); /* 固定周期扫描,避免过高频率浪费CPU。 */ if ((uint32_t)(now - s_last_scan_ms) < KEY_SCAN_PERIOD_MS) { return; } s_last_scan_ms = now; for (uint8_t i = 0u; i < KEY_COUNT; i++) { KeyScanCtx_t *k = &s_keys[i]; uint8_t raw = (HAL_GPIO_ReadPin(k->port, k->pin) == GPIO_PIN_RESET) ? 0u : 1u; if (raw != k->raw_level) { k->raw_level = raw; k->last_change_ms = now; } if ((uint32_t)(now - k->last_change_ms) >= KEY_DEBOUNCE_MS) { if (k->stable_level != k->raw_level) { k->stable_level = k->raw_level; if (k->stable_level == 0u) { /* 稳定按下:记录按下时间,等待长按判断。 */ k->press_ms = now; k->long_started = 0u; } else { /* 稳定释放:若未触发长按则上报CLICK,否则上报RELEASE。 */ push_action(k->key, k->long_started ? KEY_EVT_RELEASE : KEY_EVT_CLICK); } } } if (k->stable_level == 0u) { uint32_t hold_ms = (uint32_t)(now - k->press_ms); if (hold_ms >= KEY_LONG_MS) { if (k->long_started == 0u) { /* 长按开始事件只上报一次。 */ k->long_started = 1u; push_action(k->key, KEY_EVT_LONG_START); } } } } } bool Int_Key_PopAction(KeyAction_t *action) { /* 从事件队列弹出一个事件供上层消费。 */ if (action == NULL) { return false; } if (s_q_tail == s_q_head) { return false; } *action = s_queue[s_q_tail]; s_q_tail = queue_next(s_q_tail); return true; } Key_t Int_key_read(void) { /* 兼容旧接口:仅返回按键编号,不区分事件类型。 */ KeyAction_t action; if (Int_Key_PopAction(&action)) { return action.key; } return KEY_NONE; }