2026-07-09 10:49:15 +08:00
|
|
|
|
# 编码实现 - 按键扫描与事件判定 (Docs/60_coding/mod-key.md)
|
2026-07-09 10:31:36 +08:00
|
|
|
|
|
|
|
|
|
|
本文件对应按键状态消抖、长按计时判定以及组合按键识别的具体编码实现细节。
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 对应代码源文件
|
|
|
|
|
|
|
|
|
|
|
|
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定时中断内的按键扫描、按键状态累加、主循环事件处理)
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 关键代码片段与逻辑实现
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 按键中断定时器扫描 (每 10ms 调度一次)
|
|
|
|
|
|
在 `Timer1_Isr` (1ms 滴答) 内,通过 `key_scan_timer` 进行 10ms 分频并调用 `Key_Scan_Process()`:
|
|
|
|
|
|
```c
|
|
|
|
|
|
void Key_Scan_Process(void) {
|
|
|
|
|
|
// 1. 读取引脚状态并消抖
|
|
|
|
|
|
static u8 key_up_state = 0xFF;
|
|
|
|
|
|
static u8 key_down_state = 0xFF;
|
2026-07-09 10:49:15 +08:00
|
|
|
|
static u8 key_confirm_state = 0xFF;
|
|
|
|
|
|
static u8 key_sos1_state = 0xFF;
|
|
|
|
|
|
static u8 key_sos2_state = 0xFF;
|
|
|
|
|
|
u8 key_sos_state;
|
2026-07-09 10:31:36 +08:00
|
|
|
|
|
|
|
|
|
|
key_up_state = (key_up_state << 1) | KEY_UP;
|
|
|
|
|
|
key_down_state = (key_down_state << 1) | KEY_DOWN;
|
2026-07-09 10:49:15 +08:00
|
|
|
|
key_confirm_state = (key_confirm_state << 1) | KEY_CONFIRM;
|
|
|
|
|
|
key_sos1_state = (key_sos1_state << 1) | KEY_SOS1;
|
|
|
|
|
|
key_sos2_state = (key_sos2_state << 1) | KEY_SOS2;
|
|
|
|
|
|
|
|
|
|
|
|
// 双上部 SOS 键的逻辑并联(低电平有效,按位与运算相当于逻辑或)
|
|
|
|
|
|
key_sos_state = key_sos1_state & key_sos2_state;
|
2026-07-09 10:31:36 +08:00
|
|
|
|
|
|
|
|
|
|
// 2. 长按与组合按键计时器累加
|
|
|
|
|
|
if ((key_up_state & 0x07) == 0 && (key_down_state & 0x07) == 0) {
|
|
|
|
|
|
// ▲ + ▼ 组合键按住
|
|
|
|
|
|
comb_hold++;
|
|
|
|
|
|
if (comb_hold == 300) { // 3秒
|
|
|
|
|
|
key_event_buf = KEY_COMB_LONG;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
comb_hold = 0;
|
|
|
|
|
|
|
2026-07-09 10:49:15 +08:00
|
|
|
|
// 单个按键:▲ 键 (UP)
|
2026-07-09 10:31:36 +08:00
|
|
|
|
if ((key_up_state & 0x07) == 0) {
|
|
|
|
|
|
key_up_hold++;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (key_up_hold > 2 && key_up_hold < 200) {
|
|
|
|
|
|
key_event_buf = KEY_UP_SHORT;
|
|
|
|
|
|
}
|
|
|
|
|
|
key_up_hold = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-09 10:49:15 +08:00
|
|
|
|
// 单个按键:■ 确认键 (CONFIRM)
|
|
|
|
|
|
if ((key_confirm_state & 0x07) == 0) {
|
|
|
|
|
|
key_confirm_hold++;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (key_confirm_hold > 2 && key_confirm_hold < 200) {
|
|
|
|
|
|
key_event_buf = KEY_CONFIRM_CLICK;
|
|
|
|
|
|
}
|
|
|
|
|
|
key_confirm_hold = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 单个按键:并联 SOS 键
|
2026-07-09 10:31:36 +08:00
|
|
|
|
if ((key_sos_state & 0x07) == 0) {
|
|
|
|
|
|
key_sos_hold++;
|
|
|
|
|
|
if (key_sos_hold == 500) { // 5秒
|
|
|
|
|
|
key_event_buf = KEY_SOS_LONG;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if (key_sos_hold > 2 && key_sos_hold < 500) {
|
|
|
|
|
|
key_event_buf = KEY_SOS_SHORT;
|
|
|
|
|
|
}
|
|
|
|
|
|
key_sos_hold = 0;
|
|
|
|
|
|
}
|
2026-07-09 10:49:15 +08:00
|
|
|
|
// ▼ 键 (DOWN) 处理同上...
|
2026-07-09 10:31:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-07-09 14:55:44 +08:00
|
|
|
|
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
2026-07-09 11:03:18 +08:00
|
|
|
|
|
2026-07-09 10:31:36 +08:00
|
|
|
|
### 2.2 事件异步读取与清除
|
|
|
|
|
|
主循环在其周期内轮询 `key_event_buf`。一旦发现其非 `KEY_EVENT_NONE`,拷贝并立即重置该缓冲区为 `KEY_EVENT_NONE` 以防止重复触发:
|
|
|
|
|
|
```c
|
|
|
|
|
|
if (key_event_buf != KEY_EVENT_NONE) {
|
|
|
|
|
|
KeyEvent evt = key_event_buf;
|
|
|
|
|
|
key_event_buf = KEY_EVENT_NONE; // 清空事件缓冲区
|
|
|
|
|
|
|
|
|
|
|
|
// 执行具体事件动作,如在常态下短按 SOS 进入 SOS 警报发射状态等
|
|
|
|
|
|
// ...
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
通过该缓冲区实现了按键中断采集与主循环处理的解耦。
|