diff --git a/App/main.c b/App/main.c index 2457293..f98e8a5 100644 --- a/App/main.c +++ b/App/main.c @@ -219,6 +219,8 @@ void main(void) inactivity_timer = 0; current_state = STATE_SLEEP; // 系统置为休眠状态 Enter_Low_Power_Sleep(); // 该函数是阻塞的,MCU 将在此挂起。唤醒后将自动从其后继续执行 + current_state = STATE_NORMAL; // 唤醒后重新置为正常待机状态 + AppManager_StartApp(APP_ID_CLOCK); // 重新开启时钟应用以刷新画面和背光 } } } diff --git a/App/system.c b/App/system.c index 16ca08e..3578669 100644 --- a/App/system.c +++ b/App/system.c @@ -271,7 +271,7 @@ void Power_Off(void) MOTOR = 0; // 关断屏幕背光与 RGB 灯光 - SGM_CTRL = 0; + SGM_CTRL = 1; // 高电平断电,关闭背光灭屏 RGB_Send(0, 0, 0, 0, 0, 0); // 拉低 PWR_HOLD 切断电源锁存使总电源关闭 @@ -288,15 +288,81 @@ void Power_Off(void) */ void Enter_Low_Power_Sleep(void) { - Uart_SendString("[SYS] Entering Sleep mode...\r\n"); - SGM_CTRL = 0; // 熄灭背光 + Uart_SendString("[SYS] Entering low power sleep...\r\n"); + + // 1. 关闭/熄灭 RGB 灯 RGB_Send(0, 0, 0, 0, 0, 0); - // 配置 PCON 挂起单片机 - PCON |= 0x02; // PD = 1 掉电停机模式 + // 2. 向 LCD 芯片写入 Display OFF 指令 (0x28) 关显示 + WriteComm(0x28); + Delay_ms(20); + + // 3. 向 LCD 芯片写入 Sleep In 指令 (0x10) 关内部电荷泵 + WriteComm(0x10); + Delay_ms(20); + + // 4. 关闭背光(高电平断电,关闭背光灭屏) + SGM_CTRL = 1; + + // 5. 屏幕接口防漏电处理 + LCD_CS = 1; + LCD_RST = 1; + LCD_DCX = 0; + LCD_SCL = 0; + LCD_SDI = 0; + + // 6. 射频设置为关闭接收模式(低功耗,SHUT=0, RF_SetMode(0)) + RF_SetMode(0); + + // 使能访问扩展特殊功能寄存器 + P_SW2 |= 0x80; + + // 7. 配置 Port0 中断唤醒源 (KEY_UP=P0.1, KEY_CONFIRM=P0.2, KEY_DOWN=P0.3) + P0IM1 |= 0x0E; + P0IM0 &= ~0x0E; // 下降沿触发 + P0INTF = 0x00; // 清除挂起的中断标志 + P0INTE |= 0x0E; // 开启 P0.1, P0.2, P0.3 中断允许 + P0WKUE |= 0x0E; // 使能 P0.1, P0.2, P0.3 掉电唤醒 + + // 8. 配置 Port2 中断唤醒源 (SOS=P2.6) + P2IM1 |= 0x40; + P2IM0 &= ~0x40; // 下降沿触发 + P2INTF = 0x00; // 清除挂起标志 + P2INTE |= 0x40; // 开启 P2.6 中断允许 + P2WKUE |= 0x40; // 使能 P2.6 掉电唤醒 + + // 9. 配置 Port3 中断唤醒源 (RF_RX_DATA=P3.6) + P3IM1 |= 0x40; + P3IM0 |= 0x40; // 双边沿触发 + P3INTF = 0x00; // 清除挂起标志 + P3INTE |= 0x40; // 开启 P3.6 中断允许 + P3WKUE |= 0x40; // 使能 P3.6 掉电唤醒 + + // 确保引脚上拉和输入使能,防止因浮空产生的功耗泄漏 + P2PU |= 0x40; + P2IE |= 0x40; + P3PU &= ~0x40; + P3IE |= 0x40; + + // 清零各个唤醒检测标志位 + P0INTF = 0x00; + P2INTF = 0x00; + P3INTF = 0x00; + + p0_wakeup_flag = 0; + p2_wakeup_flag = 0; + p3_wakeup_flag = 0; + rf_wakeup_flag = 0; + + // 10. 关闭系统滴答定时器 Timer1 中断,防止休眠时被定时器误唤醒 + ET1 = 0; + EA = 1; // 开启全局中断 + + // 配置 PCON 挂起单片机,切入停机 (Power Down) 模式 + PCON |= 0x02; // PD = 1 _nop_(); _nop_(); _nop_(); _nop_(); - // 被唤醒后继续执行 + // ====== 被外部中断唤醒后,在此处继续运行 ====== Wakeup_Restore(); } @@ -305,8 +371,52 @@ void Enter_Low_Power_Sleep(void) */ void Wakeup_Restore(void) { - SGM_CTRL = 1; // 恢复背光 - Uart_SendString("[SYS] System Woken Up!\r\n"); + EAXFR = 1; + // 1. 立即关闭所有掉电外部中断允许与唤醒允许,防止重入 + P0INTE = 0x00; + P2INTE = 0x00; + P3INTE = 0x00; + P0WKUE = 0x00; + P2WKUE = 0x00; + P3WKUE = 0x00; + P0INTF = 0x00; + P2INTF = 0x00; + P3INTF = 0x00; + + // 2. 清零掉电唤醒定时器 + WKTCH = 0x00; + WKTCL = 0x00; + + // 3. 开启全局中断并重启系统滴答定时器 + EA = 1; + ET1 = 1; + + // 4. 恢复射频芯片工作模式 + RF_SetMode(1); + + // 打印唤醒调试日志 + if ((p0_wakeup_flag & 0x0E) || (p2_wakeup_flag & 0x40)) { + Uart_SendString("[WR] Woken by KEY (P0="); + Uart_SendHex8(p0_wakeup_flag); + Uart_SendString(", P2="); + Uart_SendHex8(p2_wakeup_flag); + Uart_SendString(")\r\n"); + } else if ((p3_wakeup_flag & 0x40) || rf_wakeup_flag) { + rf_wakeup_flag = 1; + Uart_SendString("[WR] Woken by RF (P3.6)!\r\n"); + } else { + Uart_SendString("[WR] Woken by TIMER/Other\r\n"); + } + + // 5. 恢复屏幕供电与背光(低电平上电,恢复背光亮屏) + SGM_CTRL = 0; + + // 6. 延时 200ms 等待液晶稳压板上电稳定后,重新对 LCD 寄存器初始化 + Delay_ms(200); + LCD_Init(); + + // 7. 充零闲置计时器 + inactivity_timer = 0; } /**