#include "config.h" #include "rgb.h" #include "event.h" #include "app_manager.h" #include "database.h" #include "ui.h" #include "system.h" #include "clock.h" #include "xtell.h" #include "../Drivers/rf.h" #include "../Drivers/lcd.h" // 声明外部射频模拟变量 extern volatile u32 mock_rx_addr; extern volatile u8 mock_rx_data; extern volatile bit mock_rf_ready; /* ========================================================================= * 系统全局变量定义 * ========================================================================= */ SystemState current_state = STATE_NORMAL; // 系统整体的当前运行状态,默认为正常时钟待机页 u8 menu_select = 0; // 主菜单当前选中的行高亮索引 (0~2) u32 captured_addr = 0; // 配对或报警时,捕获到的传感器 24 位 EV1527 射频物理地址 u8 captured_type = 0; // 正在对码或触发警报的传感器设备类型 (0:门磁, 1:PIR...) u8 alarm_sensor_slot = 0; // 触发警报的传感器在 sensor_list 数组中的索引槽位号 // 传感器存储列表数据库,位于单片机外部 XDATA 存储空间,总共 16 个槽位 Sensor_Slot xdata sensor_list[16]; // 全局滴答与定时中断计数变量,位于 volatile 防止被编译器优化 volatile u16 ms_tick = 0; // 定时中断 1ms 基准滴答累加器 volatile u16 inactivity_timer = 0; // 用户闲置计时器,用于无操作判定(单位: 10ms) volatile u32 pair_timeout_ms = 0; // 传感器配对对码超时毫秒计时器 (上限 30000ms 即 30s) volatile u16 alarm_timer_ms = 0; // 入侵报警马达震动时序计数器 volatile u16 motor_timer_ms = 0; // 独立马达震动时长计数器 volatile bit alarm_flash_flag = 0; // 报警时红框周期性闪烁亮灭标志位 // 物理按键扫描与消抖长按计数器 (10ms 扫描一次) volatile u16 key_scan_timer = 0; // 10ms 扫描周期分频器 volatile u16 key_up_hold = 0; // ▲ (KEY_UP) 按下时长累加 volatile u16 key_down_hold = 0; // ▼ (KEY_DOWN) 按下时长累加 volatile u16 key_confirm_hold = 0; // ■ (KEY_CONFIRM) 按下时长累加 volatile u16 key_sos_hold = 0; // SOS 按下时长累加 volatile u16 comb_hold = 0; // ▲ + ▼ 组合键按下时长累加 /* ========================================================================= * 串口调试指令解析与事件派发封装 * ========================================================================= */ /** * @brief 解析通过串口 1 发送来的键盘及测试模拟指令 */ void Debug_ProcessCommand(char cmd) { SystemEvent debug_evt; inactivity_timer = 0; // 收到指令,立即重置用户的无操作闲置计时器 debug_evt.extra_data = 0; debug_evt.extra_size = 0; if (cmd == 'u') { debug_evt.key_event = KEY_EVENT_UP_CLICK; EventQueue_Push(debug_evt); // 压入队尾 XTELL_LOG("[UART] KEY_UP Clicked\r\n"); } else if (cmd == 'U') { debug_evt.key_event = KEY_EVENT_UP_LONG; EventQueue_Push(debug_evt); XTELL_LOG("[UART] KEY_UP Long Pressed\r\n"); } else if (cmd == 'd') { debug_evt.key_event = KEY_EVENT_DOWN_CLICK; EventQueue_Push(debug_evt); XTELL_LOG("[UART] KEY_DOWN Clicked\r\n"); } else if (cmd == 'D') { debug_evt.key_event = KEY_EVENT_DOWN_LONG; EventQueue_Push(debug_evt); XTELL_LOG("[UART] KEY_DOWN Long Pressed\r\n"); } else if (cmd == 's') { debug_evt.key_event = KEY_EVENT_SOS_CLICK; EventQueue_InsertFront(debug_evt); // 紧急事件插入队首 XTELL_LOG("[UART] KEY_SOS Clicked\r\n"); } else if (cmd == 'S') { debug_evt.key_event = KEY_EVENT_SOS_LONG; EventQueue_InsertFront(debug_evt); XTELL_LOG("[UART] KEY_SOS Long Pressed\r\n"); } else if (cmd == 'c' || cmd == 'C') { debug_evt.key_event = KEY_EVENT_UP_DOWN_COMB; EventQueue_Push(debug_evt); XTELL_LOG("[UART] KEY_UP+DOWN Combined\r\n"); } else if (cmd == 'a' || cmd == 'A') { u32 mock_addr = 0x123456; // 设定模拟的报警射频源地址 u8 mock_slot; // 如果本地数据库中没有匹配该射频,则强制登记进 1 号防区 if (!Check_Sensor_ID(mock_addr, &mock_slot)) { Add_Sensor_With_Zone(mock_addr, 0, 1); } mock_rx_addr = mock_addr; mock_rx_data = 0x01; mock_rf_ready = 1; // 触发射频模拟 XTELL_LOG("[UART] Mock RF Alarm Triggered\r\n"); } else if (cmd == 'p' || cmd == 'P') { mock_rx_addr = 0x789ABC; mock_rx_data = 0x01; mock_rf_ready = 1; // 触发射频模拟 XTELL_LOG("[UART] Mock RF Pair Triggered\r\n"); } else if (cmd == '1') { // 模拟切换至 正常撤防 (NORMAL) 状态并刷新时钟 if (AppManager_GetActiveAppID() == APP_ID_CLOCK) { current_state = STATE_NORMAL; UI_ShowClockPage(current_state, current_hour, current_min); } XTELL_LOG("[UART] State: NORMAL\r\n"); } else if (cmd == '2') { // 模拟切换至 已布防 (ARMED) 状态,普通门磁可触发警报 if (AppManager_GetActiveAppID() == APP_ID_CLOCK) { current_state = STATE_ARMED; UI_ShowClockPage(current_state, current_hour, current_min); } XTELL_LOG("[UART] State: ARMED\r\n"); } else if (cmd == '3') { // 模拟切换至 已撤防 (DISARMED) 状态,忽略普通报警 if (AppManager_GetActiveAppID() == APP_ID_CLOCK) { current_state = STATE_DISARMED; UI_ShowClockPage(current_state, current_hour, current_min); } XTELL_LOG("[UART] State: DISARMED\r\n"); } else if (cmd == 'z' || cmd == 'Z') { inactivity_timer = 6000; // 模拟闲置 60 秒超时,强制触发主循环深度休眠 XTELL_LOG("[UART] Force Entering Sleep mode!\r\n"); } else if (cmd == 't' || cmd == 'T') { Loopback_Test(); // 调用回环测试验证屏幕 RF_Test_Pin(); // 无线射频测试 } } /* ========================================================================= * 主函数 (入口) * ========================================================================= */ void main(void) { char cmd; // ====== STC32G 特殊功能寄存器内核基础初始化 ====== WTST = 0; // 设置程序 Flash 访问等待时间为 0 (最高速运行) EAXFR = 1; // 允许访问扩展特殊功能寄存器 (XSFR) CKCON = 0; // 外部总线时钟设定为最快 WDT_CONTR = 0x00; // 关闭看门狗定时器 // ====== 硬件各模块基础初始化 ====== GPIO_Init(); // 配置各个引脚的推挽输出/准双向模式及内部上拉 RF_Init(); // 初始化射频芯片各引脚控制 Delay_ms(500); // 软启动延时,等待供电电容稳定 SGM_SendPulse(27); // 通过脉冲给 SGM3833 供电芯片发指令,稳压开启 LCD 正负电压轨 Delay_ms(50); // 等待电压充盈稳定,避开浪涌 LCD_Init(); // 初始化 Truly AMOLED 屏幕控制寄存器序列 Uart1_Init(); // 初始化串口 1 波特率 115200 供调试日志 XTELL_LOG("Wristband System Initialized!\r\n"); Load_Database(); // 从 IAP Flash 第 254 扇区读取所有已绑定的传感器数据至 RAM /* 步骤 1: 初始化事件环形缓冲区队列 */ EventQueue_Init(); /* 步骤 2: 初始化应用管理器 */ AppManager_Init(); /* 步骤 3: 动态挂载待机时钟应用到前台,并挂载后台射频监控应用 */ AppManager_SwitchToForeground(&clock_app); AppManager_AttachToBackground(&rf_monitor_app); /* 启动 1ms 系统基准定时器 Timer1 */ Timer1_Init(); XTELL_LOG("[SYS] Event-driven framework ready\r\n"); // ====== 主循环 ====== while (1) { /* 1. 串口非阻塞指令捕获 -> 装配为事件方式入队 */ cmd = Uart_RxChar(); if (cmd != '\0') { Debug_ProcessCommand(cmd); } /* 2. 事件分发总线:循环轮询并处理队列中的所有有效事件 */ while (!EventQueue_IsEmpty()) { Event_Dispatcher_Loop(); } /* 3. 应用调度中心:运行前后台所有已挂载激活的应用 */ AppManager_RunActiveApp(); /* 4. 自动休眠判定:常态无操作闲置达到 60 秒 (6000 * 10ms = 60s) 时,切入低功耗停机休眠 */ if (inactivity_timer >= 6000) { inactivity_timer = 0; current_state = STATE_SLEEP; // 系统置为休眠状态 Enter_Low_Power_Sleep(); // 挂起 MCU } } } // 唤醒源事件标志,由对应的外部中断 ISR 写入 volatile u8 p0_wakeup_flag = 0; // P0 端口按键唤醒标志 volatile u8 p2_wakeup_flag = 0; // P2 端口按键唤醒标志 volatile u8 rf_wakeup_flag = 0; // P2.1 射频中断唤醒标志 /* ========================================================================= * STC32G 端口掉电外部中断唤醒中断服务程序 (ISR) * ========================================================================= */ /** * @brief Port0 端口掉电中断服务函数 (由 isr_jump.asm 引导定位至此) * @details 负责处理 P0.1, P0.2, P0.3 按键在休眠模式下的物理触发,并立刻禁用中断防止反复执行。 */ void Port0_Isr(void) interrupt 13 { EAXFR = 1; // 使能访问扩展寄存区 p0_wakeup_flag = P0INTF | 0x01;// 读取并备份 P0 中断标志寄存器值 (0x01作安全掩码) P0INTF = 0x00; // 清除 P0 端口中断悬挂标志位 P0INTE = 0x00; // 【关键保护】:立即关闭 P0 中断允许,防止按键处于低电平期间反复触发 ISR 导致堆栈溢出 } /** * @brief Port2 端口掉电中断服务函数 (由 isr_jump.asm 引导定位至此) * @details 负责处理 P2.6 (SOS按键) 与 P2.1 (射频数据脚) 在休眠模式下的物理跳变唤醒。 */ void Port2_Isr(void) interrupt 15 { EAXFR = 1; // 使能扩展寄存区 p2_wakeup_flag = P2INTF | 0x01;// 读取并备份 P2 中断标志寄存区的值 P2INTF = 0x00; // 清除 P2 端口中断悬挂标志位 P2INTE = 0x00; // 立即关闭 P2 中断通道,防止低电平期间反复重入 }