#include "stc32g.h" #include "intrins.h" #include "config.h" #include "../Drivers/lcd.h" #include "../Drivers/rf.h" /* ========================================================================= * 硬件引脚定义 * ========================================================================= */ sbit MOTOR = P2^5; // 振动马达控制端 (推挽输出,与 SPI SCLK 物理共享引脚) sbit KEY_UP = P0^1; // 侧边按键 ▲ (高阻输入 + 上拉) sbit KEY_CONFIRM = P0^2; // 侧边按键 ■ (高阻输入 + 上拉) sbit KEY_DOWN = P0^3; // 侧边按键 ▼ (高阻输入 + 上拉) sbit KEY_SOS = P2^6; // 物理 SOS 求救按键 (高阻输入 + 上拉) sbit RGB_DIN = P2^3; // FCOB 幻彩灯条 DIN 控制线 sbit SHUT = P2^2; // LR690L 射频芯片休眠/工作控制引脚 (低使能开启工作) sbit SGM_CTRL = P3^4; // SGM3833 PMIC 屏幕负压供电使能脚 sbit LCD_RST = P1^0; // Truly AMOLED 屏幕复位脚 (RESET) sbit LCD_DCX = P1^1; // Truly AMOLED 屏幕数据/指令选择脚 (D/C) sbit LCD_SDI = P1^4; // Truly AMOLED 屏幕 SPI 数据脚 (MOSI) sbit LCD_SCL = P1^5; // Truly AMOLED 屏幕 SPI 时钟脚 (SCLK) sbit LCD_CS = P1^6; // Truly AMOLED 屏幕 SPI 片选脚 (CS) /* ====== 硬件 SPI 寄存器定义 ====== */ sfr P_SW1 = 0xA2; sfr SPCTL = 0xCE; sfr SPSTAT = 0xCD; sfr SPDAT = 0xCF; /* ====== RGB 幻彩灯条驱动函数 ====== */ void SPI_Init(void) { P_SW1 = (P_SW1 & ~0x0C) | 0x04; // 映射 SPI 至第二组 (P2.2~P2.5) SPCTL = 0xD1; // SSIG=1, SPEN=1, MSTR=1, SPR0=1 (3.0 MHz) SPSTAT = 0xC0; // 清除标志 } void Encode_Byte(u8 val, u8 *out) { u32 spi_val = 0; u8 i; for (i = 0; i < 8; i++) { spi_val <<= 3; if (val & (0x80 >> i)) { spi_val |= 6; // 1码 -> 110 } else { spi_val |= 4; // 0码 -> 100 } } out[0] = (u8)(spi_val >> 16); out[1] = (u8)(spi_val >> 8); out[2] = (u8)spi_val; } void RGB_Send(u8 g1, u8 r1, u8 b1, u8 g2, u8 r2, u8 b2) { u8 idata spi_buf[18]; u8 i; // 转码 3-bit 编码 Encode_Byte(g1, &spi_buf[0]); Encode_Byte(r1, &spi_buf[3]); Encode_Byte(b1, &spi_buf[6]); Encode_Byte(g2, &spi_buf[9]); Encode_Byte(r2, &spi_buf[12]); Encode_Byte(b2, &spi_buf[15]); EA = 0; // 关中断 // 临时将 P2.5 (MOTOR) 配置为高阻输入以隔离时钟信号 P2M1 |= (1 << 5); P2M0 &= ~(1 << 5); SPI_Init(); // 启动 SPI for (i = 0; i < 18; i++) { SPDAT = spi_buf[i]; while (!(SPSTAT & 0x80)); // 等待发送完毕 SPSTAT = 0xC0; } SPCTL = 0; // 关闭 SPI // 配置 P2.3 (RGB_DIN) 为推挽输出并拉低 100us 做 Reset P2M1 &= ~(1 << 3); P2M0 |= (1 << 3); RGB_DIN = 0; for (i = 0; i < 200; i++) { _nop_(); _nop_(); _nop_(); } // 恢复 P2.5 (MOTOR) 为推挽输出以进行振动控制 P2M1 &= ~(1 << 5); P2M0 |= (1 << 5); MOTOR = 0; EA = 1; // 开中断 } /* ========================================================================= * 系统全局变量 * ========================================================================= */ SystemState current_state = STATE_NORMAL; u8 current_hour = 10; u8 current_min = 35; u8 current_sec = 0; volatile u8 clock_updated = 0; u8 menu_select = 0; u32 captured_addr = 0; u8 captured_type = 0; u8 alarm_sensor_slot = 0; Sensor_Slot xdata sensor_list[16]; volatile u16 ms_tick = 0; volatile u16 inactivity_timer = 0; // 无操作闲置计时器 volatile u32 pair_timeout_ms = 0; volatile u16 alarm_timer_ms = 0; volatile u16 motor_timer_ms = 0; volatile bit alarm_flash_flag = 0; volatile u16 key_scan_timer = 0; volatile u16 key_up_hold = 0; volatile u16 key_down_hold = 0; volatile u16 key_confirm_hold = 0; volatile u16 key_sos_hold = 0; volatile u16 comb_hold = 0; /* ========================================================================= * 辅助映射表及前置声明 * ========================================================================= */ char *code sensor_names_fr[5] = { "PORTE", "PIR", "FUMEE", "GAZ", "EAU" }; char *code default_names[5] = { "PORTE", "PIR", "FUMEE", "GAZ", "EAU" }; u8 code default_zones[5] = {1, 1, 0, 0, 0}; char *code menu_items[5] = { "DETEC. PORTE", "DETEC. PIR", "DETEC. FUMEE", "DETEC. GAZ", "DETEC. EAU" }; void GPIO_Init(void); void Timer1_Init(void); u16 GetTimer0_Safe(void); void Delay_us(u16 us); void Delay_ms(u16 ms); void Uart1_Init(void); void Uart_SendByte(u8 dat); void Uart_SendString(char *s); char Uart_RxChar(void); void Uart_SendHex4(u8 val); void Uart_SendHex8(u8 val); void Uart_SendHex20(u32 val); void Uart_SendHex32(u32 val); void Uart_SendHex16(u16 val); void FormatHex(u32 val, char *buf); void IAP_Disable(void); u8 IAP_ReadByte(u16 addr); void IAP_WriteByte(u16 addr, u8 dat); void IAP_EraseSector(u16 addr); void Load_Database(void); void Save_Database(void); void Add_Sensor_With_Zone(u32 addr, u8 type, u8 zone); bit Check_Sensor_ID(u32 addr, u8 *out_slot_index); void UI_ShowClockPage(SystemState state, u8 hour, u8 min); void UI_ShowPairMenuPage(u8 selected_index); void UI_ShowPairWaitPage(u8 frame_index); void UI_ShowPairConfirmPage(u8 type, u8 zone_index); void UI_ShowPairSuccessPage(void); void UI_ShowPairFailPage(u8 is_timeout); void UI_ShowAlarmPage(u8 type, u8 zone_index); void UI_ShowSosPage(void); void UI_ShowBindingPage(u32 addr); void UI_ShowMainMenu(u8 selected_index); void UI_ShowSetTimePage(u8 hour, u8 min, u8 selection, u8 blink_on); void Start_Time_Edit(void); bit EV1527_Decode(u32 *out_addr, u8 *out_data); void RF_SetMode(u8 mode); void EV1527_Transmit(u32 addr, u8 dat); void EventQueue_Init(void); bit EventQueue_Push(SystemEvent evt); bit EventQueue_InsertFront(SystemEvent evt); SystemEvent EventQueue_Pop(void); bit EventQueue_IsEmpty(void); void AppManager_Init(void); void AppManager_StartApp(AppID app_id); void AppManager_DispatchEvent(SystemEvent evt); void AppManager_RunActiveApp(void); AppID AppManager_GetActiveAppID(void); void Add_Sensor_With_Zone(u32 addr, u8 type, u8 zone); /* ========================================================================= * 步骤1+4: 事件环形队列 (SystemEvent 环形缓冲区, 深度8) * ========================================================================= */ #define EVENT_QUEUE_DEPTH 8 static SystemEvent idata event_queue[EVENT_QUEUE_DEPTH]; static u8 queue_head = 0; static u8 queue_tail = 0; static u8 queue_count = 0; void EventQueue_Init(void) { queue_head = 0; queue_tail = 0; queue_count = 0; } bit EventQueue_Push(SystemEvent evt) { if (queue_count >= EVENT_QUEUE_DEPTH) return 0; EA = 0; event_queue[queue_tail] = evt; queue_tail = (queue_tail + 1) % EVENT_QUEUE_DEPTH; queue_count++; EA = 1; return 1; } bit EventQueue_InsertFront(SystemEvent evt) { if (queue_count >= EVENT_QUEUE_DEPTH) return 0; EA = 0; queue_head = (queue_head - 1 + EVENT_QUEUE_DEPTH) % EVENT_QUEUE_DEPTH; event_queue[queue_head] = evt; queue_count++; EA = 1; return 1; } SystemEvent EventQueue_Pop(void) { SystemEvent evt; evt.key_event = KEY_EVENT_NONE; evt.priority = EVENT_PRIORITY_LOW; evt.extra_data = 0; evt.extra_size = 0; if (queue_count == 0) return evt; EA = 0; evt = event_queue[queue_head]; queue_head = (queue_head + 1) % EVENT_QUEUE_DEPTH; queue_count--; EA = 1; return evt; } bit EventQueue_IsEmpty(void) { return (queue_count == 0) ? 1 : 0; } bit EventQueue_IsFull(void) { return (queue_count >= EVENT_QUEUE_DEPTH) ? 1 : 0; } u8 EventQueue_GetCount(void) { return queue_count; } /* ========================================================================= * 步骤2+5: App 框架与 AppManager * ========================================================================= */ #define APP_ONRUN_MAX_TICKS 5 static WristbandApp app_registry[APP_ID_MAX]; static WristbandApp *active_app = NULL; #define DEFAULT_APP_ID APP_ID_CLOCK /* 回调函数前置声明 */ void ClockApp_OnStart(void); void ClockApp_onRun(void); void ClockApp_onClose(void); EventResult ClockApp_onEvent(SystemEvent *evt); void MenuApp_OnStart(void); void MenuApp_onRun(void); void MenuApp_onClose(void); EventResult MenuApp_onEvent(SystemEvent *evt); void PairApp_OnStart(void); void PairApp_onRun(void); void PairApp_onClose(void); EventResult PairApp_onEvent(SystemEvent *evt); void AlarmApp_OnStart(void); void AlarmApp_onRun(void); void AlarmApp_onClose(void); EventResult AlarmApp_onEvent(SystemEvent *evt); void SOSApp_OnStart(void); void SOSApp_onRun(void); void SOSApp_onClose(void); EventResult SOSApp_onEvent(SystemEvent *evt); /* ====== AppManager 核心接口 ====== */ void AppManager_Init(void) { u8 i; /* 清零注册表 */ for (i = 0; i < APP_ID_MAX; i++) { app_registry[i].app_id = APP_ID_MAX; app_registry[i].app_type = APP_TYPE_FOREGROUND; app_registry[i].app_name = ""; app_registry[i].OnStart = NULL; app_registry[i].onRun = NULL; app_registry[i].onClose = NULL; app_registry[i].onEvent = NULL; app_registry[i].is_active = 0; app_registry[i].is_running = 0; } /* 注册 ClockApp */ app_registry[APP_ID_CLOCK].app_id = APP_ID_CLOCK; app_registry[APP_ID_CLOCK].app_type = APP_TYPE_FOREGROUND; app_registry[APP_ID_CLOCK].app_name = "Clock"; app_registry[APP_ID_CLOCK].OnStart = ClockApp_OnStart; app_registry[APP_ID_CLOCK].onRun = ClockApp_onRun; app_registry[APP_ID_CLOCK].onClose = ClockApp_onClose; app_registry[APP_ID_CLOCK].onEvent = ClockApp_onEvent; /* 注册 MenuApp */ app_registry[APP_ID_MENU].app_id = APP_ID_MENU; app_registry[APP_ID_MENU].app_type = APP_TYPE_FOREGROUND; app_registry[APP_ID_MENU].app_name = "Menu"; app_registry[APP_ID_MENU].OnStart = MenuApp_OnStart; app_registry[APP_ID_MENU].onRun = MenuApp_onRun; app_registry[APP_ID_MENU].onClose = MenuApp_onClose; app_registry[APP_ID_MENU].onEvent = MenuApp_onEvent; /* 注册 PairApp */ app_registry[APP_ID_PAIR].app_id = APP_ID_PAIR; app_registry[APP_ID_PAIR].app_type = APP_TYPE_FOREGROUND; app_registry[APP_ID_PAIR].app_name = "Pair"; app_registry[APP_ID_PAIR].OnStart = PairApp_OnStart; app_registry[APP_ID_PAIR].onRun = PairApp_onRun; app_registry[APP_ID_PAIR].onClose = PairApp_onClose; app_registry[APP_ID_PAIR].onEvent = PairApp_onEvent; /* 注册 AlarmApp */ app_registry[APP_ID_ALARM].app_id = APP_ID_ALARM; app_registry[APP_ID_ALARM].app_type = APP_TYPE_FOREGROUND; app_registry[APP_ID_ALARM].app_name = "Alarm"; app_registry[APP_ID_ALARM].OnStart = AlarmApp_OnStart; app_registry[APP_ID_ALARM].onRun = AlarmApp_onRun; app_registry[APP_ID_ALARM].onClose = AlarmApp_onClose; app_registry[APP_ID_ALARM].onEvent = AlarmApp_onEvent; /* 注册 SOSApp */ app_registry[APP_ID_SOS].app_id = APP_ID_SOS; app_registry[APP_ID_SOS].app_type = APP_TYPE_FOREGROUND; app_registry[APP_ID_SOS].app_name = "SOS"; app_registry[APP_ID_SOS].OnStart = SOSApp_OnStart; app_registry[APP_ID_SOS].onRun = SOSApp_onRun; app_registry[APP_ID_SOS].onClose = SOSApp_onClose; app_registry[APP_ID_SOS].onEvent = SOSApp_onEvent; AppManager_StartApp(DEFAULT_APP_ID); } void AppManager_StartApp(AppID app_id) { WristbandApp *target; if (app_id >= APP_ID_MAX) return; target = &app_registry[app_id]; if (target->OnStart == NULL) return; if (active_app == target) return; Uart_SendString("[APP] StartApp: "); Uart_SendString(target->app_name); Uart_SendString("\r\n"); /* 关闭当前活跃应用 */ if (active_app != NULL && active_app->onClose != NULL) { active_app->is_active = 0; active_app->onClose(); } /* 切换并启动新应用 */ active_app = target; if (active_app->OnStart != NULL) { active_app->is_active = 1; active_app->is_running = 1; active_app->OnStart(); } } void AppManager_DispatchEvent(SystemEvent evt) { EventResult result = EVENT_IGNORED; if (active_app != NULL && active_app->is_active && active_app->onEvent != NULL) { result = active_app->onEvent(&evt); if (result == EVENT_HANDLED) return; } } void AppManager_RunActiveApp(void) { u16 start_tick; u16 elapsed; if (active_app == NULL || !active_app->is_active) return; if (!active_app->is_running) return; if (active_app->onRun == NULL) return; start_tick = ms_tick; active_app->onRun(); elapsed = ms_tick - start_tick; if (elapsed > APP_ONRUN_MAX_TICKS) { active_app->is_running = 0; } else { active_app->is_running = 1; } } AppID AppManager_GetActiveAppID(void) { if (active_app == NULL) return APP_ID_MAX; return active_app->app_id; } /* ========================================================================= * ClockApp 回调实现与时间编辑状态机 * ========================================================================= */ static u8 time_edit_active = 0; static u8 time_edit_field = 1; static u8 time_edit_blink_on = 1; void Start_Time_Edit(void) { time_edit_active = 1; time_edit_field = 1; time_edit_blink_on = 1; current_state = STATE_SET_TIME; // FCOB 幻彩灯条蓝色常亮 (R=0, G=0, B=180) RGB_Send(0, 0, 180, 0, 0, 180); // 马达短振 50ms MOTOR = 1; Delay_ms(50); MOTOR = 0; UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1); } void ClockApp_OnStart(void) { time_edit_active = 0; current_state = STATE_NORMAL; RF_SetMode(1); UI_ShowClockPage(current_state, current_hour, current_min); // 启动时熄灭灯条 RGB_Send(0, 0, 0, 0, 0, 0); Uart_SendString("[ClockApp] Started\r\n"); } void ClockApp_onRun(void) { u32 rx_addr; u8 rx_data; if (time_edit_active) { // 500ms 周期控制闪烁 u8 blink = (ms_tick / 500) % 2; if (blink != time_edit_blink_on) { time_edit_blink_on = blink; UI_ShowSetTimePage(current_hour, current_min, time_edit_field, time_edit_blink_on); } } else { if (clock_updated) { clock_updated = 0; UI_ShowClockPage(current_state, current_hour, current_min); } 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) { if (sensor_list[slot].zone == 0 || current_state == STATE_ARMED) { SystemEvent rf_evt; rf_evt.key_event = KEY_EVENT_NONE; rf_evt.priority = EVENT_PRIORITY_HIGH; rf_evt.extra_data = rx_addr; rf_evt.extra_size = 4; EventQueue_InsertFront(rf_evt); } } } } } } void ClockApp_onClose(void) { time_edit_active = 0; RGB_Send(0, 0, 0, 0, 0, 0); Uart_SendString("[ClockApp] Closed\r\n"); } EventResult ClockApp_onEvent(SystemEvent *evt) { if (time_edit_active) { if (evt->key_event == KEY_EVENT_UP_CLICK) { if (time_edit_field == 1) { current_hour = (current_hour + 1) % 24; } else { current_min = (current_min + 1) % 60; } UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_DOWN_CLICK) { if (time_edit_field == 1) { current_hour = (current_hour == 0) ? 23 : (current_hour - 1); } else { current_min = (current_min == 0) ? 59 : (current_min - 1); } UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_LONG) { // 长按 Confirm 键跳转字段 if (time_edit_field == 1) { time_edit_field = 2; } else { time_edit_field = 1; } UI_ShowSetTimePage(current_hour, current_min, time_edit_field, 1); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) { // 短按 Confirm 键保存退出 time_edit_active = 0; current_state = STATE_NORMAL; RGB_Send(0, 0, 0, 0, 0, 0); // 熄灭 // 退出短振 MOTOR = 1; Delay_ms(50); MOTOR = 0; UI_ShowClockPage(current_state, current_hour, current_min); return EVENT_HANDLED; } return EVENT_HANDLED; // 吞掉其他按键 } if (evt->key_event == KEY_EVENT_CONFIRM_LONG) { AppManager_StartApp(APP_ID_MENU); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_UP_LONG) { if (current_state == STATE_ARMED) { current_state = STATE_DISARMED; } else { current_state = STATE_ARMED; } // 切换状态短震确认 MOTOR = 1; Delay_ms(100); MOTOR = 0; UI_ShowClockPage(current_state, current_hour, current_min); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_SOS_CLICK || evt->key_event == KEY_EVENT_SOS_LONG) { AppManager_StartApp(APP_ID_SOS); return EVENT_HANDLED; } return EVENT_IGNORED; } /* ========================================================================= * MenuApp 回调实现 * ========================================================================= */ static u8 menu_level = 0; // 0:主菜单, 1:传感器对码二级菜单, 2:IPC绑定中 static u16 last_bind_tx_ms = 0; void MenuApp_OnStart(void) { menu_level = 0; menu_select = 0; current_state = STATE_PAIR_MENU; RF_SetMode(0); UI_ShowMainMenu(menu_select); RGB_Send(0, 0, 0, 0, 0, 0); // 熄灭灯条 Uart_SendString("[MenuApp] Started (Main Menu)\r\n"); } void MenuApp_onRun(void) { if (menu_level == 2) { // 绑定中:控制青色呼吸灯 (周期1000ms,双灯同步) u16 breath = ms_tick % 1000; u8 val = (breath < 500) ? (breath * 2 / 5) : ((1000 - breath) * 2 / 5); // 范围 0~200 RGB_Send(0, val, val, 0, val, val); // 每 500ms 发射一次绑定信号 (出厂 Factory ID) if (ms_tick - last_bind_tx_ms >= 500 || ms_tick < last_bind_tx_ms) { last_bind_tx_ms = ms_tick; RF_SetMode(2); EV1527_Transmit(CLONED_ADDR, 0x01); RF_SetMode(0); } } } void MenuApp_onClose(void) { menu_level = 0; RGB_Send(0, 0, 0, 0, 0, 0); RF_SetMode(1); Uart_SendString("[MenuApp] Closed\r\n"); } EventResult MenuApp_onEvent(SystemEvent *evt) { if (menu_level == 0) { // 主菜单层 (0-HORLOGE, 1-APPAIRAGE, 2-LIAISON) if (evt->key_event == KEY_EVENT_UP_CLICK) { if (menu_select > 0) { menu_select--; UI_ShowMainMenu(menu_select); } return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_DOWN_CLICK) { if (menu_select < 2) { menu_select++; UI_ShowMainMenu(menu_select); } return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) { if (menu_select == 0) { // 启动时钟 App 并立即进入编辑模式 AppManager_StartApp(APP_ID_CLOCK); Start_Time_Edit(); } else if (menu_select == 1) { // 进入二级传感器对码菜单 menu_level = 1; menu_select = 0; UI_ShowPairMenuPage(menu_select); } else if (menu_select == 2) { // 进入摄像机绑定 menu_level = 2; last_bind_tx_ms = ms_tick; current_state = STATE_IPC_BIND; UI_ShowBindingPage(CLONED_ADDR); } return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_LONG) { AppManager_StartApp(APP_ID_CLOCK); return EVENT_HANDLED; } } else if (menu_level == 1) { // 传感器对码选择菜单 (0-门磁, 1-PIR, 2-烟感, 3-气感, 4-水浸) if (evt->key_event == KEY_EVENT_UP_CLICK) { if (menu_select > 0) { menu_select--; UI_ShowPairMenuPage(menu_select); } return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_DOWN_CLICK) { if (menu_select < 4) { menu_select++; UI_ShowPairMenuPage(menu_select); } return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) { // 保存当前选定的类型到 captured_type,短震 100ms 并跳转到 PairApp 对码搜索 captured_type = menu_select; MOTOR = 1; Delay_ms(100); MOTOR = 0; AppManager_StartApp(APP_ID_PAIR); return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_DOWN_LONG) { // 返回主菜单 menu_level = 0; menu_select = 1; UI_ShowMainMenu(menu_select); return EVENT_HANDLED; } } else if (menu_level == 2) { // 绑定中:长按 Confirm 键 (3秒) 或 长按 DOWN 键 (2秒) 退出返回主菜单 if (evt->key_event == KEY_EVENT_CONFIRM_LONG || evt->key_event == KEY_EVENT_DOWN_LONG) { menu_level = 0; menu_select = 2; current_state = STATE_PAIR_MENU; RGB_Send(0, 0, 0, 0, 0, 0); // 熄灭 UI_ShowMainMenu(menu_select); return EVENT_HANDLED; } } return EVENT_IGNORED; } /* ========================================================================= * PairApp 回调实现 * ========================================================================= */ enum { PAIR_STATE_WAIT, PAIR_STATE_CONFIRM, PAIR_STATE_SUCCESS, PAIR_STATE_FAIL }; static u8 pair_state; static u8 last_radar_sec; static u8 captured_zone = 1; static u32 success_start_ms = 0; static u32 fail_start_ms = 0; void PairApp_OnStart(void) { pair_state = PAIR_STATE_WAIT; last_radar_sec = 99; current_state = STATE_PAIR_WAIT; pair_timeout_ms = 0; captured_zone = 1; RF_SetMode(1); // 初始化对码搜寻状态显示 UI_ShowPairWaitPage(0); // 快闪白色 RGB (双灯) RGB_Send(150, 150, 150, 150, 150, 150); Uart_SendString("[PairApp] Started (WAIT)\r\n"); } void PairApp_onRun(void) { u32 rx_addr; u8 rx_data; u8 flash; u8 frame; if (pair_state == PAIR_STATE_WAIT) { // 白色 3Hz 快闪 (周期 333ms, 亮 166ms) flash = (ms_tick / 166) % 2; if (flash) RGB_Send(150, 150, 150, 150, 150, 150); else RGB_Send(0, 0, 0, 0, 0, 0); frame = (u8)((ms_tick / 250) % 3); if (frame != last_radar_sec) { last_radar_sec = frame; UI_ShowPairWaitPage(frame); } if (pair_timeout_ms >= 30000UL) { pair_timeout_ms = 0; pair_state = PAIR_STATE_FAIL; current_state = STATE_PAIR_FAIL; fail_start_ms = ms_tick; UI_ShowPairFailPage(1); // 红色常亮 RGB_Send(200, 0, 0, 200, 0, 0); Uart_SendString("[PairApp] Timeout\r\n"); return; } if (EV1527_Decode(&rx_addr, &rx_data)) { // 排除 SOS 数据码 (0x08 代表 SOS 求救,不用于常规传感器配对) if (rx_data != 0x08) { captured_addr = rx_addr; pair_state = PAIR_STATE_CONFIRM; current_state = STATE_PAIR_CONFIRM; RF_SetMode(0); captured_zone = 1; // 初始为防区 1 UI_ShowPairConfirmPage(captured_type, captured_zone); Uart_SendString("[PairApp] Sensor captured\r\n"); } } } else if (pair_state == PAIR_STATE_CONFIRM) { // 橙色慢闪 (1.5Hz, 周期 666ms) u8 flash = (ms_tick / 333) % 2; if (flash) RGB_Send(100, 180, 0, 100, 180, 0); // 橙色 else RGB_Send(0, 0, 0, 0, 0, 0); } else if (pair_state == PAIR_STATE_SUCCESS) { // 2 秒后自动返回二级菜单 if (ms_tick - success_start_ms >= 2000 || ms_tick < success_start_ms) { AppManager_StartApp(APP_ID_MENU); } } else if (pair_state == PAIR_STATE_FAIL) { // 5 秒后自动返回二级菜单 if (ms_tick - fail_start_ms >= 5000 || ms_tick < fail_start_ms) { AppManager_StartApp(APP_ID_MENU); } } } void PairApp_onClose(void) { RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯光 MOTOR = 0; RF_SetMode(1); Uart_SendString("[PairApp] Closed\r\n"); } EventResult PairApp_onEvent(SystemEvent *evt) { if (pair_state == PAIR_STATE_CONFIRM) { if (evt->key_event == KEY_EVENT_UP_CLICK) { if (captured_zone < 99) { captured_zone++; UI_ShowPairConfirmPage(captured_type, captured_zone); } return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_DOWN_CLICK) { if (captured_zone > 1) { captured_zone--; UI_ShowPairConfirmPage(captured_type, captured_zone); } return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_CLICK) { // 保存防区配对并显示成功反馈 Add_Sensor_With_Zone(captured_addr, captured_type, captured_zone); pair_state = PAIR_STATE_SUCCESS; current_state = STATE_PAIR_SUCCESS; success_start_ms = ms_tick; UI_ShowPairSuccessPage(); // 绿色常亮且马达长振 400ms RGB_Send(0, 200, 0, 0, 200, 0); MOTOR = 1; Delay_ms(400); MOTOR = 0; return EVENT_HANDLED; } if (evt->key_event == KEY_EVENT_CONFIRM_LONG) { // 长按 Confirm 取消返回主菜单 RGB_Send(0, 0, 0, 0, 0, 0); AppManager_StartApp(APP_ID_MENU); return EVENT_HANDLED; } } // 搜寻状态或确认状态下长按 DOWN 退出 if (evt->key_event == KEY_EVENT_DOWN_LONG) { RGB_Send(0, 0, 0, 0, 0, 0); AppManager_StartApp(APP_ID_MENU); return EVENT_HANDLED; } return EVENT_IGNORED; } /* ========================================================================= * AlarmApp 回调实现 * ========================================================================= */ void AlarmApp_OnStart(void) { u8 slot; u8 type = 0; u8 zone = 1; current_state = STATE_ALARM; alarm_timer_ms = 0; alarm_flash_flag = 0; if (Check_Sensor_ID(captured_addr, &slot)) { type = sensor_list[slot].type; zone = sensor_list[slot].zone; alarm_sensor_slot = slot; } // 初始化显示警报界面 UI_ShowAlarmPage(type, zone); // 首次亮起防区对应颜色 if (type == 0) RGB_Send(0, 180, 0, 0, 180, 0); // 门磁: 红色 (R=180) else if (type == 1) RGB_Send(100, 180, 0, 100, 180, 0); // PIR: 黄色 else if (type == 2) RGB_Send(180, 0, 0, 180, 0, 0); // 烟感: 绿色 (G=180) else if (type == 3) RGB_Send(0, 180, 180, 0, 180, 180); // 气感: 紫色 else RGB_Send(0, 0, 180, 0, 0, 180); // 水浸: 蓝色 Uart_SendString("[AlarmApp] Started\r\n"); } void AlarmApp_onRun(void) { u8 type = sensor_list[alarm_sensor_slot].type; u8 flash = (ms_tick / 250) % 2; // 250ms 亮灭周期 // 同步控制 RGB 幻彩灯闪烁 if (flash) { if (type == 0) RGB_Send(0, 180, 0, 0, 180, 0); else if (type == 1) RGB_Send(100, 180, 0, 100, 180, 0); else if (type == 2) RGB_Send(180, 0, 0, 180, 0, 0); else if (type == 3) RGB_Send(0, 180, 180, 0, 180, 180); else RGB_Send(0, 0, 180, 0, 0, 180); } else { RGB_Send(0, 0, 0, 0, 0, 0); } // Truly AMOLED 粗红框闪烁 if (alarm_flash_flag) { LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED); LCD_DrawRectBorder(6, 6, 108, 228, COLOR_RED); } else { LCD_DrawRectBorder(4, 4, 112, 232, COLOR_BLACK); LCD_DrawRectBorder(6, 6, 108, 228, COLOR_BLACK); } } void AlarmApp_onClose(void) { RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯条 MOTOR = 0; current_state = STATE_NORMAL; Uart_SendString("[AlarmApp] Closed\r\n"); } EventResult AlarmApp_onEvent(SystemEvent *evt) { // 任意键按下或长按 ➔ 清除报警返回时钟 if (evt->key_event != KEY_EVENT_NONE) { AppManager_StartApp(APP_ID_CLOCK); return EVENT_HANDLED; } return EVENT_IGNORED; } /* ========================================================================= * SOSApp 回调实现 * ========================================================================= */ static u8 sos_last_phase; void SOSApp_OnStart(void) { current_state = STATE_SOS_EMITTED; sos_last_phase = 99; alarm_timer_ms = 0; UI_ShowSosPage(); // 立即启动双灯交替爆闪 RGB_Send(0, 200, 0, 0, 0, 0); Uart_SendString("[SOSApp] Started\r\n"); } void SOSApp_onRun(void) { // 每 500ms 发射一次求救射频信号 (CLONED_ADDR 伴随 SOS 数据码 0x08) u8 sec_phase = (u8)((ms_tick / 500) % 2); if (sec_phase != sos_last_phase) { sos_last_phase = sec_phase; RF_SetMode(2); EV1527_Transmit(CLONED_ADDR, 0x08); RF_SetMode(0); } // 50ms 周期控制双灯交替红色闪烁 { u8 flash = (ms_tick / 50) % 2; if (flash) { RGB_Send(0, 200, 0, 0, 0, 0); // 灯1亮红,灯2灭 } else { RGB_Send(0, 0, 0, 0, 200, 0); // 灯1灭,灯2亮红 } } // Truly AMOLED 边框闪烁 (红粗边框 + 白细边框) if (alarm_flash_flag) { LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED); LCD_DrawRectBorder(5, 5, 110, 230, COLOR_RED); LCD_DrawRectBorder(8, 8, 104, 224, COLOR_WHITE); } else { LCD_DrawRectBorder(4, 4, 112, 232, COLOR_BLACK); LCD_DrawRectBorder(5, 5, 110, 230, COLOR_BLACK); LCD_DrawRectBorder(8, 8, 104, 224, COLOR_BLACK); } } void SOSApp_onClose(void) { RGB_Send(0, 0, 0, 0, 0, 0); // 关闭灯条 MOTOR = 0; current_state = STATE_NORMAL; Uart_SendString("[SOSApp] Closed\r\n"); } EventResult SOSApp_onEvent(SystemEvent *evt) { // 短按或长按任意键 ➔ 退出求救状态返回待机时钟 if (evt->key_event != KEY_EVENT_NONE) { AppManager_StartApp(APP_ID_CLOCK); return EVENT_HANDLED; } return EVENT_IGNORED; } /* ========================================================================= * 延时与时间获取辅助函数 * ========================================================================= */ 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; } /* ========================================================================= * STC32G 闪存 IAP (EEPROM) 读写 * ========================================================================= */ #define IAP_CMD_READ 1 #define IAP_CMD_WRITE 2 #define IAP_CMD_ERASE 3 void IAP_Disable(void) { IAP_CONTR = 0; IAP_CMD = 0; IAP_TRIG = 0; IAP_ADDRH = 0xff; IAP_ADDRL = 0xff; } u8 IAP_ReadByte(u16 addr) { IAP_CONTR = 0x80; IAP_TPS = (u8)(MAIN_Fosc / 1000000UL); IAP_CMD = IAP_CMD_READ; IAP_ADDRL = (u8)addr; IAP_ADDRH = (u8)(addr >> 8); IAP_ADDRE = 0; IAP_TRIG = 0x5a; IAP_TRIG = 0xa5; _nop_(); _nop_(); _nop_(); _nop_(); IAP_Disable(); return IAP_DATA; } void IAP_WriteByte(u16 addr, u8 dat) { IAP_CONTR = 0x80; IAP_TPS = (u8)(MAIN_Fosc / 1000000UL); IAP_CMD = IAP_CMD_WRITE; IAP_ADDRL = (u8)addr; IAP_ADDRH = (u8)(addr >> 8); IAP_ADDRE = 0; IAP_DATA = dat; IAP_TRIG = 0x5a; IAP_TRIG = 0xa5; _nop_(); _nop_(); _nop_(); _nop_(); IAP_Disable(); } void IAP_EraseSector(u16 addr) { IAP_CONTR = 0x80; IAP_TPS = (u8)(MAIN_Fosc / 1000000UL); IAP_CMD = IAP_CMD_ERASE; IAP_ADDRL = (u8)addr; IAP_ADDRH = (u8)(addr >> 8); IAP_ADDRE = 0; IAP_TRIG = 0x5a; IAP_TRIG = 0xa5; _nop_(); _nop_(); _nop_(); _nop_(); IAP_Disable(); } void Load_Database(void) { u16 addr = 0; u8 *ptr = (u8 *)&sensor_list; u16 size = sizeof(sensor_list); u16 i; for (i = 0; i < size; i++) { ptr[i] = IAP_ReadByte(addr++); } } void Save_Database(void) { u16 addr = 0; u8 *ptr = (u8 *)&sensor_list; u16 size = sizeof(sensor_list); u16 i; IAP_EraseSector(0); for (i = 0; i < size; i++) { IAP_WriteByte(addr++, ptr[i]); } } void Add_Sensor_With_Zone(u32 addr, u8 type, u8 zone) { u8 i; u8 slot_to_use = 15; for (i = 0; i < 16; i++) { if (sensor_list[i].is_used == 0x01) { u32 existing_addr = ((u32)sensor_list[i].addr[0] << 16) | ((u32)sensor_list[i].addr[1] << 8) | sensor_list[i].addr[2]; if (existing_addr == addr) { slot_to_use = i; break; } } else { slot_to_use = i; break; } } sensor_list[slot_to_use].is_used = 0x01; sensor_list[slot_to_use].addr[0] = (u8)(addr >> 16); sensor_list[slot_to_use].addr[1] = (u8)(addr >> 8); sensor_list[slot_to_use].addr[2] = (u8)addr; sensor_list[slot_to_use].type = type; sensor_list[slot_to_use].zone = zone; for (i = 0; i < 15; i++) { sensor_list[slot_to_use].name_gbk[i] = sensor_names_fr[type][i]; if (sensor_names_fr[type][i] == '\0') break; } sensor_list[slot_to_use].name_gbk[15] = '\0'; Save_Database(); } bit Check_Sensor_ID(u32 addr, u8 *out_slot_index) { u8 i; for (i = 0; i < 16; i++) { if (sensor_list[i].is_used == 0x01) { u32 slot_addr = ((u32)sensor_list[i].addr[0] << 16) | ((u32)sensor_list[i].addr[1] << 8) | sensor_list[i].addr[2]; if (slot_addr == addr) { *out_slot_index = i; return 1; } } } return 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'; } /* ========================================================================= * UI 页面渲染函数 * ========================================================================= */ void UI_ShowClockPage(SystemState state, u8 hour, u8 min) { char time_str[6]; LCD_Clear(COLOR_BLACK); // 左上角锁图标 if (state == STATE_ARMED) { LCD_DrawRectBorder(10, 23, 20, 15, COLOR_RED); LCD_FillRect(15, 15, 2, 8, COLOR_RED); LCD_FillRect(17, 15, 10, 2, COLOR_RED); LCD_FillRect(25, 15, 2, 8, COLOR_RED); } else { LCD_DrawRectBorder(10, 23, 20, 15, COLOR_GREEN); LCD_FillRect(15, 15, 2, 8, COLOR_GREEN); LCD_FillRect(17, 15, 8, 2, COLOR_GREEN); LCD_FillRect(25, 17, 2, 6, COLOR_GREEN); } // 右上角电量 LCD_ShowString(62, 24, "85%", COLOR_GRAY, COLOR_BLACK); LCD_DrawMonoBitmap(92, 27, 20, 10, bmp_battery_20x10, COLOR_GRAY, COLOR_BLACK); // 中间时间 time_str[0] = '0' + (hour / 10); time_str[1] = '0' + (hour % 10); time_str[2] = ':'; time_str[3] = '0' + (min / 10); time_str[4] = '0' + (min % 10); time_str[5] = '\0'; LCD_ShowString16x32Centered(100, time_str, COLOR_WHITE, COLOR_BLACK); // AM/PM LCD_ShowStringCentered(150, "AM", COLOR_WHITE, COLOR_BLACK); // 日期 (法语) LCD_ShowStringCentered(195, "VEN 10-07", COLOR_GRAY, COLOR_BLACK); } void UI_ShowPairMenuPage(u8 selected_index) { LCD_Clear(COLOR_BLACK); LCD_ShowStringCentered(30, "MENU APPAI.", COLOR_AMBER, COLOR_BLACK); if (selected_index > 0) { LCD_ShowStringCentered(78, menu_items[selected_index - 1], COLOR_GRAY, COLOR_BLACK); } LCD_DrawRectBorder(8, 110, 104, 28, COLOR_CYAN); LCD_ShowStringCentered(118, menu_items[selected_index], COLOR_CYAN, COLOR_BLACK); if (selected_index < 4) { LCD_ShowStringCentered(158, menu_items[selected_index + 1], COLOR_GRAY, COLOR_BLACK); } } void UI_ShowPairWaitPage(u8 frame_index) { LCD_Clear(COLOR_BLACK); LCD_ShowStringCentered(35, "APPAIRAGE", COLOR_GRAY, COLOR_BLACK); if (frame_index == 0) LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_radar_32x32_f1, COLOR_CYAN, COLOR_BLACK); else if (frame_index == 1) LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_radar_32x32_f2, COLOR_CYAN, COLOR_BLACK); else LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_radar_32x32_f3, COLOR_CYAN, COLOR_BLACK); LCD_ShowStringCentered(165, "RECHERCHE", COLOR_WHITE, COLOR_BLACK); LCD_ShowStringCentered(200, "DECLENCH. CAPT", COLOR_CYAN, COLOR_BLACK); } void UI_ShowPairConfirmPage(u8 type, u8 zone_index) { char zone_str[3]; LCD_Clear(COLOR_BLACK); LCD_ShowStringCentered(32, "v RECU", COLOR_GREEN, COLOR_BLACK); if (type == 0) { LCD_DrawMonoBitmap(44, 55, 32, 32, bmp_door_32x32, COLOR_WHITE, COLOR_BLACK); } else if (type == 2 || type == 3) { LCD_DrawMonoBitmap(44, 55, 32, 32, bmp_siren_32x32, COLOR_WHITE, COLOR_BLACK); } else { LCD_DrawMonoBitmap(44, 55, 32, 32, bmp_confirm_lock_32x32, COLOR_WHITE, COLOR_BLACK); } LCD_ShowStringCentered(105, sensor_names_fr[type], COLOR_WHITE, COLOR_BLACK); LCD_DrawRectBorder(15, 140, 90, 44, COLOR_CYAN); zone_str[0] = '0' + (zone_index / 10); zone_str[1] = '0' + (zone_index % 10); zone_str[2] = '\0'; LCD_ShowString16x32(44, 146, zone_str, COLOR_CYAN, COLOR_BLACK); LCD_ShowStringCentered(215, "CONFIRMER", COLOR_GRAY, COLOR_BLACK); } void UI_ShowPairSuccessPage(void) { LCD_Clear(COLOR_BLACK); LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_checkmark_32x32, COLOR_GREEN, COLOR_BLACK); LCD_ShowStringCentered(145, "SUCCES", COLOR_GREEN, COLOR_BLACK); LCD_ShowStringCentered(180, "ENREGISTRE", COLOR_GRAY, COLOR_BLACK); } void UI_ShowPairFailPage(u8 is_timeout) { LCD_Clear(COLOR_BLACK); LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_cross_32x32, COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(145, "ECHEC", COLOR_RED, COLOR_BLACK); if (is_timeout) { LCD_ShowStringCentered(180, "DELAI DEPASSE", COLOR_GRAY, COLOR_BLACK); } else { LCD_ShowStringCentered(180, "TYPE INCORRECT", COLOR_GRAY, COLOR_BLACK); } } void UI_ShowAlarmPage(u8 type, u8 zone_index) { char zone_info[20]; LCD_Clear(COLOR_BLACK); LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED); LCD_DrawRectBorder(6, 6, 108, 228, COLOR_RED); if (type == 0) { LCD_DrawMonoBitmap(44, 50, 32, 32, bmp_door_32x32, COLOR_RED, COLOR_BLACK); } else if (type == 2 || type == 3) { LCD_DrawMonoBitmap(44, 50, 32, 32, bmp_siren_32x32, COLOR_RED, COLOR_BLACK); } else { LCD_DrawMonoBitmap(44, 50, 32, 32, bmp_confirm_lock_32x32, COLOR_RED, COLOR_BLACK); } { u8 len = 0; char *p = sensor_names_fr[type]; while(*p) { zone_info[len++] = *p++; } zone_info[len++] = ' '; zone_info[len++] = '0' + (zone_index / 10); zone_info[len++] = '0' + (zone_index % 10); zone_info[len] = '\0'; } LCD_ShowStringCentered(135, zone_info, COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(175, "INTRUSION!", COLOR_WHITE, COLOR_BLACK); } void UI_ShowSosPage(void) { LCD_Clear(COLOR_BLACK); LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED); LCD_DrawRectBorder(5, 5, 110, 230, COLOR_RED); LCD_DrawRectBorder(8, 8, 104, 224, COLOR_WHITE); // 警灯组合绘制 LCD_FillRect(44, 45, 32, 2, COLOR_RED); LCD_FillRect(48, 47, 24, 12, COLOR_RED); LCD_FillRect(40, 59, 40, 4, COLOR_GRAY); LCD_FillRect(57, 51, 6, 6, COLOR_WHITE); LCD_FillRect(58, 36, 4, 6, COLOR_RED); LCD_FillRect(46, 38, 4, 4, COLOR_RED); LCD_FillRect(70, 38, 4, 4, COLOR_RED); LCD_ShowStringCentered(120, "SOS", COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(150, "ENVOI", COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(195, "APPEL...", COLOR_WHITE, COLOR_BLACK); } void UI_ShowBindingPage(u32 addr) { char id_str[20]; LCD_Clear(COLOR_BLACK); // 摄像机组合绘制 LCD_DrawRectBorder(36, 46, 32, 26, COLOR_CYAN); LCD_FillRect(44, 56, 6, 6, COLOR_CYAN); LCD_FillRect(68, 48, 2, 22, COLOR_CYAN); LCD_FillRect(70, 50, 2, 18, COLOR_CYAN); LCD_FillRect(72, 52, 2, 14, COLOR_CYAN); LCD_ShowStringCentered(120, "LIAISON", COLOR_WHITE, COLOR_BLACK); LCD_ShowStringCentered(155, "ENVOI EN COURS", COLOR_CYAN, COLOR_BLACK); id_str[0] = 'I'; id_str[1] = 'D'; id_str[2] = ':'; id_str[3] = ' '; id_str[4] = '0'; id_str[5] = 'x'; { u8 val1 = (u8)(addr >> 16); u8 val2 = (u8)(addr >> 8); u8 val3 = (u8)addr; u8 nibble = val1 >> 4; id_str[6] = (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10)); nibble = val1 & 0x0F; id_str[7] = (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10)); nibble = val2 >> 4; id_str[8] = (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10)); nibble = val2 & 0x0F; id_str[9] = (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10)); nibble = val3 >> 4; id_str[10] = (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10)); nibble = val3 & 0x0F; id_str[11] = (nibble < 10) ? ('0' + nibble) : ('A' + (nibble - 10)); id_str[12] = '\0'; } LCD_ShowStringCentered(205, id_str, COLOR_GRAY, COLOR_BLACK); } void UI_ShowMainMenu(u8 selected_index) { LCD_Clear(COLOR_BLACK); LCD_FillRect(58, 20, 4, 2, COLOR_GRAY); LCD_FillRect(56, 22, 8, 2, COLOR_GRAY); LCD_FillRect(54, 24, 12, 2, COLOR_GRAY); if (selected_index == 0) { LCD_DrawRectBorder(44, 70, 32, 32, COLOR_CYAN); LCD_FillRect(59, 76, 2, 10, COLOR_CYAN); LCD_FillRect(59, 85, 8, 2, COLOR_CYAN); LCD_ShowStringCentered(150, "1. HORLOGE", COLOR_WHITE, COLOR_BLACK); } else if (selected_index == 1) { LCD_DrawMonoBitmap(44, 70, 32, 32, bmp_radar_32x32_f3, COLOR_CYAN, COLOR_BLACK); LCD_ShowStringCentered(150, "2. APPAIRAGE", COLOR_WHITE, COLOR_BLACK); } else if (selected_index == 2) { LCD_DrawRectBorder(44, 74, 20, 16, COLOR_CYAN); LCD_FillRect(52, 80, 4, 4, COLOR_CYAN); LCD_FillRect(64, 76, 2, 12, COLOR_CYAN); LCD_FillRect(66, 78, 2, 8, COLOR_CYAN); LCD_FillRect(68, 80, 2, 4, COLOR_CYAN); LCD_ShowStringCentered(150, "3. LIAISON", COLOR_WHITE, COLOR_BLACK); } LCD_FillRect(54, 210, 12, 2, COLOR_GRAY); LCD_FillRect(56, 212, 8, 2, COLOR_GRAY); LCD_FillRect(58, 214, 4, 2, COLOR_GRAY); } void UI_ShowSetTimePage(u8 hour, u8 min, u8 selection, u8 blink_on) { char time_str[6]; LCD_Clear(COLOR_BLACK); LCD_DrawRectBorder(10, 23, 20, 15, COLOR_GREEN); LCD_FillRect(15, 15, 2, 8, COLOR_GREEN); LCD_FillRect(17, 15, 8, 2, COLOR_GREEN); LCD_FillRect(25, 17, 2, 6, COLOR_GREEN); LCD_ShowString(62, 24, "85%", COLOR_GRAY, COLOR_BLACK); LCD_DrawMonoBitmap(92, 27, 20, 10, bmp_battery_20x10, COLOR_GRAY, COLOR_BLACK); if (selection == 1 && !blink_on) { time_str[0] = ' '; time_str[1] = ' '; } else { time_str[0] = '0' + (hour / 10); time_str[1] = '0' + (hour % 10); } time_str[2] = '\0'; LCD_ShowString16x32(12, 100, time_str, COLOR_CYAN, COLOR_BLACK); LCD_ShowString16x32(48, 98, ":", COLOR_WHITE, COLOR_BLACK); if (selection == 2 && !blink_on) { time_str[0] = ' '; time_str[1] = ' '; } else { time_str[0] = '0' + (min / 10); time_str[1] = '0' + (min % 10); } time_str[2] = '\0'; LCD_ShowString16x32(64, 100, time_str, COLOR_CYAN, COLOR_BLACK); LCD_ShowStringCentered(150, "AM", COLOR_WHITE, COLOR_BLACK); LCD_ShowStringCentered(195, "VEN 10-07", COLOR_GRAY, COLOR_BLACK); } void Wakeup_Restore(void); 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 为 低电平触发 唤醒 // PxIM1=1, PxIM0=0 → 低电平触发 P0IM1 |= 0x0E; P0IM0 &= ~0x0E; P0INTE |= 0x0E; // 8. 配置 P2.6 (KEY_SOS) 为 低电平触发 唤醒 P2IM1 |= 0x40; P2IM0 &= ~0x40; P2INTE |= 0x40; // ===== 关键新增:配置端口掉电唤醒使能寄存器 PxWKUE ===== // STC32G 在进入 Power-Down (STOP) 模式后,除了开启端口中断外, // 必须使能对应的 PxWKUE 寄存器,硬件唤醒通路才能生效! P0WKUE |= 0x0E; // 使能 P0.1/P0.2/P0.3 掉电唤醒 P2WKUE |= 0x40; // 使能 P2.6 掉电唤醒 // 9. 不允许外部中断 2 (RF_RX_DATA) 沿触发唤醒源 EX2 = 0; // 10. 清除端口中断的悬挂/标志位,防误触 P0INTF = 0x00; P2INTF = 0x00; // 11. 关闭 Timer1 中断,保持 EA=1 让端口中断能唤醒 ET1 = 0; EA = 1; // 12. 写入 PCON 掉电模式位,使 MCU 进入深度 Power-Down 挂起状态 // CPU 在此停止,直到端口低电平中断唤醒 Uart_SendString("[SYS] Entering Power-Down mode...\r\n"); PCON |= 0x02; // PD = 1 _nop_(); _nop_(); _nop_(); _nop_(); // 13. 唤醒并执行完 ISR 后,CPU 从这里继续执行 Wakeup_Restore(); } void Wakeup_Restore(void) { u8 p0_flag; u8 p2_flag; // 确保 EAXFR=1 才能访问扩展 SFR (P0INTF/P2INTF/P0INTE/P2INTE) EAXFR = 1; // [诊断] 在清除标志位之前先读取,判断唤醒来源 p0_flag = P0INTF; p2_flag = P2INTF; // 1. 立即禁用端口中断和唤醒,防止继续触发 P0INTE = 0x00; P2INTE = 0x00; P0WKUE = 0x00; // 清除 P0 唤醒允许 P2WKUE = 0x00; // 清除 P2 唤醒允许 P0INTF = 0x00; P2INTF = 0x00; EX2 = 0; // 1b. 关闭掉电唤醒定时器 WKTCH = 0x00; WKTCL = 0x00; // 2. 重新开启全局中断与 Timer1 中断 EA = 1; ET1 = 1; // [诊断] 打印唤醒来源 if (p0_flag & 0x0E) { Uart_SendString("[WR] Woken by KEY P0 (P0INTF=0x"); Uart_SendHex8(p0_flag); Uart_SendString(")\r\n"); } else if (p2_flag & 0x40) { Uart_SendString("[WR] Woken by KEY P2 (P2INTF=0x"); Uart_SendHex8(p2_flag); Uart_SendString(")\r\n"); } else { Uart_SendString("[WR] Woken by TIMER (no key flag)\r\n"); } // 3. 保持 SHUT 开启射频接收芯片工作 SHUT = 1; // 4. 拉高 SGM_CTRL 并发送脉冲使能 SGM3833 升压 SGM_CTRL = 1; SGM_SendPulse(27); // 5. 等待负压电轨充分稳定 Delay_ms(200); // 6. 重做屏控制器 RM69310 寄存器组的初始化 LCD_Init(); // 7. 重置闲置倒计时 inactivity_timer = 0; // 8. 直接绘制时钟界面(绕过 AppManager 早期返回保护) current_state = STATE_NORMAL; UI_ShowClockPage(current_state, current_hour, current_min); Uart_SendString("[SYS] Wakeup restored!\r\n"); } // 移除了冲突的中断服务函数,采用更健壮的 EA=0 挂起直接继续执行唤醒序列 /* ========================================================================= * 步骤3: 事件分发路由器 (Event_Dispatcher_Loop) * ========================================================================= */ void Event_Dispatcher_Loop(void) { SystemEvent evt = EventQueue_Pop(); if (evt.key_event == KEY_EVENT_NONE && evt.extra_size == 0) { return; } inactivity_timer = 0; // 收到有效按键或无线事件,重置闲置计时器 Uart_SendString("[EVENT] key="); Uart_SendHex8((u8)evt.key_event); Uart_SendString(", pri="); Uart_SendHex8((u8)evt.priority); Uart_SendString("\r\n"); // SOS 按键:仅在当前不处于 SOS 求救模式时触发进入 SOS 状态,否则作为普通按键进行事件分发 if ((evt.key_event == KEY_EVENT_SOS_CLICK || evt.key_event == KEY_EVENT_SOS_LONG) && AppManager_GetActiveAppID() != APP_ID_SOS) { AppManager_StartApp(APP_ID_SOS); return; } // 传感器入侵警报:当前不处于 SOS 求救状态时方可跳转到报警界面 if (evt.priority == EVENT_PRIORITY_HIGH && evt.extra_size >= 4) { u8 slot; if (Check_Sensor_ID(evt.extra_data, &slot)) { if (AppManager_GetActiveAppID() != APP_ID_SOS) { captured_addr = evt.extra_data; alarm_sensor_slot = slot; AppManager_StartApp(APP_ID_ALARM); return; } } } // 无线对码捕获:处于 PAIR 模式下时,将射频事件分发给 PairApp 处理并退出分发 if (evt.priority == EVENT_PRIORITY_NORMAL && evt.extra_size >= 4) { captured_addr = evt.extra_data; captured_type = menu_select; if (AppManager_GetActiveAppID() == APP_ID_PAIR) { AppManager_DispatchEvent(evt); return; } } AppManager_DispatchEvent(evt); } /* ========================================================================= * 定时器 1 (1ms 中断服务 + 按键消抖状态机) * ========================================================================= */ void Timer1_Init(void) { AUXR |= 0x40; TMOD &= 0x0F; { u16 reload = (u16)(65536UL - (MAIN_Fosc / 1000UL)); TL1 = (u8)reload; TH1 = (u8)(reload >> 8); } ET1 = 1; TR1 = 1; EA = 1; } void Timer1_Isr(void) interrupt 3 { SystemEvent evt; ms_tick++; if (ms_tick >= 1000) { ms_tick = 0; current_sec++; if (current_sec >= 60) { current_sec = 0; current_min++; if (current_min >= 60) { current_min = 0; current_hour++; if (current_hour >= 24) current_hour = 0; } clock_updated = 1; } } if (current_state == STATE_PAIR_WAIT) { pair_timeout_ms++; } /* 振动马达定时状态机(仅控制马达,不再控制已被挪用/废弃的 LED) */ if (current_state == STATE_SOS_EMITTED) { alarm_timer_ms++; if (alarm_timer_ms >= 1200) alarm_timer_ms = 0; if (alarm_timer_ms < 1000) MOTOR = 1; else MOTOR = 0; } else if (current_state == STATE_ALARM) { u8 stype = sensor_list[alarm_sensor_slot].type; alarm_timer_ms++; if (alarm_timer_ms >= 5000) alarm_timer_ms = 0; if (stype == 0) { // 门磁警报振动波形 if (alarm_timer_ms < 300) MOTOR = 1; else MOTOR = 0; } else if (stype == 1) { // PIR 警报振动波形 if (alarm_timer_ms < 300) MOTOR = 1; else if (alarm_timer_ms >= 300 && alarm_timer_ms < 500) MOTOR = 0; else if (alarm_timer_ms >= 500 && alarm_timer_ms < 800) MOTOR = 1; else MOTOR = 0; } else if (stype == 2) { // 烟感警报振动波形 if (alarm_timer_ms < 200) MOTOR = 1; else if (alarm_timer_ms >= 200 && alarm_timer_ms < 350) MOTOR = 0; else if (alarm_timer_ms >= 350 && alarm_timer_ms < 550) MOTOR = 1; else if (alarm_timer_ms >= 550 && alarm_timer_ms < 700) MOTOR = 0; else if (alarm_timer_ms >= 700 && alarm_timer_ms < 900) MOTOR = 1; else MOTOR = 0; } else if (stype == 3) { // 气感警报振动波形 if (alarm_timer_ms < 200) MOTOR = 1; else if (alarm_timer_ms >= 200 && alarm_timer_ms < 300) MOTOR = 0; else if (alarm_timer_ms >= 300 && alarm_timer_ms < 500) MOTOR = 1; else if (alarm_timer_ms >= 500 && alarm_timer_ms < 600) MOTOR = 0; else if (alarm_timer_ms >= 600 && alarm_timer_ms < 800) MOTOR = 1; else if (alarm_timer_ms >= 800 && alarm_timer_ms < 900) MOTOR = 0; else if (alarm_timer_ms >= 900 && alarm_timer_ms < 1100) MOTOR = 1; else MOTOR = 0; } else if (stype == 4) { // 水浸警报振动波形 if (alarm_timer_ms < 600) MOTOR = 1; else if (alarm_timer_ms >= 600 && alarm_timer_ms < 900) MOTOR = 0; else if (alarm_timer_ms >= 900 && alarm_timer_ms < 1500) MOTOR = 1; else MOTOR = 0; } else { if (alarm_timer_ms < 300) MOTOR = 1; else MOTOR = 0; } } else { MOTOR = 0; alarm_timer_ms = 0; motor_timer_ms = 0; } alarm_flash_flag = (ms_tick / 100) % 2; /* 按键消抖扫描 (每10ms) */ key_scan_timer++; if (key_scan_timer >= 10) { u8 raw_up = !KEY_UP; u8 raw_down = !KEY_DOWN; u8 raw_confirm = !KEY_CONFIRM; u8 raw_sos = !KEY_SOS; key_scan_timer = 0; // 如果检测到有任何按键按下,清零闲置计时器;否则在非休眠非警报下累加 if (raw_up || raw_down || raw_confirm || raw_sos) { inactivity_timer = 0; } else { if (current_state != STATE_SLEEP && current_state != STATE_ALARM && current_state != STATE_SOS_EMITTED) { inactivity_timer++; } } evt.key_event = KEY_EVENT_NONE; evt.extra_data = 0; evt.extra_size = 0; if (raw_up && raw_down) { comb_hold++; if (comb_hold == 300) { evt.key_event = KEY_EVENT_UP_DOWN_COMB; evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(evt); } key_up_hold = 0; key_down_hold = 0; } else { comb_hold = 0; if (raw_up) { key_up_hold++; if (key_up_hold == 300) { evt.key_event = KEY_EVENT_UP_LONG; evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(evt); } } else { if (key_up_hold >= 2 && key_up_hold < 300) { evt.key_event = KEY_EVENT_UP_CLICK; evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(evt); } key_up_hold = 0; } if (raw_down) { key_down_hold++; if (key_down_hold == 300) { evt.key_event = KEY_EVENT_DOWN_LONG; evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(evt); } } else { if (key_down_hold >= 2 && key_down_hold < 300) { evt.key_event = KEY_EVENT_DOWN_CLICK; evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(evt); } key_down_hold = 0; } if (raw_confirm) { key_confirm_hold++; if (key_confirm_hold == 300) { evt.key_event = KEY_EVENT_CONFIRM_LONG; evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(evt); } } else { if (key_confirm_hold >= 2 && key_confirm_hold < 300) { evt.key_event = KEY_EVENT_CONFIRM_CLICK; evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(evt); } key_confirm_hold = 0; } if (raw_sos) { key_sos_hold++; if (key_sos_hold == 300) { evt.key_event = KEY_EVENT_SOS_LONG; evt.priority = EVENT_PRIORITY_URGENT; EventQueue_InsertFront(evt); } } else { if (key_sos_hold >= 2 && key_sos_hold < 300) { evt.key_event = KEY_EVENT_SOS_CLICK; evt.priority = EVENT_PRIORITY_URGENT; EventQueue_InsertFront(evt); } key_sos_hold = 0; } } } } /* ========================================================================= * 主函数 (事件驱动框架) * ========================================================================= */ void main(void) { u8 last_led_r = 1; u8 last_led_g = 1; u8 last_led_b = 1; u8 last_motor = 0; char cmd; WTST = 0; EAXFR = 1; CKCON = 0; WDT_CONTR = 0x00; GPIO_Init(); RF_Init(); Delay_ms(500); SGM_SendPulse(27); Delay_ms(50); LCD_Init(); Uart1_Init(); Uart_SendString("Wristband System Initialized!\r\n"); Load_Database(); /* 步骤1: 初始化事件队列 */ EventQueue_Init(); /* 步骤2+5: 初始化应用管理器 */ AppManager_Init(); /* 启动1ms定时器中断 */ Timer1_Init(); Uart_SendString("[SYS] Event-driven framework ready\r\n"); while (1) { /* 串口调试命令 → 以事件方式入队 */ cmd = Uart_RxChar(); if (cmd != '\0') { 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; debug_evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(debug_evt); Uart_SendString("[UART] KEY_UP Clicked\r\n"); } else if (cmd == 'U') { debug_evt.key_event = KEY_EVENT_UP_LONG; debug_evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(debug_evt); Uart_SendString("[UART] KEY_UP Long Pressed\r\n"); } else if (cmd == 'd') { debug_evt.key_event = KEY_EVENT_DOWN_CLICK; debug_evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(debug_evt); Uart_SendString("[UART] KEY_DOWN Clicked\r\n"); } else if (cmd == 'D') { debug_evt.key_event = KEY_EVENT_DOWN_LONG; debug_evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(debug_evt); Uart_SendString("[UART] KEY_DOWN Long Pressed\r\n"); } else if (cmd == 's') { debug_evt.key_event = KEY_EVENT_SOS_CLICK; debug_evt.priority = EVENT_PRIORITY_URGENT; EventQueue_InsertFront(debug_evt); Uart_SendString("[UART] KEY_SOS Clicked\r\n"); } else if (cmd == 'S') { debug_evt.key_event = KEY_EVENT_SOS_LONG; debug_evt.priority = EVENT_PRIORITY_URGENT; EventQueue_InsertFront(debug_evt); Uart_SendString("[UART] KEY_SOS Long Pressed\r\n"); } else if (cmd == 'c' || cmd == 'C') { debug_evt.key_event = KEY_EVENT_UP_DOWN_COMB; debug_evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(debug_evt); Uart_SendString("[UART] KEY_UP+DOWN Combined\r\n"); } else if (cmd == 'a' || cmd == 'A') { u32 mock_addr = 0x123456; u8 mock_slot; if (!Check_Sensor_ID(mock_addr, &mock_slot)) { Add_Sensor_With_Zone(mock_addr, 0, 1); } debug_evt.key_event = KEY_EVENT_NONE; debug_evt.priority = EVENT_PRIORITY_HIGH; debug_evt.extra_data = mock_addr; debug_evt.extra_size = 4; EventQueue_InsertFront(debug_evt); Uart_SendString("[UART] Mock RF Alarm\r\n"); } else if (cmd == 'p' || cmd == 'P') { if (AppManager_GetActiveAppID() == APP_ID_PAIR) { debug_evt.key_event = KEY_EVENT_NONE; debug_evt.priority = EVENT_PRIORITY_NORMAL; debug_evt.extra_data = 0x789ABC; debug_evt.extra_size = 4; EventQueue_Push(debug_evt); Uart_SendString("[UART] Mock RF Pair Signal\r\n"); } else { Uart_SendString("[UART] Not in PAIR mode\r\n"); } } else if (cmd == '1') { if (AppManager_GetActiveAppID() == APP_ID_CLOCK) { current_state = STATE_NORMAL; UI_ShowClockPage(current_state, current_hour, current_min); } Uart_SendString("[UART] State: NORMAL\r\n"); } else if (cmd == '2') { if (AppManager_GetActiveAppID() == APP_ID_CLOCK) { current_state = STATE_ARMED; UI_ShowClockPage(current_state, current_hour, current_min); } Uart_SendString("[UART] State: ARMED\r\n"); } else if (cmd == '3') { if (AppManager_GetActiveAppID() == APP_ID_CLOCK) { current_state = STATE_DISARMED; UI_ShowClockPage(current_state, current_hour, current_min); } Uart_SendString("[UART] State: DISARMED\r\n"); } else if (cmd == 'z' || cmd == 'Z') { inactivity_timer = 1000; // 模拟闲置超时,强制触发休眠 Uart_SendString("[UART] Force Entering Sleep mode!\r\n"); } } /* 步骤3: 事件分发 — 循环处理队列中所有事件 */ while (!EventQueue_IsEmpty()) { Event_Dispatcher_Loop(); } /* 步骤5: 运行活跃应用 (含CPU占用控制) */ AppManager_RunActiveApp(); /* 步骤6: 超时自动进入深度休眠 */ if (inactivity_timer >= 1000) { inactivity_timer = 0; current_state = STATE_SLEEP; Enter_Low_Power_Sleep(); } } } /* ========================================================================= * GPIO 初始化 * ========================================================================= */ 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)); } // ========================================================================= // STC32G 端口中断 ISR // 说明:STC32G 的 Port0 (向量 37) / Port2 (向量 39) 超过 Keil C251 // 支持的 0~31 范围,无法直接用 interrupt 37/39 声明。 // 因此通过 App/isr_jump.asm 在硬件绝对向量地址处放置 LJMP, // 将 Port0 向量 → interrupt 13 入口 (0x006BH) // 将 Port2 向量 → interrupt 15 入口 (0x007BH) // 以此实现 Keil C251 可正确编译链接的中断服务函数。 // ========================================================================= // Port0 中断服务函数 (由 isr_jump.asm 从向量 37 @ 0x012BH 跳转至此) void Port0_Isr(void) interrupt 13 { // 关键:P0INTF/P0INTE 是 far 扩展 SFR,写入前必须确保 EAXFR=1 EAXFR = 1; P0INTF = 0x00; // 清除 P0 端口中断悬挂标志 P0INTE = 0x00; // 立即禁用,防止低电平保持期间反复触发 } // Port2 中断服务函数 (由 isr_jump.asm 从向量 39 @ 0x013BH 跳转至此) void Port2_Isr(void) interrupt 15 { // 关键:P2INTF/P2INTE 是 far 扩展 SFR,写入前必须确保 EAXFR=1 EAXFR = 1; P2INTF = 0x00; // 清除 P2 端口中断悬挂标志 P2INTE = 0x00; // 立即禁用,防止低电平保持期间反复触发 }