第一版代码,为了在EEPROM保存参数的时候走STM32的CRC,让Codex修改了一下,现在的效果是无法存储,codex表示原因是CRC方法不同,修改到一半今天的额度使用完了,有待后续解决CRC的bug
This commit is contained in:
148
Interface/Int_Key.c
Normal file
148
Interface/Int_Key.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "Int_Key.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/* 单个按键扫描上下文:
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user