#include "../main/SystemInclude.h" // 全局变量(静态,仅本文件访问) Device_StateTypeDef g_device_state = DEVICE_STATE_OFF; // 初始状态:关机 uint32_t g_key_press_time = 0; // 按键按下累计时间(单位:扫描周期) uint8_t g_key_last_state = 0; // 按键上一次状态(0=未按下,1=按下) extern bool g_SystemStartupComplete; // 单位按键按下标志位 volatile uint8_t key_press_flag = 0; // 1 = 定时器时间到,请求关机;0 = 无关机请求 volatile uint8_t g_auto_shutdown_flag = 0; // 引脚初始化:PA0(下拉输入)、PA1(推挽输出) void Key_Power_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; // PA0:下拉输入(按键检测) GPIO_InitStruct.Pin = KEY1_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Current = GPIO_CURRENT_2mA; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.SchmittTrigger = ENABLE; GPIO_InitStruct.Alternate = GPIOx_AF_GPIO; // // AF为普通IO LHL_GPIO_Init(KEY1_PORT, &GPIO_InitStruct); // PA1:推挽输出(电源控制) GPIO_InitStruct.Pin = POWER_CTRL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Current = GPIO_CURRENT_2mA; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.SchmittTrigger = ENABLE; GPIO_InitStruct.Alternate = GPIOx_AF_GPIO; // // AF为普通IO LHL_GPIO_Init(POWER_CTRL_PORT, &GPIO_InitStruct); // 初始状态:关机→PA1拉低(关闭外部电源) LHL_GPIO_WritePin(POWER_CTRL_PORT, POWER_CTRL_PIN, GPIO_PIN_RESET); g_device_state = DEVICE_STATE_OFF; // 单位切换检测脚:上拉输入 GPIO_InitStruct.Pin = UnitKEY_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Current = GPIO_CURRENT_2mA; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.SchmittTrigger = ENABLE; GPIO_InitStruct.Alternate = GPIOx_AF_GPIO; // // AF为普通IO LHL_GPIO_Init(UnitKEY_PORT, &GPIO_InitStruct); } // 设备开机处理 static void Device_Start(void) { LHL_GPIO_WritePin(POWER_CTRL_PORT, POWER_CTRL_PIN,GPIO_PIN_SET); // PA1拉高→外部电源启动 delay_ms(100); // 等待电源稳定 g_device_state = DEVICE_STATE_ON; g_key_press_time = 0; // 重置按键计时 g_auto_shutdown_flag = 0; } // 设备关机处理 static void Device_Shutdown(void) { LHL_GPIO_WritePin(POWER_CTRL_PORT, POWER_CTRL_PIN,GPIO_PIN_RESET); // PA1拉低→外部电源关闭 delay_ms(100); // 等待电源完全关闭 g_device_state = DEVICE_STATE_OFF; g_key_press_time = 0; } // 增加一个标志位,用于记录长按是否已经触发 static bool g_key_long_pressed_flag = false; // 增加消抖计数器 static uint16_t g_key_debounce_count = 0; void Key_Scan_Task(void) { // 1. 读取当前按键状态 uint8_t key_current_state = LHL_GPIO_ReadPin(KEY1_PORT, KEY1_PIN); // 2. 简单的消抖处理:当读取到状态与上次一致时,计数器增加;否则重置 if (key_current_state == g_key_last_state) { if (g_key_debounce_count < 65535) g_key_debounce_count++; } else { g_key_debounce_count = 0; g_key_last_state = key_current_state; // 更新状态以便下一次比较 } // 3. 只有消抖计数器达到阈值(例如5次,即50ms)才认为状态有效 if (g_key_debounce_count < 2) { return; } // 如果设备处于开机状态,且检测到自动关机标志被置 1 if (g_device_state == DEVICE_STATE_ON) { if (g_auto_shutdown_flag == 1) { Device_Shutdown(); // 执行关机 g_auto_shutdown_flag = 0; // 清除标志位,防止死循环关机 // 注意:这里不需要 break,因为关机后状态变为 OFF,下面的 switch 不会再执行 ON 的分支 } } // 4. 状态机处理 switch (g_device_state) { case DEVICE_STATE_OFF: if (key_current_state == 1) { // 按键按下 if (!g_key_long_pressed_flag) { g_key_press_time++; // 长按阈值检查 (40 * 10ms = 400ms) if (g_key_press_time >= (KEY_PRESS_TIME_LONG / KEY_SCAN_INTERVAL)) { Device_Start(); // 执行开机 g_key_long_pressed_flag = true; // 标记长按已触发,防止重复执行 } } } else { // 按键松开 g_key_press_time = 0; g_key_long_pressed_flag = false; // 重置长按标志 } break; case DEVICE_STATE_ON: if (key_current_state == 1) { // 按键按下 if (!g_key_long_pressed_flag) { g_key_press_time++; if (g_key_press_time >= (KEY_PRESS_TIME_LONG / KEY_SCAN_INTERVAL)) { Device_Shutdown(); // 执行关机 g_key_long_pressed_flag = true; // 标记长按已触发 } } } else { // 按键松开 g_key_press_time = 0; g_key_long_pressed_flag = false; // 重置长按标志 } break; } } // 获取当前设备状态 Device_StateTypeDef Get_Device_State(void) { return g_device_state; } void Unit_key(void) { static uint8_t key_state = 0; // 0: 释放/消抖中, 1: 已确认按下 static uint16_t key_count = 0; uint8_t key_level = LHL_GPIO_ReadPin(UnitKEY_PORT,UnitKEY_PIN); switch (key_state) { case 0: if (key_level == 0) { key_count++; if (key_count >= 3) { key_state = 1; key_press_flag = 1;// 触发事件:告诉主循环有按键按下 key_count=0; } } else { key_count = 0; // 只要没按下,就一直清零 } break; case 1: if (key_level == 1) {// 检测到松开 key_state = 0; key_count = 0;// 复位计数,准备下一次 } break; } }