Files
stc32g128k/Docs/60_coding/mod-key.md

150 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 编码实现 - 按键扫描与事件判定 (Docs/60_coding/mod-key.md)
本文件对应按键状态消抖、确认键长按 3 秒判定以及主键事件注入的具体编码实现细节。
## 1. 对应代码源文件
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定时中断内的按键扫描、按键状态高阻读取、长短按电平扫描)
## 2. 关键代码片段与逻辑实现
### 2.1 按键引脚定义与初始化
在主控初始化或 `Key_Init()` 中,配置按键 GPIO 为高阻输入并开启内部上拉:
```c
// 引脚声明
sbit KEY_UP = P2^0; // Pin 21
sbit KEY_DOWN = P3^6; // Pin 19
sbit KEY_CONFIRM = P3^7; // Pin 20
sbit KEY_SOS = P2^3; // Pin 24 (原理图上 SOS1/SOS2 并联至该引脚)
void Key_Init(void) {
// 设置为高阻输入
P2M1 |= 0x09; P2M0 &= ~0x09;
P3M1 |= 0xC0; P3M0 &= ~0xC0;
// 开启内部上拉
P2PU |= 0x09;
P3PU |= 0xC0;
}
```
### 2.2 按键中断定时器扫描 (每 10ms 调度一次)
`Timer1_Isr` 内通过定时器分频调用 `Key_Scan_Process()` 进行消抖与长短按状态判定,并将事件推入系统环形队列:
```c
void Key_Scan_Process(void) {
// 1. 读取引脚状态并进行 3 次移位消抖
static u8 key_up_state = 0xFF;
static u8 key_down_state = 0xFF;
static u8 key_confirm_state = 0xFF;
static u8 key_sos_state = 0xFF;
key_up_state = (key_up_state << 1) | KEY_UP;
key_down_state = (key_down_state << 1) | KEY_DOWN;
key_confirm_state = (key_confirm_state << 1) | KEY_CONFIRM;
key_sos_state = (key_sos_state << 1) | KEY_SOS;
// 2. 按键长按与短按状态机扫描
// ▲ 键 (UP) 处理
if ((key_up_state & 0x07) == 0) {
key_up_hold++;
} else {
if (key_up_hold > 2) {
Event_Queue_Push(KEY_EVENT_UP_CLICK);
}
key_up_hold = 0;
}
// ▼ 键 (DOWN) 处理 (支持长按 2 秒清除报警/退出)
if ((key_down_state & 0x07) == 0) {
key_down_hold++;
if (key_down_hold == 200) { // 2秒
Event_Queue_Push(KEY_EVENT_DOWN_LONG);
}
} else {
if (key_down_hold > 2 && key_down_hold < 200) {
Event_Queue_Push(KEY_EVENT_DOWN_CLICK);
}
key_down_hold = 0;
}
// ■ 确认键 (CONFIRM) 处理 (支持长按 3 秒进入菜单)
if ((key_confirm_state & 0x07) == 0) {
key_confirm_hold++;
if (key_confirm_hold == 300) { // 3秒
Event_Queue_Push(KEY_EVENT_SOS_LONG); // 复用为确认长按,拉起菜单
}
} else {
if (key_confirm_hold > 2 && key_confirm_hold < 300) {
Event_Queue_Push(KEY_EVENT_SOS_CLICK); // 确认单击
}
key_confirm_hold = 0;
}
// SOS 键 (物理双按键并联,按下任意即触发)
if ((key_sos_state & 0x07) == 0) {
key_sos_hold++;
if (key_sos_hold == 3) { // 30ms 快速响应
Event_Queue_Push(KEY_SOS_ACTIVE);
}
} else {
key_sos_hold = 0;
}
}
```
### 2.2 事件解调与微调分配分发 (Process_System_Event 示例)
在主循环事件分发中,对各个状态下的事件进行处理:
```c
void Process_System_Event(KeyEvent evt) {
switch (current_state) {
case STATE_MENU:
if (evt == KEY_UP_SHORT) {
if (menu_index > 0) menu_index--;
Redraw = 1;
} else if (evt == KEY_DOWN_SHORT) {
if (menu_index < 3) menu_index++;
Redraw = 1;
} else if (evt == KEY_CONFIRM_CLICK) {
Enter_Menu_Branch(menu_index);
} else if (evt == KEY_CONFIRM_LONG) {
current_state = STATE_CLOCK;
Redraw = 1;
}
break;
case STATE_PAIR_CONFIRM:
// 直接进行后缀序号微调 (传感器类型已由射频数据码自动识别并锁定)
if (evt == KEY_UP_SHORT) {
if (selected_suffix < 99) selected_suffix++;
Redraw = 1;
} else if (evt == KEY_DOWN_SHORT) {
if (selected_suffix > 1) selected_suffix--;
Redraw = 1;
} else if (evt == KEY_CONFIRM_CLICK) {
// 点击 CONFIRM直接将自动解析的类型和调整好的序号写入数据库
Add_Sensor(captured_addr, auto_detected_type, selected_suffix);
current_state = STATE_CLOCK;
Redraw = 1;
} else if (evt == KEY_CONFIRM_LONG) {
// 长按 3 秒放弃保存返回时钟
current_state = STATE_CLOCK;
Redraw = 1;
}
break;
case STATE_IPC_BIND:
if (evt == KEY_CONFIRM_LONG || evt == KEY_DOWN_LONG) {
current_state = STATE_CLOCK;
Redraw = 1;
} else if (evt == KEY_CONFIRM_CLICK) {
EV1527_Transmit(bracelet_factory_id, 0x01);
}
break;
// 其它状态处理...
}
}
```
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->