#include "system.h" #include "rgb.h" #include "ui.h" #include "../Drivers/lcd.h" #include "../Drivers/rf.h" #include "database.h" #include "app_manager.h" void GPIO_Init(void) { IE = 0x00; IE2 = 0x00; TCON = 0x00; TMOD &= 0xF0; TR0 = 0; ET0 = 0; AUXR = 0x00; INTCLKO = 0x00; P_SW1 = 0x00; P_SW2 = 0x80; // 开启 EAXFR=1,允许访问 P0PU/P2PU/P0INTE/P2INTE 等扩展 SFR 寄存器 P_SW3 = 0x00; // 配置 P0.0 (BAT_ADC) 为高阻输入模式 P0M1 |= (1 << 0); P0M0 &= ~(1 << 0); // 配置 P0.1 (KEY_UP), P0.2 (KEY_CONFIRM), P0.3 (KEY_DOWN) 为准双向口模式并置 1 P0M1 &= ~((1 << 1) | (1 << 2) | (1 << 3)); P0M0 &= ~((1 << 1) | (1 << 2) | (1 << 3)); KEY_UP = 1; KEY_CONFIRM = 1; KEY_DOWN = 1; // 配置 P2.3 (RGB_DIN) 为推挽输出模式 P2M1 &= ~(1 << 3); P2M0 |= (1 << 3); RGB_DIN = 0; // 配置 P2.5 (MOTOR) 为推挽输出模式 P2M1 &= ~(1 << 5); P2M0 |= (1 << 5); MOTOR = 0; // 配置 P2.6 (KEY_SOS) 为准双向口模式并置 1 P2M1 &= ~(1 << 6); P2M0 &= ~(1 << 6); KEY_SOS = 1; // 配置 P2.2 (SHUT) 为推挽输出模式 P2M1 &= ~(1 << 2); P2M0 |= (1 << 2); SHUT = 1; // 默认拉高开启射频接收芯片工作 // 开启按键引脚 P0.1, P0.2, P0.3 和 P2.6 的内部上拉电阻,避免引脚抖动误唤醒 P0PU |= 0x0E; P2PU |= 0x40; // 配置 P2.7 (DET) 为高阻输入模式 P2M1 |= (1 << 7); P2M0 &= ~(1 << 7); // 配置 P3.0 (TXD), P3.1 (RXD) 和 P3.4 (SGM_CTRL) P3M1 &= ~((1 << 0) | (1 << 1) | (1 << 4)); P3M0 &= ~(1 << 0); P3M0 |= ((1 << 1) | (1 << 4)); } void Delay_ms(u16 ms) { u16 i, j; for (i = 0; i < ms; i++) for (j = 12000; j > 0; j--); } void Delay10us(void) { unsigned char data i; _nop_(); i = 30; while (--i); } u16 GetTimer0_Safe(void) { u8 h1, l, h2; do { h1 = TH0; l = TL0; h2 = TH0; } while (h1 != h2); return ((u16)h1 << 8) | l; } void Delay_us(u16 us) { u16 ticks = (u16)((u32)us * (MAIN_Fosc / 1000000UL) / 12UL); TL0 = 0; TH0 = 0; TR0 = 1; while (GetTimer0_Safe() < ticks); TR0 = 0; } void Uart1_Init(void) { u16 reload = (u16)(65536UL - (MAIN_Fosc / 4 / 115200UL)); SCON = 0x50; AUXR |= 0x01; AUXR |= 0x04; T2L = (u8)reload; T2H = (u8)(reload >> 8); AUXR |= 0x10; TI = 0; } void Uart_SendByte(u8 dat) { REN = 0; SBUF = dat; while (!TI); TI = 0; RI = 0; REN = 1; } void Uart_SendString(char *s) { REN = 0; while (*s) { SBUF = *s++; while (!TI); TI = 0; } RI = 0; REN = 1; } char Uart_RxChar(void) { if (RI) { char c = SBUF; RI = 0; return c; } return 0; } void Uart_SendHex4(u8 val) { val &= 0x0F; if (val < 10) Uart_SendByte((u8)('0' + val)); else Uart_SendByte((u8)('A' + (val - 10))); } void Uart_SendHex8(u8 val) { Uart_SendHex4(val >> 4); Uart_SendHex4(val); } void Uart_SendHex20(u32 val) { Uart_SendHex4((u8)(val >> 16)); Uart_SendHex8((u8)(val >> 8)); Uart_SendHex8((u8)val); } void Uart_SendHex32(u32 val) { Uart_SendHex8((u8)(val >> 24)); Uart_SendHex8((u8)(val >> 16)); Uart_SendHex8((u8)(val >> 8)); Uart_SendHex8((u8)val); } void Uart_SendHex16(u16 val) { Uart_SendHex8((u8)(val >> 8)); Uart_SendHex8((u8)val); } void FormatHex(u32 val, char *buf) { u8 i; buf[0] = 'A'; buf[1] = 'D'; buf[2] = 'D'; buf[3] = 'R'; buf[4] = ':'; buf[5] = ' '; buf[6] = '0'; buf[7] = 'x'; for (i = 0; i < 5; i++) { u8 nibble = (val >> (4 * (4 - i))) & 0x0F; if (nibble < 10) buf[8 + i] = '0' + nibble; else buf[8 + i] = 'A' + (nibble - 10); } buf[13] = '\0'; } void Enter_Low_Power_Sleep(void) { // 串口打印进入休眠提示 Uart_SendString("[SYS] Entering low power sleep...\r\n"); // 1. 熄灭 FCOB 双幻彩灯条 RGB_Send(0, 0, 0, 0, 0, 0); // 2. 向屏幕发送 Display OFF (0x28) 彻底关闭像素发光显示 WriteComm(0x28); Delay_ms(20); // 3. AMOLED 屏控制器写入 Sleep In (0x10) 睡眠指令 WriteComm(0x10); Delay_ms(20); // 4. 拉低 SGM_CTRL 彻底断开 SGM3833 负压升压芯片的供电 SGM_CTRL = 0; // 5. 将 AMOLED 控制总线所有 IO 拉低,以防由于 IO 寄生二极管对屏幕倒灌电导致常亮 LCD_CS = 0; LCD_RST = 0; LCD_DCX = 0; LCD_SCL = 0; LCD_SDI = 0; // 6. 休眠状态下不能关闭接收芯片,保持 SHUT 为高电平 (1) 工作状态 SHUT = 1; // 确保开启扩展寄存器访问 (EAXFR = 1),以便能正确配置端口唤醒使能扩展寄存器 P_SW2 |= 0x80; // 7. 配置 P0.1, P0.2, P0.3 为 低电平触发 唤醒 P0IM1 |= 0x0E; P0IM0 &= ~0x0E; P0INTE |= 0x0E; // 8. 配置 P2.6 (KEY_SOS) 为 低电平触发 唤醒 P2IM1 |= 0x40; P2IM0 &= ~0x40; P2INTE |= 0x40; // 8b. 配置 P2.1 (RF_RX_DATA) 为 低电平触发 唤醒 P2IM1 |= 0x02; P2IM0 &= ~0x02; P2INTE |= 0x02; // ===== 配置端口掉电唤醒使能寄存器 PxWKUE ===== P0WKUE |= 0x0E; // 使能 P0.1/P0.2/P0.3 掉电唤醒 P2WKUE |= 0x42; // 使能 P2.6, P2.1 掉电唤醒 // 9. 不允许外部中断 2 (RF_RX_DATA) 沿触发唤醒源 EX2 = 0; // 10. 清除端口中断的悬挂/标志位,防误触 P0INTF = 0x00; P2INTF = 0x00; // 11. 关闭 Timer1 中断,将 EA 置 0,通过硬件唤醒直接向下执行 ET1 = 0; EA = 0; // 12. 写入 PCON 掉电模式位,使 MCU 进入深度 Power-Down 挂起状态 while (1) { Uart_SendString("[SYS] Entering Power-Down mode...\r\n"); PCON |= 0x02; // PD = 1 _nop_(); _nop_(); _nop_(); _nop_(); // 13. 唤醒后直接从这里继续执行,如果是真唤醒,则打破挂起循环 if (Wakeup_Restore() == 1) { break; } } } u8 Wakeup_Restore(void) { u8 actual_p0; u8 actual_p2; u8 decoded = 0; // 确保 EAXFR=1 才能访问扩展 SFR (P0INTF/P2INTF/P0INTE/P2INTE) EAXFR = 1; // 直接读取当前的真实悬挂标志 actual_p0 = P0INTF; actual_p2 = P2INTF; // 1. 立即禁用端口中断和唤醒,防止继续触发 P0INTE = 0x00; P2INTE = 0x00; P0WKUE = 0x00; // 清除 P0 唤醒允许 P2WKUE = 0x00; // 清除 P2 唤醒允许 P0INTF = 0x00; P2INTF = 0x00; EX2 = 0; // 1b. 关闭掉电唤醒定时器 WKTCH = 0x00; WKTCL = 0x00; // [诊断] 打印唤醒来源 if (actual_p0 & 0x0E) { Uart_SendString("[WR] Woken by KEY P0 (P0INTF=0x"); Uart_SendHex8(actual_p0); Uart_SendString(")\r\n"); } else if (actual_p2 & 0x40) { Uart_SendString("[WR] Woken by KEY P2 (P2INTF=0x"); Uart_SendHex8(actual_p2); Uart_SendString(")\r\n"); } else if (actual_p2 & 0x02) { Uart_SendString("[WR] Woken by RF P2.1 (P2INTF=0x"); Uart_SendHex8(actual_p2); Uart_SendString(")\r\n"); } else { Uart_SendString("[WR] Woken by TIMER/OTHER\r\n"); } // 3. 处理射频唤醒:判断是否真的有传感器报警 if ((actual_p2 & 0x02) && !(actual_p0 & 0x0E) && !(actual_p2 & 0x40)) { u8 i; u32 rx_addr; u8 rx_data; // 全速尝试解调,由于 EA 此时仍为 0,不受滴答定时器干扰 for (i = 0; i < 6; i++) { if (EV1527_Decode(&rx_addr, &rx_data)) { u8 slot; if (Check_Sensor_ID(rx_addr, &slot)) { u8 sensor_type = sensor_list[slot].type; if (sensor_type < 5) { // 只有在防区开启 (zone == 0) 或处于 STATE_ARMED (警戒) 状态下才触发 if (sensor_list[slot].zone == 0 || current_state == STATE_ARMED) { captured_addr = rx_addr; alarm_sensor_slot = slot; decoded = 1; break; } } } } Delay_ms(20); } if (!decoded) { // 只是噪声或未配对的遥控器,无视,不亮屏直接返回 0 让主休眠循环继续挂起(保持 EA = 0) Uart_SendString("[WR] RF false alarm/noise. Re-sleeping.\r\n"); return 0; } Uart_SendString("[WR] RF Alarm Decoded successfully!\r\n"); } // 4. 到这里说明是真唤醒(或者是按键,或者是有效的射频警报解码成功) // 开启射频接收芯片工作 SHUT = 1; // 拉高 SGM_CTRL 并发送脉冲使能 SGM3833 升压 SGM_CTRL = 1; SGM_SendPulse(27); // 等待负压电轨充分稳定 Delay_ms(200); // 重做屏控制器 RM69310 寄存器组的初始化 LCD_Init(); // 重置闲置倒计时 inactivity_timer = 0; // 根据唤醒源决定显示什么 if (decoded) { // 如果是有效的射频入侵触发,强制切到 Alarm 状态并启动应用 AppManager_StartApp(APP_ID_ALARM); } else { // 如果是按键触发唤醒,显示主时间界面 current_state = STATE_NORMAL; UI_ShowClockPage(current_state, current_hour, current_min); } Uart_SendString("[SYS] Wakeup restored!\r\n"); return 1; // 返回 1 表示真唤醒 }