#include "stc32g.h" #include "intrins.h" #include "config.h" #include "event.h" #include "appmgr.h" #include "../Drivers/lcd.h" #include "../Drivers/rf.h" /* ========================================================================= * 硬件引脚与全局变量定义 * ========================================================================= */ // 软件虚拟 LED 状态变量(0表示亮,1表示灭,兼容原有代码逻辑) bit LED_R = 1; bit LED_G = 1; bit LED_B = 1; bit last_hw_r = 1; bit last_hw_g = 1; bit last_hw_b = 1; bit rgb_test_mode = 0; // 实际 WS2812 物理控制引脚(接 P0.0) sbit WS2812_DI = P2^3; // 振动马达控制引脚(输出1开启振动,输出0停止) sbit MOTOR = P2^5; // 板载独立按键(按下时为低电平,利用内部上拉电阻) sbit KEY_UP = P0^1; // SW1 按键 sbit KEY_SOS = P0^2; // SW3 按键 sbit KEY_DOWN = P0^3; // SW2 按键 // 系统运行状态变量与时钟 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; // 对码菜单选中的传感器类型索引 (0~4) u32 captured_addr = 0; // 射频接收捕获到的临时24位地址码 u8 captured_type = 0; // 射频接收捕获到的临时传感器类型 u8 alarm_sensor_slot = 0; // 正在报警的传感器槽位索引 // 传感器配对记录表 (16组槽位,保存在 xdata 中,防内存溢出) Sensor_Slot xdata sensor_list[16]; // 系统软件计数滴答(由定时器1 ms中断累加维护) volatile u16 ms_tick = 0; // 毫秒计数器 (0~999) volatile u32 pair_timeout_ms = 0; // 对码等待超时计数器 (最大 30000ms) volatile u16 alarm_timer_ms = 0; // 警报声光闪烁定时器 volatile u16 motor_timer_ms = 0; // 马达振动波形定时器 volatile bit alarm_flash_flag = 0; // 闪烁标志状态位 // 独立按键消抖、长按与组合判定的软件计数器 volatile u16 key_scan_timer = 0; // 10ms按键扫描定时计数器 volatile u16 key_up_hold = 0; // SW1按键按下维持时间 (单位: 10ms) volatile u16 key_down_hold = 0; // SW2按键按下维持时间 (单位: 10ms) volatile u16 key_sos_hold = 0; // SW3按键按下维持时间 (单位: 10ms) volatile u16 comb_hold = 0; // SW1+SW2组合键按下维持时间 (单位: 10ms) volatile KeyEvent key_event_buf = KEY_EVENT_NONE; // 按键事件缓冲区 /* ========================================================================= * 辅助映射表及前置声明 * ========================================================================= */ // 各防区类型的默认法语防区名称 (供报警显示使用,最大15字符) char *code default_names[5] = { "PORTE ENTREE", // 0: 门磁 "SALON PIR", // 1: 红外 "CUISINE FUMEE", // 2: 烟感 "CUISINE GAZ", // 3: 燃气 "SDB EAU" // 4: 水浸 }; // 各防区类型的默认防区类别 (0: 24小时防区-撤防亦报警, 1: 普通防区-仅布防下报警) u8 code default_zones[5] = {1, 1, 0, 0, 0}; // 对码选择菜单显示的各条目字符串 (法语,最大15字符) char *code menu_items[5] = { "DETEC. PORTE", // 0 "DETEC. PIR", // 1 "DETEC. FUMEE", // 2 "DETEC. GAZ", // 3 "DETEC. EAU" // 4 }; // 本地函数前置声明 void Delay10us(void); 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 Format_Sensor_Name(u8 slot, char *buf); // IAP 闪存读写底层声明 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(u32 addr, u8 type); bit Check_Sensor_ID(u32 addr, u8 *out_slot_index); // UI 绘制层接口声明 void UI_ShowClockPage(SystemState state, u8 hour, u8 min); void UI_ShowPairMenuPage(u8 selected_index); void UI_ShowPairWaitPage(u8 frame_index); void UI_ShowPairConfirmPage(u32 addr); void UI_ShowPairSuccessPage(u32 addr); void UI_ShowPairFailPage(u8 is_timeout); void UI_ShowAlarmPage(char *sensor_name, u8 zone); void UI_ShowSosPage(void); /* ========================================================================= * WS2812B 幻彩 LED 单线驱动函数 (24MHz 1T 模式下精准时序控制) * ========================================================================= */ const u16 code SPI_LUT[16] = { 0x924, 0x926, 0x934, 0x936, 0x9A4, 0x9A6, 0x9B4, 0x9B6, 0xD24, 0xD26, 0xD34, 0xD36, 0xDA4, 0xDA6, 0xDB4, 0xDB6 }; void WS2812_EncodeByte(u8 v, u8 *buf) { u16 p1 = SPI_LUT[v >> 4]; u16 p2 = SPI_LUT[v & 0x0F]; buf[0] = p1 >> 4; buf[1] = ((p1 & 0x0F) << 4) | (p2 >> 8); buf[2] = p2; } void WS2812_Write24Bit(u8 g, u8 r, u8 b) { u8 data buf[10]; u8 b0, b1, b2, b3, b4, b5, b6, b7, b8, b9; buf[0] = 0x00; // Prepend dummy 0x00 to absorb SPI hardware startup delay/glitch WS2812_EncodeByte(g, &buf[1]); WS2812_EncodeByte(r, &buf[4]); WS2812_EncodeByte(b, &buf[7]); b0 = buf[0]; b1 = buf[1]; b2 = buf[2]; b3 = buf[3]; b4 = buf[4]; b5 = buf[5]; b6 = buf[6]; b7 = buf[7]; b8 = buf[8]; b9 = buf[9]; EA = 0; // Ensure P2.3 (MOSI) and P2.5 (SCLK) are configured as push-pull output P2M1 &= ~((1 << 3) | (1 << 5)); P2M0 |= ((1 << 3) | (1 << 5)); SPSTAT = 0xC0; // Clear flags first SPDAT = b0; // Write data first! SPCTL = 0xD0; // Enable SPI after writing data. Should start shifting b0 immediately! // Unrolled 10-byte transmission with minimal gap (~300ns) while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b1; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b2; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b3; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b4; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b5; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b6; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b7; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b8; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPDAT = b9; while (!(SPSTAT & 0x80)); SPSTAT = 0xC0; SPCTL = 0x90; // Disable SPI WS2812_DI = 0; MOTOR = 0; // Ensure motor is off EA = 1; } void WS2812_Reset(void) { SPCTL = 0x90; WS2812_DI = 0; { u8 i; for (i = 0; i < 10; i++) { Delay10us(); } } } 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; // 满足 24M 下时钟宽度 while(--i); } // 保证 16 位定时器 TH/TL 在读取时的原子性,防止在溢出瞬间读取出错 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; // 启动 T0 计数器 while (GetTimer0_Safe() < ticks); TR0 = 0; // 停止计数 } /* ========================================================================= * STC32G 闪存 IAP (EEPROM) 读写逻辑 * ========================================================================= */ #define IAP_CMD_READ 1 #define IAP_CMD_WRITE 2 #define IAP_CMD_ERASE 3 // 关闭 IAP 功能,恢复 SFR 安全状态 void IAP_Disable(void) { IAP_CONTR = 0; IAP_CMD = 0; IAP_TRIG = 0; IAP_ADDRH = 0xff; IAP_ADDRL = 0xff; } // 从指定 IAP 地址读取一个字节 u8 IAP_ReadByte(u16 addr) { IAP_CONTR = 0x80; // 启用 IAP 功能 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; } // 往指定 IAP 地址写入一个字节 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(); } // 擦除指定地址所在的 512 字节 IAP 扇区 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(); } // 从 IAP 的 Sector 0 载入配对列表数据 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++); } } // 将配对列表保存到 IAP 的 Sector 0 中 (先擦除再逐字节写入) void Save_Database(void) { u16 addr = 0; u8 *ptr = (u8 *)&sensor_list; u16 size = sizeof(sensor_list); u16 i; IAP_EraseSector(0); // 擦除物理 Sector 0 for (i = 0; i < size; i++) { IAP_WriteByte(addr++, ptr[i]); } } // 添加或覆盖传感器对码数据并自动存入 EEPROM void Add_Sensor(u32 addr, u8 type) { u8 i; u8 slot_to_use = 15; // 若槽位已满,默认覆盖最后一个位置 u8 suffix = 1; u32 db_addr = (addr << 4) | (type & 0x0F); // 查找是否有空余位置,或者该 ID 已经配对过 for (i = 0; i < 16; i++) { if ((sensor_list[i].flags_suffix & 0x80) == 0x80) { 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 >> 4) == addr) { slot_to_use = i; break; } } else { slot_to_use = i; break; } } // 动态计算同类型传感器的后缀序号 (如果不是覆盖已有设备) if ((sensor_list[slot_to_use].flags_suffix & 0x80) != 0x80) { for (i = 0; i < 16; i++) { if ((sensor_list[i].flags_suffix & 0x80) == 0x80) { 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 & 0x0F) == type) { suffix++; } } } } else { // 覆盖已有设备时,保留原有后缀序号 suffix = sensor_list[slot_to_use].flags_suffix & 0x7F; } // 写入防区各项核心数据 sensor_list[slot_to_use].flags_suffix = 0x80 | (suffix & 0x7F); sensor_list[slot_to_use].addr[0] = (u8)(db_addr >> 16); sensor_list[slot_to_use].addr[1] = (u8)(db_addr >> 8); sensor_list[slot_to_use].addr[2] = (u8)db_addr; Save_Database(); // 立即同步存盘 } // 检查某个接收到的 24 位地址是否已注册,若成功返回槽位索引 bit Check_Sensor_ID(u32 addr, u8 *out_slot_index) { u8 i; for (i = 0; i < 16; i++) { if ((sensor_list[i].flags_suffix & 0x80) == 0x80) { 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 >> 4) == addr) { *out_slot_index = i; return 1; // 匹配成功 } } } return 0; // 未在对码列表中找到 } /* ========================================================================= * 串口调试驱动 (用于捕获输出及测试打印) * ========================================================================= */ void Uart1_Init(void) { u16 reload = (u16)(65536UL - (MAIN_Fosc / 4 / 115200UL)); SCON = 0x50; // 8位可变波特率 AUXR |= 0x01; // 定时器2作为波特率发生器 AUXR |= 0x04; // 定时器2为 1T 模式 T2L = (u8)reload; T2H = (u8)(reload >> 8); AUXR |= 0x10; // 启动定时器2 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 Format_Sensor_Name(u8 slot, char *buf) { u8 i = 0; u32 slot_addr = ((u32)sensor_list[slot].addr[0] << 16) | ((u32)sensor_list[slot].addr[1] << 8) | sensor_list[slot].addr[2]; u8 type = slot_addr & 0x0F; u8 suffix = sensor_list[slot].flags_suffix & 0x7F; char *name_prefix = (type < 5) ? default_names[type] : "SENSOR"; while (name_prefix[i] != '\0' && i < 15) { buf[i] = name_prefix[i]; i++; } buf[i++] = ' '; buf[i++] = '0' + (suffix / 10); buf[i++] = '0' + (suffix % 10); buf[i] = '\0'; } /* ========================================================================= * UI 页面渲染函数 * ========================================================================= */ void UI_ShowClockPage(SystemState state, u8 hour, u8 min) { char time_str[6]; LCD_Clear(COLOR_BLACK); // 右上角电量指示 (调整坐标防止贴在一起) LCD_DrawMonoBitmap(92, 27, 20, 10, bmp_battery_20x10, COLOR_GRAY, COLOR_BLACK); LCD_ShowString(62, 24, "85%", COLOR_GRAY, COLOR_BLACK); // 2x 放大绘制当前时钟 (无显存双倍行/列插值算法) 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, (state == STATE_ARMED) ? COLOR_WHITE : ((state == STATE_DISARMED) ? COLOR_WHITE : COLOR_CYAN), COLOR_BLACK); // 静态星期和日期 (法语 JEU) LCD_ShowStringCentered(155, "JEU 07-02", COLOR_GRAY, COLOR_BLACK); // 屏幕底端布撤防状态标识 (Y=202 避开屏幕下圆弧) if(state == STATE_ARMED) { LCD_DrawMonoBitmap(32, 202, 16, 16, bmp_lock_16x16, COLOR_RED, COLOR_BLACK); LCD_ShowString(52, 202, "ARME", COLOR_RED, COLOR_BLACK); } else if(state == STATE_DISARMED) { LCD_DrawMonoBitmap(22, 202, 16, 16, bmp_unlock_16x16, COLOR_GREEN, COLOR_BLACK); LCD_ShowString(42, 202, "DESARME", COLOR_GREEN, 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) { // 雷达扫描:仅局部擦除并重新绘制雷达波纹,消除整屏清屏带来的闪烁 if(frame_index == 0) LCD_DrawMonoBitmap(44, 56, 32, 32, bmp_radar_32x32_f1, COLOR_CYAN, COLOR_BLACK); else if(frame_index == 1) LCD_DrawMonoBitmap(44, 56, 32, 32, bmp_radar_32x32_f2, COLOR_CYAN, COLOR_BLACK); else LCD_DrawMonoBitmap(44, 56, 32, 32, bmp_radar_32x32_f3, COLOR_CYAN, COLOR_BLACK); } void UI_ShowPairConfirmPage(u32 addr) { char hex_str[15]; LCD_Clear(COLOR_BLACK); LCD_DrawRectBorder(4, 4, 112, 232, COLOR_GRAY); LCD_DrawMonoBitmap(44, 60, 32, 32, bmp_confirm_lock_32x32, COLOR_AMBER, COLOR_BLACK); LCD_ShowStringCentered(135, "CODE TROUVE", COLOR_WHITE, COLOR_BLACK); LCD_ShowStringCentered(160, "MAINTENIR SOS", COLOR_AMBER, COLOR_BLACK); FormatHex(addr, hex_str); LCD_ShowStringCentered(185, hex_str, COLOR_GRAY, COLOR_BLACK); } void UI_ShowPairSuccessPage(u32 addr) { char hex_str[15]; LCD_Clear(COLOR_BLACK); LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_checkmark_32x32, COLOR_GREEN, COLOR_BLACK); LCD_ShowStringCentered(135, "SUCCES APPAI.", COLOR_GREEN, COLOR_BLACK); FormatHex(addr, hex_str); LCD_ShowStringCentered(165, hex_str, 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); if (is_timeout) { LCD_ShowStringCentered(145, "DELAI DEPASSE", COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(170, "AUCUN SIGNAL", COLOR_GRAY, COLOR_BLACK); } else { LCD_ShowStringCentered(145, "ECHEC APPAI.", COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(170, "TYPE INCORRECT", COLOR_GRAY, COLOR_BLACK); } } void UI_ShowAlarmPage(char *sensor_name, u8 zone) { char zone_str[20]; LCD_Clear(COLOR_BLACK); LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED); LCD_DrawMonoBitmap(44, 55, 32, 32, bmp_door_32x32, COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(120, sensor_name, COLOR_RED, COLOR_BLACK); zone_str[0] = 'Z'; zone_str[1] = 'O'; zone_str[2] = 'N'; zone_str[3] = 'E'; zone_str[4] = ' '; zone_str[5] = '0' + zone; zone_str[6] = ' '; zone_str[7] = '|'; zone_str[8] = ' '; zone_str[9] = 'A'; zone_str[10] = 'L'; zone_str[11] = 'A'; zone_str[12] = 'R'; zone_str[13] = 'M'; zone_str[14] = 'E'; zone_str[15] = '\0'; LCD_ShowStringCentered(155, zone_str, COLOR_WHITE, COLOR_BLACK); } void UI_ShowSosPage(void) { LCD_Clear(COLOR_BLACK); LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED); LCD_DrawRectBorder(8, 8, 104, 224, COLOR_WHITE); LCD_DrawMonoBitmap(44, 55, 32, 32, bmp_siren_32x32, COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(125, "SOS EMIS", COLOR_RED, COLOR_BLACK); LCD_ShowStringCentered(155, "BRACELET ACTIF", COLOR_WHITE, COLOR_BLACK); } void UI_ShowBindingPage(void) { LCD_Clear(COLOR_BLACK); LCD_DrawRectBorder(4, 4, 112, 232, COLOR_CYAN); LCD_DrawMonoBitmap(44, 60, 32, 32, bmp_confirm_lock_32x32, COLOR_CYAN, COLOR_BLACK); LCD_ShowStringCentered(135, "LIAISON IPC", COLOR_WHITE, COLOR_BLACK); LCD_ShowStringCentered(160, "ENVOI EN COURS", COLOR_CYAN, COLOR_BLACK); } /* ========================================================================= * 定时器 1 (1ms 中断服务,包含消抖状态机) * ========================================================================= */ void Timer1_Init(void) { AUXR |= 0x40; // 1T 模式,不分频 TMOD &= 0x0F; // 16位自动重装载 { u16 reload = (u16)(65536UL - (MAIN_Fosc / 1000UL)); TL1 = (u8)reload; TH1 = (u8)(reload >> 8); } ET1 = 1; // 使使能中断 TR1 = 1; // 启动定时器 EA = 1; // 开启全局总中断 } // 1ms 时钟嘀嗒与按键扫描服务中断 void Timer1_Isr(void) interrupt 3 { // 1. 累加时间滴答并进位,维护软件RTC 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; } } // 通过事件队列通知时钟应用分钟变化 { SystemEvent evt; evt.key_event = KEY_EVENT_NONE; evt.priority = EVENT_PRIORITY_LOW; evt.extra_data = ((u32)current_hour << 8) | current_min; evt.extra_size = 2; EventQueue_Push(evt); } } } // 2. 雷达对码扫描倒计时 (30秒超时自动回弹待机) if (current_state == STATE_PAIR_WAIT) { pair_timeout_ms++; } // 3. 警报警示声光发生器逻辑 if (rgb_test_mode) { // RGB 测试模式下不更新虚拟 LED 状态,交由主循环串口命令控制 } else if (current_state == STATE_SOS_EMITTED) { // SOS 特殊告警:LED 红色极速闪烁 (5Hz),马达持续进行 1200ms 循环长振 u8 sos_flash = (ms_tick / 100) % 2; // 5Hz -> 100ms 翻转一次 LED_R = sos_flash ? 0 : 1; LED_G = 1; LED_B = 1; alarm_timer_ms++; if (alarm_timer_ms >= 1200) alarm_timer_ms = 0; if (alarm_timer_ms < 1000) MOTOR = 1; // 长振 1000ms else MOTOR = 0; // 停 200ms } else if (current_state == STATE_ALARM) { // 传感器告警模式:根据不同传感器类型执行专属灯光颜色与特定振动模式 u8 stype = (((u32)sensor_list[alarm_sensor_slot].addr[0] << 16) | ((u32)sensor_list[alarm_sensor_slot].addr[1] << 8) | sensor_list[alarm_sensor_slot].addr[2]) & 0x0F; alarm_timer_ms++; if (alarm_timer_ms >= 5000) alarm_timer_ms = 0; // 5秒周期循环 if (stype == 0) // 门磁/窗磁:红色,1次短振 300ms { LED_R = 0; LED_G = 1; LED_B = 1; if (alarm_timer_ms < 300) MOTOR = 1; else MOTOR = 0; } else if (stype == 1) // 人体感应 PIR:黄色/橙色,2次短振 300ms (间隔 200ms) { LED_R = 0; LED_G = 0; LED_B = 1; 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) // 烟雾传感器:绿色,3次短振 200ms (间隔 150ms) { LED_R = 1; LED_G = 0; LED_B = 1; 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) // 气体传感器:紫色,4次短振 200ms (间隔 100ms) { LED_R = 0; LED_G = 1; LED_B = 0; 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) // 水浸传感器:黄色,2次长振 600ms (间隔 300ms) { LED_R = 0; LED_G = 0; LED_B = 1; 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 { // 其他未知类型默认红色闪烁 u8 flash = (ms_tick / 500) % 2; LED_R = flash ? 0 : 1; LED_G = 1; LED_B = 1; if (alarm_timer_ms < 300) MOTOR = 1; else MOTOR = 0; } } else if (current_state == STATE_PAIR_WAIT || current_state == STATE_PAIR_CONFIRM) { // 白色快闪 (3Hz): 166ms 翻转一次 (仅在搜索和确认时开启) u16 pair_flash_cnt = ms_tick % 333; if (pair_flash_cnt < 166) { LED_R = 0; LED_G = 0; LED_B = 0; // 白色 (R+G+B 开启) } else { LED_R = 1; LED_G = 1; LED_B = 1; // 熄灭 } MOTOR = 0; } else { MOTOR = 0; LED_R = 1; LED_G = 1; LED_B = 1; alarm_flash_flag = 0; alarm_timer_ms = 0; motor_timer_ms = 0; } // 4. 按键防抖与时间累加 (每 10ms 进行一次逻辑检测) key_scan_timer++; if (key_scan_timer >= 10) { // 物理引脚低电平有效,转换成逻辑高有效状态进行判定 (用 u8 代替 bit 作为局部变量,在块开头声明变量以符合 C90 规范) u8 raw_up = !KEY_UP; u8 raw_down = !KEY_DOWN; u8 raw_sos = !KEY_SOS; key_scan_timer = 0; // 组合键检测:UP+DOWN 同时长按 3 秒 (300 * 10ms = 3000ms) if (raw_up && raw_down) { comb_hold++; if (comb_hold == 300) { key_event_buf = KEY_EVENT_UP_DOWN_COMB; } key_up_hold = 0; key_down_hold = 0; } else { comb_hold = 0; // 检测上键 UP if (raw_up) { key_up_hold++; if (key_up_hold == 300) // 达到 3.0 秒触发长按事件 { key_event_buf = KEY_EVENT_UP_LONG; } } else { if (key_up_hold >= 2 && key_up_hold < 300) // 抬手时判定为单击事件 { key_event_buf = KEY_EVENT_UP_CLICK; } key_up_hold = 0; } // 检测下键 DOWN if (raw_down) { key_down_hold++; if (key_down_hold == 300) // 达到 3.0 秒触发长按事件 { key_event_buf = KEY_EVENT_DOWN_LONG; } } else { if (key_down_hold >= 2 && key_down_hold < 300) // 抬手时判定为单击事件 { key_event_buf = KEY_EVENT_DOWN_CLICK; } key_down_hold = 0; } // 检测紧急 SOS 键 if (raw_sos) { key_sos_hold++; if (key_sos_hold == 300) // 长按 3.0 秒 { // 在对码确认状态下,长按 3 秒即可触发保存 if (current_state == STATE_PAIR_CONFIRM) { key_event_buf = KEY_EVENT_SOS_LONG; } } else if (key_sos_hold == 500) // 长按 5.0 秒 { // 在常态待机防区下,长按 5 秒触发求救发射 if (current_state == STATE_NORMAL || current_state == STATE_ARMED || current_state == STATE_DISARMED) { key_event_buf = KEY_EVENT_SOS_LONG; } } } else { if (key_sos_hold >= 2 && key_sos_hold < 300) // 抬手时判定为短按事件 { key_event_buf = KEY_EVENT_SOS_CLICK; } key_sos_hold = 0; } } } // 5. WS2812B 实际硬件驱动刷新 (当虚拟 LED 寄存器发生变化时) if (LED_R != last_hw_r || LED_G != last_hw_g || LED_B != last_hw_b) { last_hw_r = LED_R; last_hw_g = LED_G; last_hw_b = LED_B; WS2812_Write24Bit(LED_G ? 0 : 255, LED_R ? 0 : 255, LED_B ? 0 : 255); WS2812_Reset(); } } /* ========================================================================= * 外部声明:应用注册函数 * ========================================================================= */ extern void Apps_RegisterAll(void); /* ========================================================================= * 时钟更新回调:在定时器中断中触发,通知时钟应用重绘 * ========================================================================= */ void ClockApp_NotifyUpdate(void) { // 通过事件队列通知时钟应用分钟变化 SystemEvent evt; evt.key_event = KEY_EVENT_NONE; evt.priority = EVENT_PRIORITY_LOW; evt.extra_data = ((u32)current_hour << 8) | current_min; evt.extra_size = 2; EventQueue_Push(evt); } /* ========================================================================= * 系统主循环逻辑 (事件驱动框架核心) * ========================================================================= */ void main(void) { SystemEvent evt; char cmd; u8 last_led_r = 1; u8 last_led_g = 1; u8 last_led_b = 1; u8 last_motor = 0; // 单片机时钟与看门狗基础初始化 WTST = 0; EAXFR = 1; CKCON = 0; WDT_CONTR = 0x00; // 外设 GPIO 及射频接口引脚初始化 GPIO_Init(); RF_Init(); Delay_ms(500); // 唤醒 AMOLED 屏幕及供电调频芯片 SGM_SendPulse(27); Delay_ms(50); // 初始化显示屏驱动与命令 LCD_Init(); // 配置 Uart 用于后台诊断输出 Uart1_Init(); Uart_SendString("Wristband System Initialized!\r\n"); // 读入掉电保存的对码表数据,并启动 1ms 中断调度引擎 Load_Database(); Timer1_Init(); // 初始化事件队列和应用管理器 EventQueue_Init(); Apps_RegisterAll(); AppManager_Init(); Uart_SendString("[FRAMEWORK] Event-driven framework started\r\n"); while(1) { // 串口调试与物理引脚/器件仿真输入 cmd = Uart_RxChar(); if (cmd != '\0') { SystemEvent sys_evt; sys_evt.priority = EVENT_PRIORITY_NORMAL; sys_evt.extra_data = 0; sys_evt.extra_size = 0; if (cmd == 'u') { sys_evt.key_event = KEY_EVENT_UP_CLICK; EventQueue_Push(sys_evt); Uart_SendString("[UART SIM] KEY_UP Clicked\r\n"); } else if (cmd == 'U') { sys_evt.key_event = KEY_EVENT_UP_LONG; EventQueue_Push(sys_evt); Uart_SendString("[UART SIM] KEY_UP Long Pressed\r\n"); } else if (cmd == 'd') { sys_evt.key_event = KEY_EVENT_DOWN_CLICK; EventQueue_Push(sys_evt); Uart_SendString("[UART SIM] KEY_DOWN Clicked\r\n"); } else if (cmd == 'D') { sys_evt.key_event = KEY_EVENT_DOWN_LONG; EventQueue_Push(sys_evt); Uart_SendString("[UART SIM] KEY_DOWN Long Pressed\r\n"); } else if (cmd == 's') { sys_evt.key_event = KEY_EVENT_SOS_CLICK; sys_evt.priority = EVENT_PRIORITY_URGENT; EventQueue_EmergencyDispatch(sys_evt); Uart_SendString("[UART SIM] KEY_SOS Clicked (Emergency)\r\n"); } else if (cmd == 'S') { sys_evt.key_event = KEY_EVENT_SOS_LONG; sys_evt.priority = EVENT_PRIORITY_URGENT; EventQueue_EmergencyDispatch(sys_evt); Uart_SendString("[UART SIM] KEY_SOS Long Pressed (Emergency)\r\n"); } else if (cmd == 'c' || cmd == 'C') { sys_evt.key_event = KEY_EVENT_UP_DOWN_COMB; EventQueue_Push(sys_evt); Uart_SendString("[UART SIM] KEY_UP + KEY_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(mock_addr, 0); } captured_addr = mock_addr; alarm_sensor_slot = mock_slot; sys_evt.key_event = KEY_EVENT_NONE; sys_evt.priority = EVENT_PRIORITY_HIGH; sys_evt.extra_data = mock_addr; sys_evt.extra_size = 4; EventQueue_Push(sys_evt); AppManager_StartApp(APP_ID_ALARM); Uart_SendString("[UART SIM] Mock RF Alarm: ADDR 0x123456\r\n"); } else if (cmd == 'p' || cmd == 'P') { // 模拟配对信号 captured_addr = 0x789ABC; captured_type = 0; sys_evt.key_event = KEY_EVENT_NONE; sys_evt.priority = EVENT_PRIORITY_NORMAL; sys_evt.extra_data = 0x789ABC; sys_evt.extra_size = 4; EventQueue_Push(sys_evt); Uart_SendString("[UART SIM] Mock RF Pair Signal: ADDR 0x789ABC\r\n"); } else if (cmd == 't' || cmd == 'T') { Uart_SendString("[UART SIM] SPI 3MHz Clock Test on P2.5 (SCLK) and P2.3 (MOSI) active. Press reset to exit.\r\n"); P2M1 &= ~((1 << 3) | (1 << 5)); P2M0 |= ((1 << 3) | (1 << 5)); SPCTL = 0xD0; while(1) { SPSTAT = 0xC0; SPDAT = 0xAA; while (!(SPSTAT & 0x80)); } } else if (cmd == '1') { AppManager_StartApp(APP_ID_CLOCK); Uart_SendString("[UART SIM] Set Active App to: Clock\r\n"); } else if (cmd == '2') { current_state = STATE_ARMED; Uart_SendString("[UART SIM] Set State to: ARMED\r\n"); } else if (cmd == '3') { current_state = STATE_DISARMED; Uart_SendString("[UART SIM] Set State to: DISARMED\r\n"); } else if (cmd == '4') { rgb_test_mode = 1; LED_R = 0; LED_G = 1; LED_B = 1; Uart_SendString("[UART SIM] RGB Test -> RED\r\n"); } else if (cmd == '5') { rgb_test_mode = 1; LED_R = 1; LED_G = 0; LED_B = 1; Uart_SendString("[UART SIM] RGB Test -> GREEN\r\n"); } else if (cmd == '6') { rgb_test_mode = 1; LED_R = 1; LED_G = 1; LED_B = 0; Uart_SendString("[UART SIM] RGB Test -> BLUE\r\n"); } else if (cmd == '7') { rgb_test_mode = 1; LED_R = 0; LED_G = 0; LED_B = 1; Uart_SendString("[UART SIM] RGB Test -> YELLOW\r\n"); } else if (cmd == '8') { rgb_test_mode = 1; LED_R = 0; LED_G = 1; LED_B = 0; Uart_SendString("[UART SIM] RGB Test -> PURPLE\r\n"); } else if (cmd == '9') { rgb_test_mode = 1; LED_R = 1; LED_G = 0; LED_B = 0; Uart_SendString("[UART SIM] RGB Test -> CYAN\r\n"); } else if (cmd == '0') { rgb_test_mode = 1; LED_R = 0; LED_G = 0; LED_B = 0; Uart_SendString("[UART SIM] RGB Test -> WHITE\r\n"); } else if (cmd == 'f' || cmd == 'F') { rgb_test_mode = 0; LED_R = 1; LED_G = 1; LED_B = 1; Uart_SendString("[UART SIM] RGB Test -> OFF\r\n"); } } // 1. 处理按键事件缓冲区(来自定时器中断) if (key_event_buf != KEY_EVENT_NONE) { rgb_test_mode = 0; SystemEvent sys_evt; sys_evt.key_event = key_event_buf; sys_evt.extra_data = 0; sys_evt.extra_size = 0; // 设置事件优先级 if (key_event_buf == KEY_EVENT_SOS_CLICK || key_event_buf == KEY_EVENT_SOS_LONG) { sys_evt.priority = EVENT_PRIORITY_URGENT; // 紧急事件直接分发,跳过队列 EventQueue_EmergencyDispatch(sys_evt); } else { sys_evt.priority = EVENT_PRIORITY_NORMAL; EventQueue_Push(sys_evt); } key_event_buf = KEY_EVENT_NONE; } // 2. 处理事件队列中的事件 while (!EventQueue_IsEmpty()) { evt = EventQueue_Pop(); if (evt.key_event != KEY_EVENT_NONE || evt.priority != EVENT_PRIORITY_LOW) { Uart_SendString("[EVENT] Processing event: "); Uart_SendHex8((u8)evt.key_event); Uart_SendString(" Priority: "); Uart_SendHex8((u8)evt.priority); Uart_SendString("\r\n"); AppManager_DispatchEvent(evt); } } // 3. 运行当前活跃应用的 onRun 回调(带CPU占用控制) AppManager_RunActiveApp(); // 4. 仿真 LED/马达状态串口输出 if (LED_R != last_led_r || LED_G != last_led_g || LED_B != last_led_b) { last_led_r = LED_R; last_led_g = LED_G; last_led_b = LED_B; Uart_SendString("[STATE] LED status -> R:"); Uart_SendByte(last_led_r ? '0' : '1'); Uart_SendString(" G:"); Uart_SendByte(last_led_g ? '0' : '1'); Uart_SendString(" B:"); Uart_SendByte(last_led_b ? '0' : '1'); Uart_SendString("\r\n"); } if (MOTOR != last_motor) { last_motor = MOTOR; Uart_SendString("[STATE] MOTOR status -> "); if (last_motor) { Uart_SendString("VIBRATING (ON)\r\n"); } else { Uart_SendString("SILENT (OFF)\r\n"); } } } } // 芯片基础 IO 端口属性定义 void GPIO_Init(void) { IE = 0x00; IE2 = 0x00; TCON = 0x00; TMOD &= 0xF0; // T0, T1 为模式 0 (16位自动重装载) TR0 = 0; ET0 = 0; AUXR = 0x00; // T0, T1 为 12T 模式 (默认) INTCLKO = 0x00; P_SW1 = 0x04; // 串口引脚映射:P3.0 RxD, P3.1 TxD; SPI映射到第二组 (P2.2-P2.5) P_SW2 = 0x00; P_SW3 = 0x00; // 配置 P0.1 (KEY_UP), P0.2 (KEY_SOS), P0.3 (KEY_DOWN) 为双向输入口 P0M1 &= ~((1 << 1) | (1 << 2) | (1 << 3)); P0M0 &= ~((1 << 1) | (1 << 2) | (1 << 3)); // 配置 P2.3 (WS2812_DI) 为推挽输出,初始化默认输出 0 (Reset/Idle) P2M1 &= ~(1 << 3); P2M0 |= (1 << 3); WS2812_DI = 0; // 配置 P2.5 (MOTOR) 震动马达、P2.6 (LED_B)、P2.7 (LED_G) 为推挽输出 P2M1 &= ~((1 << 5) | (1 << 6) | (1 << 7)); P2M0 |= ((1 << 5) | (1 << 6) | (1 << 7)); // 初始化虚拟 LED 与跟踪变量为熄灭状态 (1代表灭) LED_R = 1; LED_G = 1; LED_B = 1; last_hw_r = 1; last_hw_g = 1; last_hw_b = 1; MOTOR = 0; // 默认马达静止 // 初始化 WS2812 灯珠为熄灭状态 (0, 0, 0) WS2812_Write24Bit(0, 0, 0); WS2812_Reset(); // 配置 P3.4 (SGM_CTRL) 为推挽输出,P3.1 (TxD) 为推挽输出,P3.0 (RxD) 为双向口输入 P3M1 &= ~((1 << 0) | (1 << 1) | (1 << 4)); P3M0 &= ~(1 << 0); P3M0 |= ((1 << 1) | (1 << 4)); } // Touched to align with doc updates V3