feat: translate UI to French and implement XL-2020RGBC-2812B addressable RGB LED driver

This commit is contained in:
2026-07-06 11:17:11 +08:00
parent ee8b8bfe15
commit 9411d2a01b

View File

@@ -8,10 +8,17 @@
* 硬件引脚与全局变量定义
* ========================================================================= */
// 三色共阳极 LED 控制引脚输出0亮输出1灭
sbit LED_R = P0^0;
sbit LED_G = P2^7;
sbit LED_B = P2^6;
// 软件虚拟 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;
// 实际 WS2812 物理控制引脚(接 P0.0
sbit WS2812_DI = P0^0;
// 振动马达控制引脚输出1开启振动输出0停止
sbit MOTOR = P2^5;
@@ -56,25 +63,25 @@ volatile KeyEvent key_event_buf = KEY_EVENT_NONE; // 按键事件缓冲区
* 辅助映射表及前置声明
* ========================================================================= */
// 各防区类型的默认英文防区名称 (供报警显示使用)
// 各防区类型的默认法语防区名称 (供报警显示使用最大15字符)
char *code default_names[5] = {
"FRONT DOOR", // 0: 门磁
"LIVING ROOM", // 1: 红外
"KITCHEN SMOKE", // 2: 烟感
"KITCHEN GAS", // 3: 燃气
"BATHROOM WATER" // 4: 水浸
"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] = {
"DOOR SENSOR", // 0
"PIR MOTION", // 1
"SMOKE DETECT", // 2
"GAS LEAK", // 3
"WATER FLOOD" // 4
"DETEC. PORTE", // 0
"DETEC. PIR", // 1
"DETEC. FUMEE", // 2
"DETEC. GAZ", // 3
"DETEC. EAU" // 4
};
// 本地函数前置声明
@@ -114,6 +121,108 @@ 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 自适应)
* ========================================================================= */
@@ -453,26 +562,26 @@ void UI_ShowClockPage(SystemState state, u8 hour, u8 min)
time_str[5] = '\0';
LCD_ShowString16x32Centered(100, time_str, (state == STATE_ARMED) ? COLOR_WHITE : ((state == STATE_DISARMED) ? COLOR_WHITE : COLOR_CYAN), COLOR_BLACK);
// 静态星期和日期
LCD_ShowStringCentered(155, "THU 07-02", COLOR_GRAY, COLOR_BLACK);
// 静态星期和日期 (法语 JEU)
LCD_ShowStringCentered(155, "JEU 07-02", COLOR_GRAY, COLOR_BLACK);
// 屏幕底端布撤防状态标识 (Y=202 避开屏幕下圆弧)
if(state == STATE_ARMED)
{
LCD_DrawMonoBitmap(30, 202, 16, 16, bmp_lock_16x16, COLOR_RED, COLOR_BLACK);
LCD_ShowString(50, 202, "ARMED", COLOR_RED, COLOR_BLACK);
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(26, 202, 16, 16, bmp_unlock_16x16, COLOR_GREEN, COLOR_BLACK);
LCD_ShowString(46, 202, "DISARM", COLOR_GREEN, COLOR_BLACK);
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, "PAIR MENU", COLOR_AMBER, COLOR_BLACK);
LCD_ShowStringCentered(30, "MENU APPAI.", COLOR_AMBER, COLOR_BLACK);
// 绘制上一项
if (selected_index > 0)
@@ -510,8 +619,8 @@ void UI_ShowPairConfirmPage(u32 addr)
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 FOUND", COLOR_WHITE, COLOR_BLACK);
LCD_ShowStringCentered(160, "HOLD SOS TO SAVE", 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);
@@ -523,7 +632,7 @@ void UI_ShowPairSuccessPage(u32 addr)
LCD_Clear(COLOR_BLACK);
LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_checkmark_32x32, COLOR_GREEN, COLOR_BLACK);
LCD_ShowStringCentered(135, "PAIR SUCCESS", 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);
@@ -536,13 +645,13 @@ void UI_ShowPairFailPage(u8 is_timeout)
LCD_DrawMonoBitmap(44, 75, 32, 32, bmp_cross_32x32, COLOR_RED, COLOR_BLACK);
if (is_timeout)
{
LCD_ShowStringCentered(145, "PAIR TIMEOUT", COLOR_RED, COLOR_BLACK);
LCD_ShowStringCentered(170, "NO SIGNAL FOUND", COLOR_GRAY, COLOR_BLACK);
LCD_ShowStringCentered(145, "DELAI DEPASSE", COLOR_RED, COLOR_BLACK);
LCD_ShowStringCentered(170, "AUCUN SIGNAL", COLOR_GRAY, COLOR_BLACK);
}
else
{
LCD_ShowStringCentered(145, "PAIR FAILED", COLOR_RED, COLOR_BLACK);
LCD_ShowStringCentered(170, "TYPE MISMATCH", COLOR_GRAY, COLOR_BLACK);
LCD_ShowStringCentered(145, "ECHEC APPAI.", COLOR_RED, COLOR_BLACK);
LCD_ShowStringCentered(170, "TYPE INCORRECT", COLOR_GRAY, COLOR_BLACK);
}
}
@@ -559,7 +668,7 @@ void UI_ShowAlarmPage(char *sensor_name, u8 zone)
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] = '\0';
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);
}
@@ -572,8 +681,8 @@ void UI_ShowSosPage(void)
LCD_DrawMonoBitmap(44, 55, 32, 32, bmp_siren_32x32, COLOR_RED, COLOR_BLACK);
LCD_ShowStringCentered(125, "EMIT SOS", COLOR_RED, COLOR_BLACK);
LCD_ShowStringCentered(155, "BAND TRIGGERED", COLOR_WHITE, COLOR_BLACK);
LCD_ShowStringCentered(125, "SOS EMIS", COLOR_RED, COLOR_BLACK);
LCD_ShowStringCentered(155, "BRACELET ACTIF", COLOR_WHITE, COLOR_BLACK);
}
void UI_ShowBindingPage(void)
@@ -581,8 +690,8 @@ 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, "BINDING IPC", COLOR_WHITE, COLOR_BLACK);
LCD_ShowStringCentered(160, "TRANSMITTING...", COLOR_CYAN, COLOR_BLACK);
LCD_ShowStringCentered(135, "LIAISON IPC", COLOR_WHITE, COLOR_BLACK);
LCD_ShowStringCentered(160, "ENVOI EN COURS", COLOR_CYAN, COLOR_BLACK);
}
/* =========================================================================
@@ -832,6 +941,17 @@ void Timer1_Isr(void) interrupt 3
}
}
}
// 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();
}
}
/* =========================================================================
@@ -1114,8 +1234,8 @@ void main(void)
{
RF_SetMode(1); // 开启射频解调芯片,开始抓包
LCD_Clear(COLOR_BLACK);
LCD_ShowStringCentered(135, "SEARCHING...", COLOR_WHITE, COLOR_BLACK);
LCD_ShowStringCentered(160, "TRIGGER SENSOR", COLOR_CYAN, 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; // 强行重置雷达波纹帧计数器
}
@@ -1305,18 +1425,28 @@ void GPIO_Init(void)
P0M1 &= ~((1 << 1) | (1 << 2) | (1 << 3));
P0M0 &= ~((1 << 1) | (1 << 2) | (1 << 3));
// 配置 P0.0 (LED_R) 为推挽输出,低电平灭,初始化默认输出 1 熄灭
// 配置 P0.0 (WS2812_DI) 为推挽输出,初始化默认输出 0 (Reset/Idle)
P0M1 &= ~(1 << 0);
P0M0 |= (1 << 0);
LED_R = 1;
WS2812_DI = 0;
// 配置 P2.5 (MOTOR) 震动马达、P2.6 (LED_B) 蓝灯、P2.7 (LED_G) 绿灯为推挽输出
// 配置 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);