Files
stc32g128k/App/main.c

1510 lines
49 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stc32g.h"
#include "intrins.h"
#include "config.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 = P0^0;
// 振动马达控制引脚输出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 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);
// 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 模式下精准时序控制)
* ========================================================================= */
void WS2812_Write24Bit(u8 g, u8 r, u8 b)
{
u8 i;
// 关全局中断,防止被其它高优先中断截断导致时序错乱
EA = 0;
// 绿光通道 (Green)
for (i = 0; i < 8; i++)
{
if (g & 0x80)
{
// 发送 "1" 码:高电平维持 ~0.8us,低电平维持 ~0.4us
WS2812_DI = 1;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
WS2812_DI = 0;
_nop_();
}
else
{
// 发送 "0" 码:高电平维持 ~0.35us,低电平维持 ~0.9us
WS2812_DI = 1;
_nop_(); _nop_(); _nop_(); _nop_();
WS2812_DI = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_();
}
g <<= 1;
}
// 红光通道 (Red)
for (i = 0; i < 8; i++)
{
if (r & 0x80)
{
WS2812_DI = 1;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
WS2812_DI = 0;
_nop_();
}
else
{
WS2812_DI = 1;
_nop_(); _nop_(); _nop_(); _nop_();
WS2812_DI = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_();
}
r <<= 1;
}
// 蓝光通道 (Blue)
for (i = 0; i < 8; i++)
{
if (b & 0x80)
{
WS2812_DI = 1;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
WS2812_DI = 0;
_nop_();
}
else
{
WS2812_DI = 1;
_nop_(); _nop_(); _nop_(); _nop_();
WS2812_DI = 0;
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_();
}
b <<= 1;
}
// 开全局中断
EA = 1;
}
void WS2812_Reset(void)
{
WS2812_DI = 0;
// 维持低电平 100us 以上以完成数据锁存 (24MHz 计数约2400)
{
u16 cnt;
for (cnt = 0; cnt < 250; cnt++)
{
_nop_();
}
}
}
/* =========================================================================
* 延时与时间获取辅助函数 (12T/1T 自适应)
* ========================================================================= */
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; // 若槽位已满,默认覆盖最后一个位置
// 查找是否有空余位置,或者该 ID 已经配对过
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;
if (type < 5)
{
sensor_list[slot_to_use].zone = default_zones[type]; // 自动绑定普通或24h防区类型
// 绑定默认英文字符名
for (i = 0; i < 15; i++)
{
sensor_list[slot_to_use].name_gbk[i] = default_names[type][i];
if (default_names[type][i] == '\0') break;
}
sensor_list[slot_to_use].name_gbk[15] = '\0';
}
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].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; // 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';
}
/* =========================================================================
* 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;
}
}
clock_updated = 1; // 标记时钟更新,在主循环中更新屏幕
}
}
// 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 = sensor_list[alarm_sensor_slot].type;
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();
}
}
/* =========================================================================
* 系统主循环逻辑 (交互状态机与射频匹配核心)
* ========================================================================= */
void main(void)
{
KeyEvent ev;
u8 state_changed = 0; // 用 u8 代替 bit 变量
u8 last_radar_sec = 99;
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 及射频接口引脚初始化
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();
// 默认进入 NORMAL 待机模式,显示时钟,并将射频调制芯片置为被动接收模式
current_state = STATE_NORMAL;
UI_ShowClockPage(current_state, current_hour, current_min);
RF_SetMode(1); // 开接收天线
while(1)
{
// 串口调试与物理引脚/器件仿真输入
cmd = Uart_RxChar();
if (cmd != '\0')
{
if (cmd == 'u')
{
key_event_buf = KEY_EVENT_UP_CLICK;
Uart_SendString("[UART SIM] KEY_UP Clicked\r\n");
}
else if (cmd == 'U')
{
key_event_buf = KEY_EVENT_UP_LONG;
Uart_SendString("[UART SIM] KEY_UP Long Pressed\r\n");
}
else if (cmd == 'd')
{
key_event_buf = KEY_EVENT_DOWN_CLICK;
Uart_SendString("[UART SIM] KEY_DOWN Clicked\r\n");
}
else if (cmd == 'D')
{
key_event_buf = KEY_EVENT_DOWN_LONG;
Uart_SendString("[UART SIM] KEY_DOWN Long Pressed\r\n");
}
else if (cmd == 's')
{
key_event_buf = KEY_EVENT_SOS_CLICK;
Uart_SendString("[UART SIM] KEY_SOS Clicked\r\n");
}
else if (cmd == 'S')
{
key_event_buf = KEY_EVENT_SOS_LONG;
Uart_SendString("[UART SIM] KEY_SOS Long Pressed\r\n");
}
else if (cmd == 'c' || cmd == 'C')
{
key_event_buf = KEY_EVENT_UP_DOWN_COMB;
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); // 0: 门磁
}
captured_addr = mock_addr;
current_state = STATE_ALARM;
state_changed = 1;
Uart_SendString("[UART SIM] Mock RF Alarm: ADDR 0x123456\r\n");
}
else if (cmd == 'p' || cmd == 'P')
{
if (current_state == STATE_PAIR_WAIT)
{
captured_addr = 0x789ABC;
captured_type = menu_select;
current_state = STATE_PAIR_CONFIRM;
state_changed = 1;
Uart_SendString("[UART SIM] Mock RF Pair Signal: ADDR 0x789ABC\r\n");
}
else
{
Uart_SendString("[UART SIM] Ignore: Not in PAIR WAIT state\r\n");
}
}
else if (cmd == '1')
{
current_state = STATE_NORMAL;
state_changed = 1;
Uart_SendString("[UART SIM] Set State to: NORMAL (Standby)\r\n");
}
else if (cmd == '2')
{
current_state = STATE_ARMED;
state_changed = 1;
Uart_SendString("[UART SIM] Set State to: ARMED (Armed)\r\n");
}
else if (cmd == '3')
{
current_state = STATE_DISARMED;
state_changed = 1;
Uart_SendString("[UART SIM] Set State to: DISARMED (Disarmed)\r\n");
}
else if (cmd == '4')
{
rgb_test_mode = 1;
LED_R = 0; LED_G = 1; LED_B = 1; // 红色亮 (0代表亮)
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 (Normal Mode)\r\n");
}
}
// 1. 读取按键事件并自动清空
ev = key_event_buf;
key_event_buf = KEY_EVENT_NONE;
if (ev != KEY_EVENT_NONE)
{
rgb_test_mode = 0; // 任何物理/按键事件触发时退出 RGB 测试模式
// 通过串口打印获取到的按键事件代号进行测试联调
Uart_SendString("Key Event Captured: ");
Uart_SendHex8((u8)ev);
Uart_SendString("\r\n");
// 根据不同的系统当前状态,执行状态迁移逻辑
if (current_state == STATE_NORMAL || current_state == STATE_ARMED || current_state == STATE_DISARMED)
{
if (ev == KEY_EVENT_UP_DOWN_COMB) // 同时长按 UP + DOWN 3 秒进入配对菜单
{
current_state = STATE_PAIR_MENU;
menu_select = 0;
state_changed = 1;
}
else if (ev == KEY_EVENT_SOS_CLICK) // 短按 SOS 发射 SOS 报警
{
current_state = STATE_SOS_EMITTED;
state_changed = 1;
}
else if (ev == KEY_EVENT_SOS_LONG) // 长按 SOS 5 秒与 IPC 绑定
{
UI_ShowBindingPage();
RF_SetMode(2); // TX mode
EV1527_Transmit(CLONED_ADDR, 0x01); // 对码绑定电报数据为 0x01
RF_SetMode(0); // Idle
Delay_ms(2000); // 维持 2 秒
current_state = STATE_NORMAL;
state_changed = 1;
}
}
else if (current_state == STATE_PAIR_MENU)
{
if (ev == KEY_EVENT_UP_CLICK) // 菜单选择上移
{
if (menu_select > 0)
{
menu_select--;
state_changed = 1;
}
}
else if (ev == KEY_EVENT_DOWN_CLICK) // 菜单选择下移
{
if (menu_select < 4)
{
menu_select++;
state_changed = 1;
}
}
else if (ev == KEY_EVENT_SOS_CLICK) // 单击 SOS 确认选项,进入对码搜索并触发 100ms 短振与白灯快闪
{
MOTOR = 1;
Delay_ms(100);
MOTOR = 0;
current_state = STATE_PAIR_WAIT;
pair_timeout_ms = 0; // 重置对码超时计时器
state_changed = 1;
}
else if (ev == KEY_EVENT_DOWN_LONG) // 长按 DOWN 键 3 秒强行返回待机
{
current_state = STATE_NORMAL;
state_changed = 1;
}
}
else if (current_state == STATE_PAIR_WAIT)
{
if (ev == KEY_EVENT_DOWN_LONG) // 在雷达页面,长按 DOWN 3秒强行退出
{
current_state = STATE_NORMAL;
state_changed = 1;
}
}
else if (current_state == STATE_PAIR_CONFIRM)
{
if (ev == KEY_EVENT_SOS_LONG) // 在确认页面,长按 SOS 3 秒保存对码结果
{
Add_Sensor(captured_addr, captured_type);
current_state = STATE_PAIR_SUCCESS;
state_changed = 1;
}
else if (ev == KEY_EVENT_DOWN_LONG) // 在确认页面,长按 DOWN 3 秒放弃保存返回待机
{
current_state = STATE_NORMAL;
state_changed = 1;
}
}
else if (current_state == STATE_ALARM)
{
// 在防区报警闪烁状态下,短按任意物理按键均可清除报警声光
current_state = STATE_NORMAL;
state_changed = 1;
}
else if (current_state == STATE_SOS_EMITTED)
{
// 再次长按任意物理按键即可主动解除求救模式
if (ev == KEY_EVENT_SOS_LONG || ev == KEY_EVENT_UP_LONG || ev == KEY_EVENT_DOWN_LONG)
{
current_state = STATE_NORMAL;
state_changed = 1;
}
}
}
// 2. 对码雷达扫描 30 秒超时自动跳回时钟主界面检测
if (current_state == STATE_PAIR_WAIT && pair_timeout_ms >= 30000UL)
{
pair_timeout_ms = 0;
UI_ShowPairFailPage(1); // 调用 Fail 绘制接口并传入超时标志 1
Delay_ms(2500); // 维持 2.5 秒超时警告
current_state = STATE_NORMAL;
state_changed = 1;
}
// 3. 状态切换的屏幕重写渲染 (只有发生状态改变才清屏,杜绝频闪)
if (state_changed)
{
state_changed = 0; // 仅在此处清除状态改变标记,确保异步状态转移时屏幕能被正确重绘
// 通过串口反馈状态机重绘过程
Uart_SendString("State Transition to: ");
Uart_SendHex8((u8)current_state);
Uart_SendString("\r\n");
if (current_state == STATE_NORMAL || current_state == STATE_ARMED || current_state == STATE_DISARMED)
{
RF_SetMode(1); // 切回接收模式监听防区
UI_ShowClockPage(current_state, current_hour, current_min);
}
else if (current_state == STATE_PAIR_MENU)
{
RF_SetMode(0); // 关闭射频节省能量
UI_ShowPairMenuPage(menu_select);
}
else if (current_state == STATE_PAIR_WAIT)
{
RF_SetMode(1); // 开启射频解调芯片,开始抓包
LCD_Clear(COLOR_BLACK);
LCD_ShowStringCentered(135, "RECHERCHE...", COLOR_WHITE, COLOR_BLACK);
LCD_ShowStringCentered(160, "DECLENCH. CAPT", COLOR_CYAN, COLOR_BLACK);
UI_ShowPairWaitPage(0);
last_radar_sec = 99; // 强行重置雷达波纹帧计数器
}
else if (current_state == STATE_PAIR_CONFIRM)
{
RF_SetMode(0); // 捕获成功,关闭射频
UI_ShowPairConfirmPage(captured_addr);
}
else if (current_state == STATE_PAIR_SUCCESS)
{
RF_SetMode(0);
UI_ShowPairSuccessPage(captured_addr);
// 触发对码成功物理反馈:强振 1 次 (400ms)LED 绿色常亮 2 秒
MOTOR = 1;
LED_G = 0; // 开启绿灯
LED_R = 1;
LED_B = 1;
Delay_ms(400); // 振动 400ms
MOTOR = 0; // 停止振动
Delay_ms(1600); // 维持绿灯常亮累计满 2 秒 (400 + 1600 = 2000ms)
LED_G = 1; // 熄灭绿灯
Delay_ms(500); // 补齐页面显示总时间 2.5 秒 (2000 + 500 = 2500ms)
current_state = STATE_NORMAL;
UI_ShowClockPage(current_state, current_hour, current_min);
RF_SetMode(1);
}
else if (current_state == STATE_ALARM)
{
u8 slot;
char *name = "UNKNOWN SENSOR";
if (Check_Sensor_ID(captured_addr, &slot))
{
name = sensor_list[slot].name_gbk; // 获取对应的注册英文名字
alarm_sensor_slot = slot;
}
UI_ShowAlarmPage(name, 1);
}
else if (current_state == STATE_SOS_EMITTED)
{
UI_ShowSosPage();
}
}
// 4. 定期局部刷新、动画更新与射频解调轮询
if (current_state == STATE_NORMAL || current_state == STATE_ARMED || current_state == STATE_DISARMED)
{
// 时钟分钟数字局部刷新 (防闪烁)
if (clock_updated)
{
clock_updated = 0;
UI_ShowClockPage(current_state, current_hour, current_min);
}
// 监听并解析防区发射的信号码
{
u32 rx_addr;
u8 rx_data;
if (EV1527_Decode(&rx_addr, &rx_data))
{
u8 slot;
if (Check_Sensor_ID(rx_addr, &slot)) // 检查接收 of 地址是否在配对列表中
{
u8 sensor_type = sensor_list[slot].type;
if (sensor_type < 5) // 仅触发普通防区传感器彻底过滤并排除SOS信号接收
{
// 24小时防区 (zone==0) 任何时候都触发,普通防区 (zone==1) 仅在 ARMED 状态下触发
if (sensor_list[slot].zone == 0 || current_state == STATE_ARMED)
{
captured_addr = rx_addr;
current_state = STATE_ALARM;
state_changed = 1;
}
}
}
}
}
}
else if (current_state == STATE_PAIR_WAIT)
{
// 雷达搜索页面每 250ms 局部刷新一帧雷达天线波纹
u8 frame = (u8)((ms_tick / 250) % 3);
if (frame != last_radar_sec)
{
last_radar_sec = frame;
UI_ShowPairWaitPage(frame);
}
// 在对码搜索状态下监听任意 EV1527 无线电码
{
u32 rx_addr;
u8 rx_data;
if (EV1527_Decode(&rx_addr, &rx_data))
{
captured_addr = rx_addr;
captured_type = menu_select;
current_state = STATE_PAIR_CONFIRM; // 捕获到信号,移至确认页
state_changed = 1;
}
}
}
else if (current_state == STATE_SOS_EMITTED)
{
// 主动 SOS 求救状态下,每 500ms 通过 LT4455 发射一次射频求救帧
u8 sec_phase = (u8)((ms_tick / 500) % 2);
if (sec_phase != last_radar_sec)
{
last_radar_sec = sec_phase;
RF_SetMode(2); // 射频置为发射端模式
EV1527_Transmit(CLONED_ADDR, 0x08); // 发射手环自带地址 CLONED_ADDR 且数据为 0x08
RF_SetMode(0); // 发射完成复位,关闭发射机
}
// 双实线红色警告边框的闪烁效果
if (alarm_flash_flag)
{
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED);
LCD_DrawRectBorder(8, 8, 104, 224, COLOR_WHITE);
}
else
{
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_BLACK);
LCD_DrawRectBorder(8, 8, 104, 224, COLOR_BLACK);
}
}
else if (current_state == STATE_ALARM)
{
// 警报闪烁状态下,交替绘制红色和黑色边框
if (alarm_flash_flag)
{
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_RED);
}
else
{
LCD_DrawRectBorder(4, 4, 112, 232, COLOR_BLACK);
}
}
// 仿真 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 = 0x00; // 串口引脚映射:默认 P3.0 RxD, P3.1 TxD
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));
// 配置 P0.0 (WS2812_DI) 为推挽输出,初始化默认输出 0 (Reset/Idle)
P0M1 &= ~(1 << 0);
P0M0 |= (1 << 0);
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));
}