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

5.5 KiB
Raw Blame History

编码实现 - 按键扫描与事件判定 (Docs/60_coding/mod-key.md)

本文件对应按键状态消抖、确认键长按 3 秒判定以及主键事件注入的具体编码实现细节。

1. 对应代码源文件

  • App/main.c (定时中断内的按键扫描、按键状态高阻读取、长短按电平扫描)

2. 关键代码片段与逻辑实现

2.1 按键中断定时器扫描 (每 10ms 调度一次)

Timer1_Isr (1ms 滴答) 内,通过 key_scan_timer 进行 10ms 分频并调用 Key_Scan_Process()

void Key_Scan_Process(void) {
    // 1. 读取引脚状态并消抖
    static u8 key_up_state = 0xFF;
    static u8 key_down_state = 0xFF;
    static u8 key_confirm_state = 0xFF;
    static u8 key_sos1_state = 0xFF;
    static u8 key_sos2_state = 0xFF;
    u8 key_sos_state;
    
    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_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;
    
    // 2. 按键长按与短按状态机扫描
    
    // ▲ 键 (UP) 处理
    if ((key_up_state & 0x07) == 0) {
        key_up_hold++;
    } else {
        if (key_up_hold > 2) {
            key_event_buf = KEY_UP_SHORT;
        }
        key_up_hold = 0;
    }
    
    // ▼ 键 (DOWN) 处理 (支持长按 2 秒清除报警/退出)
    if ((key_down_state & 0x07) == 0) {
        key_down_hold++;
        if (key_down_hold == 200) { // 2秒
            key_event_buf = KEY_DOWN_LONG;
        }
    } else {
        if (key_down_hold > 2 && key_down_hold < 200) {
            key_event_buf = KEY_DOWN_SHORT;
        }
        key_down_hold = 0;
    }
    
    // ■ 确认键 (CONFIRM) 处理 (支持长按 3 秒进入/退出)
    if ((key_confirm_state & 0x07) == 0) {
        key_confirm_hold++;
        if (key_confirm_hold == 300) { // 3秒
            key_event_buf = KEY_CONFIRM_LONG;
        }
    } else {
        if (key_confirm_hold > 2 && key_confirm_hold < 300) {
            key_event_buf = KEY_CONFIRM_CLICK;
        }
        key_confirm_hold = 0;
    }
    
    // 并联 SOS 键
    if ((key_sos_state & 0x07) == 0) {
        key_sos_hold++;
        if (key_sos_hold == 3) {
            key_event_buf = KEY_SOS_ACTIVE;
        }
    } else {
        key_sos_hold = 0;
    }
}

2.2 事件异步处理与分发 (Process_System_Event 示例)

在主循环事件分发中,对各个状态下的事件进行处理:

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) {
                // 长按 3 秒退出菜单返回时钟待机
                current_state = STATE_CLOCK;
                Redraw = 1;
            }
            break;
            
        case STATE_PAIR_CONFIRM:
            if (confirm_edit_focus == 0) {
                // 第一步:编辑传感器类型
                if (evt == KEY_UP_SHORT) {
                    if (selected_type < 6) selected_type++;
                    else selected_type = 0;
                    Redraw = 1;
                } else if (evt == KEY_DOWN_SHORT) {
                    if (selected_type > 0) selected_type--;
                    else selected_type = 6;
                    Redraw = 1;
                } else if (evt == KEY_CONFIRM_CLICK) {
                    // 点击确认,锁定类型,跳入第二步选择序号
                    confirm_edit_focus = 1;
                    Redraw = 1;
                }
            } else if (confirm_edit_focus == 1) {
                // 第二步:编辑序号后缀
                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) {
                    // 点击确认,完成最终写入保存,返回时钟
                    Add_Sensor(captured_addr, selected_type, selected_suffix);
                    current_state = STATE_CLOCK;
                    Redraw = 1;
                }
            }
            // 长按 CONFIRM 3 秒退出不保存
            if (evt == KEY_CONFIRM_LONG) {
                current_state = STATE_CLOCK;
                Redraw = 1;
            }
            break;

        case STATE_IPC_BIND:
            // IPC 绑定连发状态中支持物理长按退出
            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;
            
        // 其它状态处理...
    }
}