Files
stc32g128k/App/main.c

1480 lines
48 KiB
C
Raw Normal View History

#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 = 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);
// 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_EncodeByte4(u8 v, u8 *buf)
{
// Encode 8 FCOB bits into 4 SPI bytes (2 FCOB bits per byte)
// 0-code -> 1000 (binary), 1-code -> 1100 (binary)
buf[0] = ((v & 0x80) ? 0xC0 : 0x80) | ((v & 0x40) ? 0x0C : 0x08);
buf[1] = ((v & 0x20) ? 0xC0 : 0x80) | ((v & 0x10) ? 0x0C : 0x08);
buf[2] = ((v & 0x08) ? 0xC0 : 0x80) | ((v & 0x04) ? 0x0C : 0x08);
buf[3] = ((v & 0x02) ? 0xC0 : 0x80) | ((v & 0x01) ? 0x0C : 0x08);
}
void WS2812_Write24Bit(u8 g, u8 r, u8 b)
{
u8 xdata buf[12];
u8 i;
u16 timeout;
WS2812_EncodeByte4(g, &buf[0]);
WS2812_EncodeByte4(r, &buf[4]);
WS2812_EncodeByte4(b, &buf[8]);
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));
SPCTL = 0xD0; // Enable SPI at SYSCLK/4 (3.0 MHz actual clock on board)
SPSTAT = 0xC0; // Clear flags
for (i = 0; i < 12; i++)
{
SPDAT = buf[i];
timeout = 2000;
while (!(SPSTAT & 0x80) && --timeout); // Safe wait with timeout
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; // 若槽位已满,默认覆盖最后一个位置
// 查找是否有空余位置,或者该 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 == '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");
// Configure SCLK (P2.5) and MOSI (P2.3) as push-pull output
P2M1 &= ~((1 << 3) | (1 << 5));
P2M0 |= ((1 << 3) | (1 << 5));
SPCTL = 0xD0; // SPI Master, 6.0 MHz (SYSCLK / 4)
while(1)
{
SPSTAT = 0xC0;
SPDAT = 0xAA;
while (!(SPSTAT & 0x80));
}
}
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 = 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));
}