Configure low-power sleep and wakeup sequences for RF alarm trigger without noise interruption
This commit is contained in:
@@ -205,7 +205,7 @@ void ClockApp_OnStart(void)
|
|||||||
{
|
{
|
||||||
time_edit_active = 0;
|
time_edit_active = 0;
|
||||||
current_state = STATE_NORMAL;
|
current_state = STATE_NORMAL;
|
||||||
RF_SetMode(1);
|
RF_SetMode(0);
|
||||||
UI_ShowClockPage(current_state, current_hour, current_min);
|
UI_ShowClockPage(current_state, current_hour, current_min);
|
||||||
|
|
||||||
// 启动时熄灭灯条
|
// 启动时熄灭灯条
|
||||||
@@ -377,7 +377,7 @@ void MenuApp_onClose(void)
|
|||||||
{
|
{
|
||||||
menu_level = 0;
|
menu_level = 0;
|
||||||
RGB_Send(0, 0, 0, 0, 0, 0);
|
RGB_Send(0, 0, 0, 0, 0, 0);
|
||||||
RF_SetMode(1);
|
RF_SetMode(0);
|
||||||
Uart_SendString("[MenuApp] Closed\r\n");
|
Uart_SendString("[MenuApp] Closed\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,7 +577,7 @@ void PairApp_onClose(void)
|
|||||||
{
|
{
|
||||||
RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯光
|
RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯光
|
||||||
MOTOR = 0;
|
MOTOR = 0;
|
||||||
RF_SetMode(1);
|
RF_SetMode(0);
|
||||||
Uart_SendString("[PairApp] Closed\r\n");
|
Uart_SendString("[PairApp] Closed\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,9 +194,15 @@ void main(void)
|
|||||||
// Port0 中断服务函数 (由 isr_jump.asm 从向量 37 @ 0x012BH 跳转至此)
|
// Port0 中断服务函数 (由 isr_jump.asm 从向量 37 @ 0x012BH 跳转至此)
|
||||||
void Port0_Isr(void) interrupt 13
|
void Port0_Isr(void) interrupt 13
|
||||||
{
|
{
|
||||||
|
EAXFR = 1;
|
||||||
|
P0INTF = 0x00; // 清除 P0 端口中断悬挂标志
|
||||||
|
P0INTE = 0x00; // 立即禁用,防止低电平保持期间反复触发
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port2 中断服务函数 (由 isr_jump.asm 从向量 39 @ 0x013BH 跳转至此)
|
// Port2 中断服务函数 (由 isr_jump.asm 从向量 39 @ 0x013BH 跳转至此)
|
||||||
void Port2_Isr(void) interrupt 15
|
void Port2_Isr(void) interrupt 15
|
||||||
{
|
{
|
||||||
|
EAXFR = 1;
|
||||||
|
P2INTF = 0x00; // 清除 P2 端口中断悬挂标志
|
||||||
|
P2INTE = 0x00; // 立即禁用,防止低电平保持期间反复触发
|
||||||
}
|
}
|
||||||
|
|||||||
214
App/system.c
214
App/system.c
@@ -3,8 +3,8 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "../Drivers/lcd.h"
|
#include "../Drivers/lcd.h"
|
||||||
#include "../Drivers/rf.h"
|
#include "../Drivers/rf.h"
|
||||||
#include "database.h"
|
|
||||||
#include "app_manager.h"
|
#include "app_manager.h"
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
void GPIO_Init(void)
|
void GPIO_Init(void)
|
||||||
{
|
{
|
||||||
@@ -222,8 +222,8 @@ void Enter_Low_Power_Sleep(void)
|
|||||||
LCD_SCL = 0;
|
LCD_SCL = 0;
|
||||||
LCD_SDI = 0;
|
LCD_SDI = 0;
|
||||||
|
|
||||||
// 6. 休眠状态下不能关闭接收芯片,保持 SHUT 为高电平 (1) 工作状态
|
// 6. 休眠状态下开启接收芯片并接通天线 (SHUT=0, RF_RX=1),此时屏幕关闭没有 SGM3833 噪底干扰
|
||||||
SHUT = 1;
|
RF_SetMode(1);
|
||||||
|
|
||||||
// 确保开启扩展寄存器访问 (EAXFR = 1),以便能正确配置端口唤醒使能扩展寄存器
|
// 确保开启扩展寄存器访问 (EAXFR = 1),以便能正确配置端口唤醒使能扩展寄存器
|
||||||
P_SW2 |= 0x80;
|
P_SW2 |= 0x80;
|
||||||
@@ -238,28 +238,25 @@ void Enter_Low_Power_Sleep(void)
|
|||||||
P2IM0 &= ~0x40;
|
P2IM0 &= ~0x40;
|
||||||
P2INTE |= 0x40;
|
P2INTE |= 0x40;
|
||||||
|
|
||||||
// 8b. 配置 P2.1 (RF_RX_DATA) 为 低电平触发 唤醒
|
|
||||||
P2IM1 |= 0x02;
|
|
||||||
P2IM0 &= ~0x02;
|
|
||||||
P2INTE |= 0x02;
|
|
||||||
|
|
||||||
// ===== 配置端口掉电唤醒使能寄存器 PxWKUE =====
|
// ===== 配置端口掉电唤醒使能寄存器 PxWKUE =====
|
||||||
P0WKUE |= 0x0E; // 使能 P0.1/P0.2/P0.3 掉电唤醒
|
P0WKUE |= 0x0E; // 使使能 P0.1/P0.2/P0.3 掉电唤醒
|
||||||
P2WKUE |= 0x42; // 使能 P2.6, P2.1 掉电唤醒
|
P2WKUE |= 0x40; // 使使能 P2.6 掉电唤醒
|
||||||
|
|
||||||
// 9. 不允许外部中断 2 (RF_RX_DATA) 沿触发唤醒源
|
// 9. 开启外部中断 2 (RF_RX_DATA) 沿触发唤醒源
|
||||||
EX2 = 0;
|
EX2 = 1;
|
||||||
|
|
||||||
// 10. 清除端口中断的悬挂/标志位,防误触
|
// 10. 清除端口中断的悬挂/标志位,防误触
|
||||||
P0INTF = 0x00;
|
P0INTF = 0x00;
|
||||||
P2INTF = 0x00;
|
P2INTF = 0x00;
|
||||||
|
|
||||||
// 11. 关闭 Timer1 中断,将 EA 置 0,通过硬件唤醒直接向下执行
|
// 11. 关闭 Timer1 中断,保持 EA=1 让端口/射频中断能唤醒
|
||||||
ET1 = 0;
|
ET1 = 0;
|
||||||
EA = 0;
|
EA = 1;
|
||||||
|
|
||||||
// 12. 写入 PCON 掉电模式位,使 MCU 进入深度 Power-Down 挂起状态
|
// 12. 写入 PCON 掉电模式位,使 MCU 进入深度 Power-Down 挂起状态
|
||||||
while (1) {
|
// 如果由于杂波伪唤醒,我们在循环中检测并重新进入休眠
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
Uart_SendString("[SYS] Entering Power-Down mode...\r\n");
|
Uart_SendString("[SYS] Entering Power-Down mode...\r\n");
|
||||||
PCON |= 0x02; // PD = 1
|
PCON |= 0x02; // PD = 1
|
||||||
_nop_();
|
_nop_();
|
||||||
@@ -267,25 +264,42 @@ void Enter_Low_Power_Sleep(void)
|
|||||||
_nop_();
|
_nop_();
|
||||||
_nop_();
|
_nop_();
|
||||||
|
|
||||||
// 13. 唤醒后直接从这里继续执行,如果是真唤醒,则打破挂起循环
|
// 13. 唤醒并执行完 ISR 后,CPU 从这里继续执行
|
||||||
if (Wakeup_Restore() == 1) {
|
if (Wakeup_Restore())
|
||||||
break;
|
{
|
||||||
|
break; // 真实唤醒(按键或合法射频报警),退出休眠循环
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 14. 伪唤醒,重新配置唤醒源寄存器,准备下一次 Power-Down
|
||||||
|
EAXFR = 1;
|
||||||
|
RF_SetMode(1); // 重新开启接收芯片并接通天线
|
||||||
|
EX2 = 1; // 重新使能外部中断 2
|
||||||
|
P0INTF = 0x00;
|
||||||
|
P2INTF = 0x00;
|
||||||
|
P0INTE = 0x0E;
|
||||||
|
P2INTE = 0x40;
|
||||||
|
P0WKUE = 0x0E;
|
||||||
|
P2WKUE = 0x40;
|
||||||
|
ET1 = 0; // 关闭定时器 1
|
||||||
|
EA = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Wakeup_Restore(void)
|
bit Wakeup_Restore(void)
|
||||||
{
|
{
|
||||||
u8 actual_p0;
|
u8 p0_flag;
|
||||||
u8 actual_p2;
|
u8 p2_flag;
|
||||||
u8 decoded = 0;
|
u16 rf_check_ms = 0;
|
||||||
|
bit rf_valid = 0;
|
||||||
|
u32 rx_addr;
|
||||||
|
u8 rx_data;
|
||||||
|
|
||||||
// 确保 EAXFR=1 才能访问扩展 SFR (P0INTF/P2INTF/P0INTE/P2INTE)
|
// 确保 EAXFR=1 才能访问扩展 SFR (P0INTF/P2INTF/P0INTE/P2INTE)
|
||||||
EAXFR = 1;
|
EAXFR = 1;
|
||||||
|
|
||||||
// 直接读取当前的真实悬挂标志
|
// [诊断] 在清除标志位之前先读取,判断唤醒来源
|
||||||
actual_p0 = P0INTF;
|
p0_flag = P0INTF;
|
||||||
actual_p2 = P2INTF;
|
p2_flag = P2INTF;
|
||||||
|
|
||||||
// 1. 立即禁用端口中断和唤醒,防止继续触发
|
// 1. 立即禁用端口中断和唤醒,防止继续触发
|
||||||
P0INTE = 0x00;
|
P0INTE = 0x00;
|
||||||
@@ -294,90 +308,118 @@ u8 Wakeup_Restore(void)
|
|||||||
P2WKUE = 0x00; // 清除 P2 唤醒允许
|
P2WKUE = 0x00; // 清除 P2 唤醒允许
|
||||||
P0INTF = 0x00;
|
P0INTF = 0x00;
|
||||||
P2INTF = 0x00;
|
P2INTF = 0x00;
|
||||||
EX2 = 0;
|
EX2 = 0; // 唤醒后禁用射频中断,运行模式下不受噪底杂波干扰
|
||||||
|
|
||||||
// 1b. 关闭掉电唤醒定时器
|
// 1b. 关闭掉电唤醒定时器
|
||||||
WKTCH = 0x00;
|
WKTCH = 0x00;
|
||||||
WKTCL = 0x00;
|
WKTCL = 0x00;
|
||||||
|
|
||||||
// [诊断] 打印唤醒来源
|
// 2. 开启全局中断,但暂时保持 Timer1 关闭以防中断影响射频比值软件解码
|
||||||
if (actual_p0 & 0x0E) {
|
EA = 1;
|
||||||
|
ET1 = 0;
|
||||||
|
|
||||||
|
// 3. 判断是否为按键唤醒
|
||||||
|
if ((p0_flag & 0x0E) || (p2_flag & 0x40))
|
||||||
|
{
|
||||||
|
if (p0_flag & 0x0E) {
|
||||||
Uart_SendString("[WR] Woken by KEY P0 (P0INTF=0x");
|
Uart_SendString("[WR] Woken by KEY P0 (P0INTF=0x");
|
||||||
Uart_SendHex8(actual_p0);
|
Uart_SendHex8(p0_flag);
|
||||||
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");
|
Uart_SendString(")\r\n");
|
||||||
} else {
|
} else {
|
||||||
Uart_SendString("[WR] Woken by TIMER/OTHER\r\n");
|
Uart_SendString("[WR] Woken by KEY P2 (P2INTF=0x");
|
||||||
|
Uart_SendHex8(p2_flag);
|
||||||
|
Uart_SendString(")\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 处理射频唤醒:判断是否真的有传感器报警
|
// 运行模式屏幕开启有噪底干扰,关闭射频接收,防止无信号时在后台乱输出电平
|
||||||
if ((actual_p2 & 0x02) && !(actual_p0 & 0x0E) && !(actual_p2 & 0x40)) {
|
RF_SetMode(0);
|
||||||
u8 i;
|
|
||||||
u32 rx_addr;
|
|
||||||
u8 rx_data;
|
|
||||||
|
|
||||||
// 全速尝试解调,由于 EA 此时仍为 0,不受滴答定时器干扰
|
// 启动 SGM3833 PMIC 并发送脉冲使能升压
|
||||||
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_CTRL = 1;
|
||||||
SGM_SendPulse(27);
|
SGM_SendPulse(27);
|
||||||
|
|
||||||
// 等待负压电轨充分稳定
|
// 等待负压电轨充分稳定
|
||||||
Delay_ms(200);
|
Delay_ms(200);
|
||||||
|
|
||||||
// 重做屏控制器 RM69310 寄存器组的初始化
|
// 重做屏控制器 RM69310 寄存器组 of 初始化
|
||||||
LCD_Init();
|
LCD_Init();
|
||||||
|
|
||||||
// 重置闲置倒计时
|
// 重新开启 Timer1
|
||||||
|
ET1 = 1;
|
||||||
inactivity_timer = 0;
|
inactivity_timer = 0;
|
||||||
|
|
||||||
// 根据唤醒源决定显示什么
|
// 绘制时钟主界面
|
||||||
if (decoded) {
|
|
||||||
// 如果是有效的射频入侵触发,强制切到 Alarm 状态并启动应用
|
|
||||||
AppManager_StartApp(APP_ID_ALARM);
|
|
||||||
} else {
|
|
||||||
// 如果是按键触发唤醒,显示主时间界面
|
|
||||||
current_state = STATE_NORMAL;
|
current_state = STATE_NORMAL;
|
||||||
UI_ShowClockPage(current_state, current_hour, current_min);
|
UI_ShowClockPage(current_state, current_hour, current_min);
|
||||||
|
Uart_SendString("[SYS] Wakeup restored by Key!\r\n");
|
||||||
|
return 1; // 真实唤醒
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 射频外部中断或者 WKT 唤醒,保持屏幕 SGM_CTRL=0 关闭状态,避免升压干扰射频
|
||||||
|
Uart_SendString("[WR] Woken by RF/WKT, decoding...\r\n");
|
||||||
|
SGM_CTRL = 0;
|
||||||
|
|
||||||
|
// 尝试解码 150ms 射频包
|
||||||
|
for (rf_check_ms = 0; rf_check_ms < 150; rf_check_ms++)
|
||||||
|
{
|
||||||
|
if (EV1527_Decode(&rx_addr, &rx_data))
|
||||||
|
{
|
||||||
|
u8 slot;
|
||||||
|
if (Check_Sensor_ID(rx_addr, &slot))
|
||||||
|
{
|
||||||
|
// 找到了匹配的已配对传感器
|
||||||
|
if (sensor_list[slot].zone == 0 || current_state == STATE_ARMED)
|
||||||
|
{
|
||||||
|
rf_valid = 1;
|
||||||
|
captured_addr = rx_addr;
|
||||||
|
alarm_sensor_slot = slot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Delay_ms(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Uart_SendString("[SYS] Wakeup restored!\r\n");
|
// 采集完/超时后,立即关闭射频接收芯片,杜绝乱输出的噪底电平
|
||||||
return 1; // 返回 1 表示真唤醒
|
RF_SetMode(0);
|
||||||
|
|
||||||
|
if (rf_valid)
|
||||||
|
{
|
||||||
|
// 真实报警信号唤醒:开启屏幕,显示报警画面
|
||||||
|
Uart_SendString("[WR] Valid Alarm RF Decoded! Address=0x");
|
||||||
|
Uart_SendHex32(captured_addr);
|
||||||
|
Uart_SendString("\r\n");
|
||||||
|
|
||||||
|
// 启动 SGM3833 并使能升压
|
||||||
|
SGM_CTRL = 1;
|
||||||
|
SGM_SendPulse(27);
|
||||||
|
Delay_ms(200);
|
||||||
|
LCD_Init();
|
||||||
|
|
||||||
|
// 重新开启 Timer1
|
||||||
|
ET1 = 1;
|
||||||
|
inactivity_timer = 0;
|
||||||
|
|
||||||
|
// 进入报警 App
|
||||||
|
AppManager_StartApp(APP_ID_ALARM);
|
||||||
|
return 1; // 真实唤醒
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 伪唤醒(杂波引起的误触发,或未注册传感器):不开启屏幕,返回 0 以便主循环重新进入休眠
|
||||||
|
Uart_SendString("[WR] RF Noise or Unregistered signal, back to sleep...\r\n");
|
||||||
|
|
||||||
|
// 重新开启 Timer1
|
||||||
|
ET1 = 1;
|
||||||
|
return 0; // 假唤醒,重新进入 Power-Down
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STC32G INT2 外部中断服务子程序 (向量 10)
|
||||||
|
// 用于从 Power-Down 模式中由射频数据脚下降沿唤醒 CPU
|
||||||
|
void INT2_Isr(void) interrupt 10
|
||||||
|
{
|
||||||
|
EX2 = 0; // 唤醒后立即关闭外部中断,避免噪底电平在唤醒后反复触发中断
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ void FormatHex(u32 val, char *buf);
|
|||||||
|
|
||||||
// 电源管理与休眠唤醒
|
// 电源管理与休眠唤醒
|
||||||
void Enter_Low_Power_Sleep(void);
|
void Enter_Low_Power_Sleep(void);
|
||||||
u8 Wakeup_Restore(void);
|
bit Wakeup_Restore(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user