diff --git a/Core/Inc/input.h b/Core/Inc/input.h index 9ac54d5..326ccf0 100644 --- a/Core/Inc/input.h +++ b/Core/Inc/input.h @@ -42,7 +42,8 @@ void Input_Scan(void); /* 每 10ms 调用一次 */ uint8_t Input_GetKey(void); /* 返回当前按下的键 (单次) */ uint8_t Input_GetKeyState(uint8_t key); /* 获取按键状态 */ uint8_t Input_IsKeyPressed(uint8_t key); /* 是否刚按下 */ -uint8_t Input_IsKeyHeld(uint8_t key); /* 是否长按 */ +uint8_t Input_IsKeyHeld(uint8_t key); /* 是否长按 (800ms) */ +uint8_t Input_IsKeyHeldFor(uint8_t key, uint32_t ms); /* 是否按住指定时长 */ uint8_t Input_IsKeyReleased(uint8_t key); /* 是否刚释放 */ /* ADC 读取 */ diff --git a/Core/Inc/main.h b/Core/Inc/main.h index c719d4d..9ae16e9 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -53,7 +53,7 @@ extern "C" { void Error_Handler(void); /* USER CODE BEGIN EFP */ - +void System_Shutdown(void); /* 系统关机: 关闭外设进入休眠 */ /* USER CODE END EFP */ /* Private defines -----------------------------------------------------------*/ diff --git a/Core/Inc/oled.h b/Core/Inc/oled.h index a92660d..3f51375 100644 --- a/Core/Inc/oled.h +++ b/Core/Inc/oled.h @@ -24,6 +24,7 @@ /* OLED 初始化 */ void OLED_Init(void); +void OLED_Off(void); /* 关闭 OLED 显示 */ /* 基础操作 */ void OLED_Clear(void); diff --git a/Core/Src/input.c b/Core/Src/input.c index 7fc338d..e4b96b7 100644 --- a/Core/Src/input.c +++ b/Core/Src/input.c @@ -147,6 +147,14 @@ uint8_t Input_IsKeyHeld(uint8_t key) { return (key_state[key] == KEY_STATE_HOLD) ? 1 : 0; } +uint8_t Input_IsKeyHeldFor(uint8_t key, uint32_t ms) { + if (key > 3) return 0; + /* 按键按下且按住时间 >= ms */ + if (key_current[key] && (sys_tick_ms - key_press_time[key] >= ms)) + return 1; + return 0; +} + uint8_t Input_IsKeyReleased(uint8_t key) { if (key > 3) return 0; if (key_state[key] == KEY_STATE_RELEASE) { diff --git a/Core/Src/main.c b/Core/Src/main.c index f39b518..7d31221 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -54,6 +54,7 @@ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define MAIN_LOOP_PERIOD_MS 10 /* 主循环周期 10ms */ +#define POWER_OFF_HOLD_MS 2000 /* 长按关机阈值 */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ @@ -72,6 +73,7 @@ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ static void System_Init(void); static void System_Loop10ms(void); +void System_Shutdown(void); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ @@ -205,9 +207,10 @@ static void System_Init(void) { /* 2. 初始化 OLED 并显示开机画面 */ OLED_Init(); - OLED_DrawBitmap(0, 0, bitmap_bytes, 64, 64); /* 开机 Logo */ - OLED_ShowString(70, 20, "Loli3", 16); - OLED_ShowString(70, 40, "RC v3.0", 6); + /* 左侧: 开机 Logo (64x64) */ + OLED_DrawBitmap(0, 0, bitmap_bytes, 64, 64); + /* 右侧: "Starting..." 上下居中 */ + OLED_ShowString(66, 28, "Starting...", 6); OLED_Display(); HAL_Delay(2000); /* 显示 2 秒 */ @@ -255,6 +258,54 @@ static void System_Loop10ms(void) { LED_Update(); } +/** + * @brief 系统关机: 关闭所有外设, 进入 STOP 休眠模式 + * @retval None + */ +void System_Shutdown(void) { + /* 1. 关闭 OLED */ + OLED_Off(); + + /* 2. 关闭所有 LED */ + LED_SetSystem(0); + LED_SetNRF(3); + LED_SetCRFS(3); + + /* 3. 停止 PWM 输出 */ + PWM_SetMode(0, PWM_MODE_DISABLED); + PWM_SetMode(1, PWM_MODE_DISABLED); + + /* 4. 关闭 NRF24L01 (进入掉电模式) */ + NRF24L01_WriteReg(NRF_CONFIG, 0x00); /* PWR_DOWN */ + + /* 5. 关闭 USB */ + HAL_PCD_Stop(&hpcd_USB_FS); + + /* 6. 关闭各外设时钟 */ + HAL_ADC_Stop(&hadc1); + HAL_ADC_Stop(&hadc2); + HAL_UART_DeInit(&huart1); + HAL_UART_DeInit(&huart3); + HAL_SPI_DeInit(&hspi1); + HAL_I2C_DeInit(&hi2c2); + + /* 7. 关闭 TIM 时钟 */ + HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1); + HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_2); + HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_3); + HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_3); + HAL_TIM_PWM_Stop(&htim4, TIM_CHANNEL_4); + HAL_TIM_Base_Stop(&htim3); + HAL_TIM_Base_Stop(&htim4); + + /* 8. 进入 STOP 模式 (低功耗休眠) */ + HAL_SuspendTick(); + HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); + + /* 9. 唤醒后复位系统 (长按开机键触发唤醒后重新启动) */ + NVIC_SystemReset(); +} + /* USER CODE END 4 */ /** diff --git a/Core/Src/menu.c b/Core/Src/menu.c index 7078e3c..ad77289 100644 --- a/Core/Src/menu.c +++ b/Core/Src/menu.c @@ -195,9 +195,9 @@ void Menu_DrawHome(void) { g_page.item_count = 0; } - /* 长按返回 2s -> 休眠 */ - if (Input_IsKeyHeld(KEY_BACK)) { - /* TODO: 进入休眠模式 */ + /* 长按返回 2s -> 关机 (已连接接收机时不关机) */ + if (Input_IsKeyHeldFor(KEY_BACK, 2000) && !nrf_connected) { + System_Shutdown(); } } diff --git a/Core/Src/oled.c b/Core/Src/oled.c index a0261ff..2b28fbe 100644 --- a/Core/Src/oled.c +++ b/Core/Src/oled.c @@ -66,6 +66,12 @@ void OLED_Init(void) { OLED_Display(); } +void OLED_Off(void) { + OLED_Clear(); + OLED_Display(); + OLED_WriteCmd(0xAE); /* display off */ +} + void OLED_Clear(void) { memset(OLED_Buffer, 0x00, sizeof(OLED_Buffer)); } diff --git a/README.md b/README.md index bcaad1d..cb8cf02 100644 --- a/README.md +++ b/README.md @@ -82,12 +82,23 @@ make ## UI操作说明 +### 开机 +- 长按返回键约2秒开机 +- 显示开机画面: 左侧为开机Logo,右侧居中显示"Starting..." +- 开机画面持续2秒后进入主页 + ### 主页 - 显示各通道当前值 - 长按OK键进入高频头配置 - 长按BACK键切换值/回传显示 - 短按OK键进入主菜单 +### 关机 +- 在主页(未连接接收机时)长按返回键2秒关机 +- 关机流程: 关闭OLED → 关闭LED → 停止PWM → 关闭NRF24L01 → 关闭USB → 关闭外设时钟 → 进入STOP休眠模式 +- 唤醒后自动复位重启 +- **注意**: 当遥控器已连接到接收机时,长按返回键不会关机,防止飞行中误操作 + ### 主菜单 1. Model Select - 模型选择/新建/编辑/删除 2. RF Config - 高频头配置