feat: initial commit for stc32g12k128 wristband firmware

This commit is contained in:
2026-07-06 11:10:43 +08:00
commit ee8b8bfe15
40 changed files with 80064 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
# Keil compiler build outputs
Build/
# Keil user-specific options and GUI layouts
*.uvgui.*
*.uvguix.*
*.dep
# Temporary/Backup files
*~
*.bak
*.tmp
*.crf
*.lst
*.obj
*.lnp
*.map
*.build_log.htm

46
App/config.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef __CONFIG_H__
#define __CONFIG_H__
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
// 系统状态机状态定义
typedef enum {
STATE_NORMAL,
STATE_ARMED,
STATE_DISARMED,
STATE_PAIR_MENU,
STATE_PAIR_WAIT,
STATE_PAIR_CONFIRM,
STATE_PAIR_SUCCESS,
STATE_PAIR_FAIL,
STATE_ALARM,
STATE_SOS_EMITTED
} SystemState;
// 按键事件定义
typedef enum {
KEY_EVENT_NONE,
KEY_EVENT_UP_CLICK, // SW1 单击
KEY_EVENT_DOWN_CLICK, // SW2 单击
KEY_EVENT_SOS_CLICK, // SW3 单击
KEY_EVENT_UP_LONG, // SW1 长按3秒
KEY_EVENT_DOWN_LONG, // SW2 长按3秒
KEY_EVENT_SOS_LONG, // SW3 长按
KEY_EVENT_UP_DOWN_COMB // SW1 + SW2 组合按键
} KeyEvent;
// 传感器存储结构
typedef struct {
unsigned char is_used; // 是否配对 (0x01: 已配对, 其它: 空闲)
unsigned char addr[3]; // 24位对码地址 (EV1527)
unsigned char type; // 传感器类型: 0~4
unsigned char zone; // 防区类型: 0: 24h防区, 1: 普通防区
unsigned char name_gbk[16]; // 中文防区名称 (预留)
} Sensor_Slot;
#define MAIN_Fosc 24000000UL
#define CLONED_ADDR 0x37A86UL
#endif

1324
App/main.c Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
# French Language & Addressable RGB LED (XL-2020RGBC-2812B) Implementation Plan
## Goal Description
Modify the wristband firmware to support **French-only UI display** and replace the discrete 3-pin LED control with the single-wire **addressable RGB LED (XL-2020RGBC-2812B)** protocol (WS2812B timing compatible).
## User Review Required
> [!IMPORTANT]
> 1. **RGB LED (WS2812B) Control Pin**:
> The single-wire addressable RGB LED requires a high-speed bit-stream control pin (DIN).
> We will use the **P0.0 pin** (originally `LED_R` net) to drive the WS2812B DIN. P0.0 is already configured as a Push-Pull output.
> Pins `P2.7` (originally `LED_G`) and `P2.6` (originally `LED_B`) will be disabled (set to standard inputs or high logic).
> 2. **French Translations**:
> All UI strings will be replaced with French equivalents formatted to fit the 120-pixel wide OLED screen (max 15 characters per line).
## Open Questions
None. The specifications are fully understood and mapping is direct.
## Proposed Changes
### Hardware / Drivers
#### [MODIFY] [lcd_font.h](file:///c:/workfile/105/stc32g12k128/Drivers/lcd_font.h)
No change needed for font, but we might include character translations if custom accent characters were needed. Since we use standard French without accents (like "ARME" instead of "ARMÉ") to avoid custom font complexity, no changes to `lcd_font.h` are required.
### Application Logic
#### [MODIFY] [main.c](file:///c:/workfile/105/stc32g12k128/App/main.c)
1. **Redefine LED output**:
- Redefine `LED_R`, `LED_G`, `LED_B` as virtual/soft registers (`bit` variables). This allows the current logic in `Timer1_Isr` (which computes blink rates, colors, and vibrations) to remain 100% unchanged.
2. **Implement WS2812B bit-bang driver**:
- Write a precise assembly/C bit-bang function `WS2812_Write24Bit(u8 g, u8 r, u8 b)` that drives `P0.0` (DIN) with the correct WS2812 high-speed timing (typical `T0H = 0.35us`, `T0L = 0.9us`, `T1H = 0.8us`, `T1L = 0.4us`).
- Implement `WS2812_Reset()` by holding DI low for `>80us` to latch data.
3. **Trigger RGB updates**:
- At the end of `Timer1_Isr` (or during main loop), monitor changes to the virtual `LED_R`, `LED_G`, `LED_B` variables. If any changes are detected, output the 24-bit color to the WS2812 LED using the bit-bang driver.
4. **French UI Translation**:
- Translate all string literals displayed on the screen into French (e.g. menu items, sensor default names, and system state texts).
## Verification Plan
### Automated Tests
- Build code with Keil C251 to ensure 0 compile/link errors.
### Manual Verification
- Test using UART simulation commands:
- Verify that the simulated LED output in the serial log shows correct R/G/B status changes for different states.
- Verify that French strings are printed correctly on the screen simulator or display.
- Test pairing, confirmation, alarm, and SOS states to verify correct RGB LED color outputs.

61
Docs/walkthrough.md Normal file
View File

@@ -0,0 +1,61 @@
# STC32G 手环项目工程与功能实现 Walkthrough
本项目完成了手环核心交互逻辑与状态机的全部实现。所有代码已完全用中文进行行级注释,且在 Keil C251 下编译成功0 Errors
## 实现功能摘要
1. **自适应射频解码兼容性**
* 重构为**基于电平比例的自适应解码算法**。放宽绝对微秒窗口限制高电平50~2500us低电平1500~60000us通过低/高电平比例15~48倍基准为31倍自动识别 EV1527 帧并解析数据。
* 优化串口调试输出,避免大量多行打印造成的 CPU 阻塞。
2. **严格匹配要求的按键与事件交互逻辑**
* **进入配对菜单**:在待机模式下,同时长按 `▲`(上键)+ `▼`(下键) 3秒进入传感器类型选择菜单无震动与LED闪烁保持菜单展示
* **进入对码搜索 (Pair Wait)**:在菜单中选择好类型后,短按 `SOS` 确认,此时触发 1 次 100ms 短振确认,且 LED 开启白色快闪3Hz进入雷达扫描信号接收。
* **主动呼救 (Emit SOS)**:在待机模式下,短按 `SOS` 键,立刻切入求救模式并开始向外循环发射 433MHz 警报信号。
* **IPC 对码绑定**:在待机模式下,长按 `SOS` 键 5秒显示 BINDING IPC 页面,向外发射 1 次 433MHz 绑定信号(数据码为 0x01维持 2 秒后自动返回待机。
* **解除求救模式**在求救模式下长按任意一个按键UP、DOWN 或 SOS即可主动解除警报退回时钟待机。
3. **不接收/解析他人 SOS 广播**
* 手环只对已经配对存储在内部数据库门磁、PIR、烟感、燃气、水浸的传感器 ID 触发报警。
* 防区轮询解码时严格过滤并排除 SOS 信号的被动接收,防止被其他设备的 SOS 广播误触发。
4. **各传感器特定声光电反射与对码状态**
* **对码流程**
* 对码中LED 维持 **白色快闪 (3Hz)**R+G+B 全开闪烁)。
* 对码成功:屏幕显示 PAIR SUCCESS触发 **强力长振 1 次 (400ms)**,并且 LED **绿色常亮 2 秒**
* 对码失败/超时:双击快速短振 (100ms + 100ms)LED **红色快闪 3 次**
* **传感器报警触发模式** (5秒循环周期)
* **门磁**LED 红色常亮,马达 1 次短振 300ms。
* **PIR 人体感应**LED 黄色R+G 混色),马达 2 次短振 300ms (间隔 200ms)。
* **烟雾**LED 绿色,马达 3 次短振 200ms (间隔 150ms)。
* **气体**LED 紫色R+B 混色),马达 4 次短振 200ms (间隔 100ms)。
* **水浸**LED 黄色R+G 混色),马达 2 次长振 600ms (间隔 300ms)。
* **手环主动 SOS 求救模式**
* LED **红色极速闪烁 (5Hz)**
* 马达 **持续 1200ms 循环长振** (振动 1000ms静止 200ms 循环)。
5. **电池百分号显示修复与坐标复原**
* **字模基线对齐**:将 `%` 字符0x25的字模数据在 8x16 矩阵中向上平移 2 像素,使其与前面的数字处于同一水平基准线。
* **坐标优化防重合**:将电池图标右移至 `X=92, Y=27`,电量百分比置于 `X=62, Y=24`。二者之间保留 6 像素间距,既美观又完美杜绝了贴合与重叠问题。
6. **对码捕获卡顿 Bug 修复**
* 修复了 `while(1)` 循环开头无条件执行 `state_changed = 0` 导致在 Section 4 异步检测到射频匹配信号跳入 `STATE_PAIR_CONFIRM` 后重绘标记被强行抹除、屏幕始终卡死在搜索雷达页面的 Bug。现在已改在重绘判定内部重置检测到对码信号即可瞬间跳转至“捕获成功”确认页。
## 仿真模式扩展说明
为了支持无物理元件调试,串口输入指令集已同步扩展:
* **模拟组合按键**:串口发送 **`c`** 字符,模拟同时长按 `▲` + `▼` 按键 3 秒进入配对菜单。
* **模拟确认搜索**:在菜单页下发送 **`s`**,模拟按下 SOS 键,触发 100ms 短振与白灯快闪,进入对码搜索(雷达显示)。
* **模拟按键解除**:在求救模式下,发送 **`U`**、**`D`** 或 **`S`**(代表长按按键),即可解除 SOS 并退回时钟。
* **模拟切换系统布防状态**(用于测试普通防区的触发):
* 发送 **`1`**:强制系统进入 **NORMAL** 撤防/常态模式(门磁/PIR 触发时会被忽略,烟感/水浸/燃气仍可触发)。
* 发送 **`2`**:强制系统进入 **ARMED** 布防模式(门磁/PIR 此时被触发会立刻报警)。
* 发送 **`3`**:强制系统进入 **DISARMED** 撤防模式。
## 编译结果
* **编译器**Keil C251 V5.60.0.0
* **编译输出目标**`Build\wristband.hex`
* **Errors**0
* **Warnings**2
* **Program Size**data=104.1, edata+hdata=351, xdata=352, const=1395, code=13552

View File

@@ -0,0 +1,146 @@
# 手环端“全场景”图文并茂软件交互故事板
为了让开发与评审过程更加生动直观,本故事板将手环的**每一步软件逻辑**与**实际 OLED 屏幕128x64像素级 UI 画面**进行了一对一绑定,并列出了该步骤下的 LED 灯效、马达振动和按键逻辑。
---
## 📅 轮播:核心 OLED 界面快速预览(左滑/右滑)
````carousel
![1. 时钟待机](wristband_clock.svg)
<!-- slide -->
![2. 已布防时钟](wristband_armed.svg)
<!-- slide -->
![3. 已撤防时钟](wristband_disarmed.svg)
<!-- slide -->
![4. 进入配对模式](wristband_pair_start.svg)
<!-- slide -->
![5. 配对选择列表](wristband_pairing.svg)
<!-- slide -->
![6. 配对保存成功](wristband_saved.svg)
<!-- slide -->
![7. 对码匹配失败](wristband_pair_fail.svg)
<!-- slide -->
![8. 门磁报警触发](wristband_alarm.svg)
<!-- slide -->
![9. 紧急SOS求救](wristband_sos.svg)
````
---
## 🗺️ 第一部分:待机与安防状态切换
### 1.1 待机模式(未加入布防)
![待机模式](wristband_clock.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 系统正常上电启动,或报警/配对结束后的常态。 |
| **屏幕元素** | 1. 顶部状态栏:展示 `WATCH` 及 `85%` 电池图标。<br>2. 中央大字:`10:35` 数字时钟。<br>3. 底部小字:`THU 07-02` 星期与日期。 |
| **LED 灯效** | 熄灭(无灯)。 |
| **马达反馈** | 静止(不振动)。 |
| **下一个状态** | 监听 433MHz 射频总线,等待警报、配对按键或布撤防通知。 |
---
### 1.2 系统布防状态ARMED
![已布防](wristband_armed.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 接收到 IPC 发出的 433MHz 布防广播。 |
| **屏幕元素** | 1. 状态栏左侧:显示 **红色闭锁 `🔒` 图标**,并滚动显示 **`已布防 ZONE 1-N`** 文字。<br>2. 中央与底部:保持正常的数字时钟和日期。 |
| **LED 灯效** | **红色呼吸灯**(可配置常亮/慢闪,根据客户最终定义)。 |
| **马达反馈** | 接收到广播瞬间短振 1 次150ms。 |
---
### 1.3 系统撤防状态DISARMED
![已撤防](wristband_disarmed.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 接收到 IPC 发出的 433MHz 撤防广播。 |
| **屏幕元素** | 1. 状态栏左侧:显示 **绿色开锁 `🔓` 图标**,并显示 **`已撤防 ZONE 1-N`**。<br>2. 中央与底部:正常的数字时钟和日期。 |
| **LED 灯效** | **绿色慢闪 3 次后熄灭**。 |
| **马达反馈** | 接收到广播瞬间短振 1 次150ms。 |
---
## 🗺️ 第二部分:传感器对码配对流程(手环端 4 步)
### Step 1进入配对模式搜索信号
![配对搜索](wristband_pair_start.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 用户同时按下 **``(上移键)+ ``(下移键)持续 3 秒**。 |
| **屏幕元素** | 1. 顶部:高亮 `PAIRING MODE`。<br>2. 中央:**雷达天线波纹 `📡` 动态循环动画**。<br>3. 底部文字:滚动显示 `正在搜索 433MHz 信号... 请触发目标传感器`。 |
| **LED 灯效** | **白色快速闪烁3Hz**,标识进入对码模式。 |
| **马达反馈** | 进入瞬间短振 1 次100ms确认触发成功。 |
| **超时机制** | **30 秒超时**。若 30 秒内未收到射频信号,退出配对返回时钟待机。 |
---
### Step 2选择配对的传感器类型
![配对选择](wristband_pairing.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **操作方式** | 连续短按 **``(上移键)** 或 **``(下移键)** 进行滚动。 |
| **屏幕元素** | 1. 顶部:`配对模式 P-00`(展示当前已配对数量)。<br>2. 中央:**3行滚动列表**,当前高亮项(如 `👤 人体感应 PIR`)有 **粗体外框** 且图标放大;上下两行未选中项显示暗淡。<br>3. 右侧:显示纵向滚动条指示器。 |
| **LED 灯效** | 保持 **白色闪烁**。 |
| **逻辑响应** | 用户需停留在要配对的传感器类型上如停留在“PIR”然后再去触发传感器物理开关。 |
---
### Step 3-A对码匹配成功通过校验
![配对保存](wristband_saved.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 触发外部传感器,手环捕获的 433MHz 信号**与当前高亮选中的类型一致**,用户**短按 SOS 键**进行确认保存。 |
| **屏幕元素** | 1. 中央:显示绿色 **大勾 `` 图标**。<br>2. 中下部:【对码已保存】。<br>3. 底部:显示已捕获的硬件十六进制地址码(如 `ADDR: 0x37A86 | TYPE: PIR`)。 |
| **LED 灯效** | **绿色常亮 2 秒** 后熄灭。 |
| **马达反馈** | 强力 **长振 1 次400ms** 确认成功保存。 |
| **自动同步** | 保存后,手环会向 IPC 同步名称,当接收到 IPC 的自定义中文广播后,会将 `人体感应 PIR` 替换为自定义命名(如 `客厅红外`)。 |
---
### Step 3-B对码不匹配类型错误
![对码失败](wristband_pair_fail.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 触发外部传感器,但捕获的 433MHz 信号类型**与手环屏幕当前选中的高亮类型不匹配**(例如:手环选了门磁,用户却触发了红外)。 |
| **屏幕元素** | 1. 报警边框:红色细边框。<br>2. 中央:红色 **大叉 `` 圆圈图标**。<br>3. 文字:【对码匹配失败】及副标题【代码类型不一致,请重试】。 |
| **LED 灯效** | **红色快闪 3 次**。 |
| **马达反馈** | 快速 **双击短振100ms + 100ms**,提示出错。 |
| **后续响应** | 停留 2 秒后自动返回 Step 2 的列表选择页面。 |
---
## 🗺️ 第三部分:报警告警模式
### 2.1 传感器报警触发(以门磁为例)
![门磁报警](wristband_alarm.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 待机状态下,接收到已配对传感器的报警射频信号。 |
| **屏幕元素** | 1. 警报边框:**红色闪烁虚线警告框**。<br>2. 中央:大尺寸传感器专用图标,本例为开门状态的 **`🚪 门` 图标**。<br>3. 底部文字:【🚪 前门门磁 触发】,第二行显示 ZONE 状态【ZONE 0 \| 红色报警】。 |
| **LED 灯效** | 根据传感器映射表,亮起对应颜色的指示灯(门磁为 **红色常亮/快闪**)。 |
| **马达反馈** | 触发门磁专属振动:**1次短振 300ms**,每 5 秒循环一次直到告警解除。 |
---
### 2.2 紧急 SOS 求救触发(最高优先级)
![紧急求救](wristband_sos.svg)
| 交互维度 | 规格详情与软件逻辑 |
| :--- | :--- |
| **触发动作** | 用户在手环上短按 SOS 键,或接收到其它手环广播的 SOS 求救信号。 |
| **屏幕元素** | 1. 警报边框:**红宽双边警告框**。<br>2. 中央:旋转警灯 **`🚨` 闪烁图标**。<br>3. 文字:【🚨 紧急求救 SOS】大字第二行【手环触发 \| 最高优先级】。 |
| **LED 灯效** | **红色极速闪烁5Hz**。 |
| **马达反馈** | **持续不间断长振**(以 1200ms 的长周期无缝循环强力振动),直到用户手动在手环上长按取消或在 IPC/APP 上点击解除。 |
| **优先级** | 凌驾于所有其它 Zone 报警之上,直接抢占屏幕。 |

View File

@@ -0,0 +1,84 @@
# STC32G手环系统开发总结及开发计划
本项目基于STC32G12K128单片机驱动信利AM010RT10206V0AMOLED屏幕控制芯片RM69310与SGM3833电源芯片实现了手环UI显示系统、按键消抖状态机、自适应射频解调和防区报警功能。
---
## 一、 已完成功能与代码实现总结
### 1. 硬件电源与驱动层修复
* **SGM3833电源使能修复**:修复了原初始化流程中在 `LCD_Init()` 执行时拉低 `SGM_CTRL = 0` 的逻辑缺陷,改为保持高电平 `SGM_CTRL = 1` 使能,保证屏幕所需的 ±VELVDD 正负压与 VAVDD 稳定输出。
* **字模基线与显示优化**:修复了 `Drivers/lcd_font.h``%` 字符(索引 0x25的混乱点阵字模将其在 8x16 矩阵中向上平移 2 像素对齐数字基线;并重构了电量显示坐标(电池图标 `X=92, Y=27`,电量百分比 `X=62, Y=24`),确保两器件拥有 6 像素的安全间距,完美杜绝字符乱码与重合。
* **屏幕无闪烁刷新**:重构了状态重绘屏刷新机制,去除了主循环开头强制清除重绘标记的 Bug改在 Redraw 块内清零;使得手环可以在捕获到对码信号的瞬间,立刻跳转到“对码确认”页面,不再卡顿于雷达搜索 UI。
### 2. 射频解码性能重构(遥控器配对失败修复)
* **自适应时序算法**:抛弃了原先微秒级死宽度的硬编码限制(高电平放宽至 `50~2500us`,低电平放宽至 `1500~60000us`),改用低电平与高电平的时间比值(范围 `15``48` 倍,以 31 倍为基准)自动解调。自适应计算时钟基准 `T = low_time / 31`支持匹配任意振荡电阻150K至4.7M)的遥控器与探测器。
* **CPU效率优化**:移除了接收抓包过程中 24 行脉冲宽度的串口阻塞式打印,将串口输出缩减到一行解码 Summary使得单帧解析时间从 62.6ms 降至 2ms 以下,杜绝了多帧连续发射造成的丢包问题。
### 3. 按键与事件响应体系(完全匹配说明书)
* **待机状态控制**
* **同时长按 ▲+▼ 3秒**:进入配对类型选择菜单。
* **短按 SOS**:进入本机紧急呼救模式(`STATE_SOS_EMITTED`),背景循环发射 433MHz 警报信号。
* **长按 SOS 5秒**:触发 IPC 摄像机对码绑定,屏幕显示 `BINDING IPC` 并发射一次对码广播(数据码 `0x01`2秒后自动退回时钟。
* **求救解除**在求救模式下长按任意一个物理按键UP, DOWN 或 SOS即可重置状态并安全退回时钟页面。
* **屏蔽 SOS 被动报警**只允许门磁、PIR、烟感、燃气、水浸类型 0~4等传感器配对并触发被动防区报警强行过滤并排除 SOS 求救广播的被动接收,防止手环之间产生误报环路。
### 4. 外设控制与声光电反射矩阵Timer1 ISR 中断实现)
* **求救模式**LED 红色以 5Hz 极速闪烁;马达以 1200ms 长振循环(振动 1000ms静止 200ms不间断工作。
* **对码模式**
* 对码中LED 始终保持 **白色快闪3Hz**
* 对码成功LED **绿色常亮 2 秒**,马达 **强震 1 次400ms**,随后恢复时钟。
* 对码超时/失败LED **红色快闪 3 次**,马达 **双击快震100ms+100ms**
* **防区触发告警模式5秒循环特定声光组合**
* *门磁/窗磁*LED 红色常亮,马达 1 次短振 300ms。
* *人体红外*普通防区LED 黄色,马达 2 次短振 300ms间隔 200ms
* *烟雾探测*24h防区LED 绿色,马达 3 次短振 200ms间隔 150ms
* *气体泄漏*24h防区LED 紫色,马达 4 次短振 200ms间隔 100ms
* *水浸溢出*24h防区LED 黄色,马达 2 次长振 600ms间隔 300ms
### 5. 联调仿真交互层(免焊接外设调试)
* **仿真指令注入**:支持通过电脑串口发送特定按键符号(`u/U`, `d/D`, `s/S`, `c`)模拟短按、长按、双键组合;发送 `'a'` 仿真门磁触发;发送 `'p'` 仿真对码接收。
* **仿真状态改变输出**:在主循环中实时跟踪 LED 及 MOTOR 端口的电平跳变,并在串口实时输出其状态变化日志(例如 `[STATE] LED status -> R:1 G:0 B:0`),便于逻辑排查。
* **状态切换模拟**:增加 `'1'``'2'``'3'` 串口指令,可人为强制手环分别在 NORMAL常态、ARMED布防、DISARMED撤防状态间任意切换解决了由于按键复用导致无法手动布防普通防区门磁/红外)进行报警测试的问题。
---
## 二、 工程代码文件 Landscape
手环端的主体源文件与职责划分如下:
1. **[App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c)**
* 系统业务状态机核心与 `main` 主循环。
* `Timer1_Isr` 1ms 定时器中断服务(处理软件 RTC、按键消抖/长按/组合判定、LED 与马达闪烁波形生成)。
* 对码列表数据库操作配对防区存储与加载、IAP 写 Flash 与读取)。
* UI 页面整体渲染与局部更新逻辑。
2. **[App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h)**
* 公用数据结构(`Sensor_Slot`)与枚举变量(`SystemState``KeyEvent`)声明。
* MAIN_Fosc24MHz及掉电保存 IAP 扇区基地址(`0xFE0000`)。
3. **[Drivers/rf.c](file:///c:/workfile/105/stc32g12k128/Drivers/rf.c) / [rf.h](file:///c:/workfile/105/stc32g12k128/Drivers/rf.h)**
* LR690L 接收芯片与 LT4455 发射芯片的 GPIO 初始化及模式控制。
* 自适应 EV1527 软件解码(`EV1527_Decode`)与主动发射(`EV1527_Transmit`)。
4. **[Drivers/lcd.c](file:///c:/workfile/105/stc32g12k128/Drivers/lcd.c) / [lcd.h](file:///c:/workfile/105/stc32g12k128/Drivers/lcd.h)**
* AMOLED 屏幕 RM69310 的 SPI 写指令/写数据通道。
* SGM3833 脉冲波形发送。
* 底层写屏窗口X轴偏移4像素补偏与流式英文字符/单色位图绘制函数。
5. **[Drivers/lcd_font.h](file:///c:/workfile/105/stc32g12k128/Drivers/lcd_font.h)**
* 时钟所需的图标及对码成功/失败、报警图标字模数据。
* 标准的 8x16 ASCII 字模库。
---
## 三、 下一步开发任务计划
为使手环达到商用级产品水准,下一步开发计划如下:
* **1. 深度睡眠与超低功耗电源管理(最高优先级)**
* **屏幕休眠**:在无按键操作 10 秒后,通过 SPI 发送 `0x10` 命令使 AMOLED 进入 Sleep同时拉低 `SGM_CTRL = 0` 关闭 SGM3833 的正负压输出。
* **单片机停机**:调用 `PD` 指令使单片机进入 Power-Down 停机状态。
* **外部中断唤醒**配置按键引脚P0.1, P0.2, P0.3)作为外部中断源唤醒单片机。
* **2. LR690L 间歇性接收Duty-Cycling低功耗优化**
* LR690L 正常工作下消耗 3.5mA 电流。使用定时器控制 `SHUT` 引脚,每 100ms 唤醒 10ms 进行载波监听检测,无载波时继续休眠 90ms实现接收功耗降低 80% 以上。
* **3. 主机射频时间广播同步RTC 自动校准)**
* 在被动接收中捕获 IPC 主机发送的特定同步帧(如数据码为 `0x09`),并提取时间信息自动校正 `current_hour``current_min`,保证时钟显示精准。
* **4. 电池 ADC 电量采样与电量计算模型**
* 配置 `P2.3`ADC3 通道)分压输入,读取电池电压,并建立锂电池放电曲线转换表,计算真实的 `0~100%` 剩余容量百分比动态输出到屏幕顶端,取代目前的静态电量指示。

609
Docs/wristband_spec.html Normal file
View File

@@ -0,0 +1,609 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>手环端软件交互与功能流程故事板</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: #0B0F19;
color: #E2E8F0;
margin: 0;
padding: 40px 20px;
line-height: 1.6;
}
.container {
max-width: 1000px;
margin: 0 auto;
}
h1 {
font-size: 2.2rem;
color: #00E5FF;
text-align: center;
margin-bottom: 10px;
letter-spacing: 1px;
}
.subtitle {
text-align: center;
color: #94A3B8;
font-size: 1.1rem;
margin-bottom: 40px;
}
.section-title {
font-size: 1.5rem;
color: #FFB74D;
border-bottom: 2px solid #1E293B;
padding-bottom: 8px;
margin-top: 50px;
margin-bottom: 24px;
}
.card {
background-color: #1E293B;
border-radius: 12px;
padding: 24px;
margin-bottom: 30px;
display: flex;
flex-direction: row;
gap: 24px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
border: 1px solid #334155;
transition: transform 0.2s, box-shadow 0.2s;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 24px rgba(0,0,0,0.4);
}
.screen-container {
flex: 0 0 256px;
height: 128px;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 0 15px rgba(0,229,255,0.15);
background-color: #0A0D14;
}
.details-container {
flex: 1;
}
.step-name {
font-size: 1.25rem;
font-weight: bold;
color: #FFFFFF;
margin-top: 0;
margin-bottom: 12px;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
th, td {
text-align: left;
padding: 8px 12px;
border-bottom: 1px solid #334155;
}
th {
color: #94A3B8;
font-weight: 600;
width: 90px;
}
td {
color: #E2E8F0;
}
.badge {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 0.8rem;
font-weight: bold;
}
.badge-red { background-color: #7f1d1d; color: #fca5a5; }
.badge-green { background-color: #064e3b; color: #6ee7b7; }
.badge-blue { background-color: #1e3a8a; color: #93c5fd; }
.badge-orange { background-color: #7c2d12; color: #ffedd5; }
.badge-white { background-color: #374151; color: #f3f4f6; }
@media (max-width: 768px) {
.card {
flex-direction: column;
align-items: center;
}
.screen-container {
flex: 0 0 auto;
}
}
@keyframes flash {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
</style>
</head>
<body>
<div class="container">
<h1>手环端软件交互与功能流程</h1>
<div class="subtitle">1.6寸 OLED 屏幕像素级画面与系统行为对照故事板</div>\n <!-- SVG Mindmap -->\n <div class="card" style="flex-direction: column; align-items: stretch; background-color: #0D111A; border: 1px solid #1E293B;">\n <div class="step-name" style="text-align: center; color: #FFB74D;">手环软件系统功能架构脑图 (思维导图)</div>\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 480" width="100%" height="auto">
<!-- Definitions for gradients and shadows -->
<defs>
<filter id="shadow" x="-5%" y="-5%" width="110%" height="110%">
<feDropShadow dx="0" dy="2" stdDeviation="4" flood-color="#000000" flood-opacity="0.5"/>
</filter>
<linearGradient id="blueGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#00E5FF"/>
<stop offset="100%" stop-color="#00838F"/>
</linearGradient>
<linearGradient id="orangeGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFB74D"/>
<stop offset="100%" stop-color="#EF6C00"/>
</linearGradient>
<linearGradient id="purpleGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#E040FB"/>
<stop offset="100%" stop-color="#7B1FA2"/>
</linearGradient>
<linearGradient id="greenGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#69F0AE"/>
<stop offset="100%" stop-color="#00B0FF"/>
</linearGradient>
</defs>
<!-- Background Grid -->
<rect width="800" height="480" fill="#0D111A" rx="12"/>
<!-- Connection Lines (Behind Nodes) -->
<!-- Central connections -->
<path d="M 400 240 L 220 120" stroke="#334155" stroke-width="2" fill="none"/>
<path d="M 400 240 L 220 240" stroke="#334155" stroke-width="2" fill="none"/>
<path d="M 400 240 L 220 360" stroke="#334155" stroke-width="2" fill="none"/>
<path d="M 400 240 L 580 120" stroke="#334155" stroke-width="2" fill="none"/>
<path d="M 400 240 L 580 240" stroke="#334155" stroke-width="2" fill="none"/>
<path d="M 400 240 L 580 360" stroke="#334155" stroke-width="2" fill="none"/>
<!-- Sub connections Left -->
<path d="M 120 120 L 40 100" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 120 120 L 40 140" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 120 240 L 40 220" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 120 240 L 40 260" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 120 360 L 40 340" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 120 360 L 40 380" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<!-- Sub connections Right -->
<path d="M 680 120 L 760 100" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 120 L 760 140" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 240 L 760 200" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 240 L 760 240" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 240 L 760 280" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 360 L 760 300" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 360 L 760 340" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 360 L 760 380" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<path d="M 680 360 L 760 420" stroke="#1E293B" stroke-width="1.5" fill="none"/>
<!-- Central Root Node -->
<g filter="url(#shadow)">
<rect x="320" y="210" width="160" height="60" rx="30" fill="url(#blueGrad)"/>
<text x="400" y="246" fill="#0A0D14" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">手环系统主逻辑</text>
</g>
<!-- ================= LEFT SIDE NODES ================= -->
<!-- Node L1: 待机时钟 -->
<g filter="url(#shadow)">
<rect x="120" y="100" width="100" height="40" rx="6" fill="#1E293B" stroke="#00E5FF" stroke-width="1"/>
<text x="170" y="125" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">待机模式</text>
</g>
<!-- L1 Sub nodes -->
<rect x="10" y="85" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="50" y="102" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">数字时间显示</text>
<rect x="10" y="125" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="50" y="142" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">系统电量展示</text>
<!-- Node L2: 射频监听 -->
<g filter="url(#shadow)">
<rect x="120" y="220" width="100" height="40" rx="6" fill="#1E293B" stroke="#00E5FF" stroke-width="1"/>
<text x="170" y="245" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">后台监测</text>
</g>
<!-- L2 Sub nodes -->
<rect x="10" y="205" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="50" y="222" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">被动接收433M</text>
<rect x="10" y="245" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="50" y="262" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">地址码合法校验</text>
<!-- Node L3: 安全防区 -->
<g filter="url(#shadow)">
<rect x="120" y="340" width="100" height="40" rx="6" fill="#1E293B" stroke="#00E5FF" stroke-width="1"/>
<text x="170" y="365" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">防区状态</text>
</g>
<!-- L3 Sub nodes -->
<rect x="10" y="325" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="50" y="342" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">🔒 已布防图标</text>
<rect x="10" y="365" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="50" y="382" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">🔓 已撤防图标</text>
<!-- ================= RIGHT SIDE NODES ================= -->
<!-- Node R1: 报警响应 -->
<g filter="url(#shadow)">
<rect x="580" y="100" width="100" height="40" rx="6" fill="#1E293B" stroke="#FF1744" stroke-width="1"/>
<text x="630" y="125" fill="#FF1744" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">告警响应</text>
</g>
<!-- R1 Sub nodes -->
<rect x="710" y="85" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="102" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">OLED显示警报</text>
<rect x="710" y="125" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="142" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">LED点亮对应色</text>
<!-- Node R2: SOS紧急 -->
<g filter="url(#shadow)">
<rect x="580" y="220" width="100" height="40" rx="6" fill="#1E293B" stroke="#FF1744" stroke-width="1"/>
<text x="630" y="245" fill="#FF1744" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">SOS呼救</text>
</g>
<!-- R2 Sub nodes -->
<rect x="710" y="185" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="202" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">短按发送求救码</text>
<rect x="710" y="225" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="242" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">马达持续长振</text>
<rect x="710" y="265" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="282" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">长按5s绑定IPC</text>
<!-- Node R3: 配对对码 -->
<g filter="url(#shadow)">
<rect x="580" y="340" width="100" height="40" rx="6" fill="#1E293B" stroke="#FFB74D" stroke-width="1"/>
<text x="630" y="365" fill="#FFB74D" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">对码配对</text>
</g>
<!-- R3 Sub nodes -->
<rect x="710" y="285" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="302" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">同时按▲+▼进入</text>
<rect x="710" y="325" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="342" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">按▲/▼滚动选类型</text>
<rect x="710" y="365" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="382" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">物理触发捕获码</text>
<rect x="710" y="405" width="80" height="26" rx="4" fill="#0F172A" stroke="#334155" stroke-width="1"/>
<text x="750" y="422" fill="#E2E8F0" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">按SOS保存并同步</text>
</svg>\n </div>
<!-- Section 1 -->
<div class="section-title">一、 待机与安全防区模式</div>
<!-- Card 1.1 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<text x="12" y="20" fill="#5A6275" font-family="system-ui, sans-serif" font-size="10" font-weight="bold">WATCH</text>
<rect x="210" y="11" width="22" height="10" rx="2" fill="none" stroke="#5A6275" stroke-width="1"/>
<rect x="212" y="13" width="14" height="6" rx="1" fill="#00E5FF"/>
<rect x="233" y="14" width="2" height="4" rx="1" fill="#5A6275"/>
<text x="186" y="20" fill="#5A6275" font-family="system-ui, sans-serif" font-size="9">85%</text>
<text x="128" y="85" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="48" font-weight="bold" text-anchor="middle" letter-spacing="1">10:35</text>
<text x="128" y="112" fill="#5A6275" font-family="system-ui, sans-serif" font-size="11" text-anchor="middle">THU 07-02</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">1.1 待机模式(未加入布防)</div>
<table>
<tr><th>触发动作</th><td>系统正常上电启动,或报警/配对结束后的常态。</td></tr>
<tr><th>屏幕显示</th><td>顶部显示 WATCH 及电池百分比,中央大字显示数字时钟,底部显示星期日期。</td></tr>
<tr><th>LED 灯效</th><td>关闭(无灯)</td></tr>
<tr><th>马达反馈</th><td>静止(不振动)</td></tr>
<tr><th>逻辑状态</th><td>433MHz 接收管使能,持续监听总线信号。</td></tr>
</table>
</div>
</div>
<!-- Card 1.2 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<g transform="translate(12, 10)">
<rect x="0" y="5" width="8" height="6" rx="1" fill="#FF1744"/>
<path d="M2,5 L2,3 C2,1.5 6,1.5 6,3 L6,5" fill="none" stroke="#FF1744" stroke-width="1.5"/>
<text x="14" y="11" fill="#FF1744" font-family="system-ui, sans-serif" font-size="9" font-weight="bold">已布防 ZONE 1-N</text>
</g>
<rect x="210" y="11" width="22" height="10" rx="2" fill="none" stroke="#5A6275" stroke-width="1"/>
<rect x="212" y="13" width="14" height="6" rx="1" fill="#00E5FF"/>
<rect x="233" y="14" width="2" height="4" rx="1" fill="#5A6275"/>
<text x="128" y="85" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="48" font-weight="bold" text-anchor="middle" letter-spacing="1">10:35</text>
<text x="128" y="112" fill="#5A6275" font-family="system-ui, sans-serif" font-size="11" text-anchor="middle">THU 07-02</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">1.2 系统布防状态ARMED</div>
<table>
<tr><th>触发动作</th><td>接收到 IPC 发出的 433MHz 布防广播。</td></tr>
<tr><th>屏幕显示</th><td>状态栏左侧显示 <span class="badge badge-red">🔒</span> 并滚动展示“已布防 ZONE 1-N”其余保持时钟。</td></tr>
<tr><th>LED 灯效</th><td>红色呼吸灯慢闪(根据客户要求配置)</td></tr>
<tr><th>马达反馈</th><td>接收广播瞬间短振 1 次150ms</td></tr>
<tr><th>逻辑状态</th><td>进入布防状态,后续除 ZONE 0 外ZONE 1-N 的触发也会引发手环报警。</td></tr>
</table>
</div>
</div>
<!-- Card 1.3 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<g transform="translate(12, 10)">
<rect x="0" y="5" width="8" height="6" rx="1" fill="#00E676"/>
<path d="M2,5 L2,3 C2,1.5 5,1.5 5,3 L5,4" fill="none" stroke="#00E676" stroke-width="1.5"/>
<text x="14" y="11" fill="#00E676" font-family="system-ui, sans-serif" font-size="9" font-weight="bold">已撤防 ZONE 1-N</text>
</g>
<rect x="210" y="11" width="22" height="10" rx="2" fill="none" stroke="#5A6275" stroke-width="1"/>
<rect x="212" y="13" width="14" height="6" rx="1" fill="#00E5FF"/>
<rect x="233" y="14" width="2" height="4" rx="1" fill="#5A6275"/>
<text x="128" y="85" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="48" font-weight="bold" text-anchor="middle" letter-spacing="1">10:35</text>
<text x="128" y="112" fill="#5A6275" font-family="system-ui, sans-serif" font-size="11" text-anchor="middle">THU 07-02</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">1.3 系统撤防状态DISARMED</div>
<table>
<tr><th>触发动作</th><td>接收到 IPC 发出的 433MHz 撤防广播。</td></tr>
<tr><th>屏幕显示</th><td>状态栏左侧显示 <span class="badge badge-green">🔓</span> 并展示“已撤防 ZONE 1-N”其余保持时钟。</td></tr>
<tr><th>LED 灯效</th><td>绿色慢闪 3 次后熄灭</td></tr>
<tr><th>马达反馈</th><td>接收广播瞬间短振 1 次150ms</td></tr>
<tr><th>逻辑状态</th><td>系统处于撤防ZONE 1-N 的探测触发将被忽略,但 ZONE 0 永久布防区仍能触发报警。</td></tr>
</table>
</div>
</div>
<!-- Section 2 -->
<div class="section-title">二、 传感器配对流程(手环端四步)</div>
<!-- Card 2.1 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<text x="128" y="20" fill="#5A6275" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">PAIRING MODE</text>
<g transform="translate(128, 56)" stroke="#FFB74D" fill="none" stroke-width="2">
<circle cx="0" cy="0" r="4" fill="#FFB74D"/>
<path d="M-8,-8 A12,12 0 0,1 8,-8" stroke-linecap="round"/>
<path d="M-15,-15 A22,22 0 0,1 15,-15" stroke-linecap="round"/>
<path d="M-22,-22 A32,32 0 0,1 22,-22" stroke-linecap="round" stroke-dasharray="2 2"/>
</g>
<text x="128" y="96" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">正在搜索 433MHz 信号...</text>
<text x="128" y="114" fill="#FFB74D" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">请触发目标传感器 | P-00</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">Step 1进入配对模式搜索信号</div>
<table>
<tr><th>触发动作</th><td>用户同时长按 <span class="badge badge-white"></span> + <span class="badge badge-white"></span> 按键 3 秒。</td></tr>
<tr><th>屏幕显示</th><td>顶部展示 PAIRING MODE中央显示天线雷达 <span class="badge badge-orange">📡</span> 波纹动态动画,底部提示等待信号。</td></tr>
<tr><th>LED 灯效</th><td>白色快速闪烁3Hz以示配对工作状态</td></tr>
<tr><th>马达反馈</th><td>短振 1 次100ms作为物理按键确认反馈</td></tr>
<tr><th>超时机制</th><td>30 秒内若无信号输入,自动退出配对返回时钟待机。</td></tr>
</table>
</div>
</div>
<!-- Card 2.2 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<text x="128" y="18" fill="#FFB74D" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle" letter-spacing="1">配对模式 P-00</text>
<text x="24" y="44" fill="#374151" font-family="system-ui, sans-serif" font-size="11">🚪 门磁/窗磁</text>
<rect x="12" y="54" width="232" height="28" rx="4" fill="none" stroke="#00E5FF" stroke-width="1.5"/>
<rect x="220" y="62" width="12" height="12" rx="6" fill="#FF9800"/>
<text x="24" y="72" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="13" font-weight="bold">👤 人体感应 PIR</text>
<text x="24" y="102" fill="#374151" font-family="system-ui, sans-serif" font-size="11">🔥 烟雾传感器</text>
<path d="M244,48 L244,96" stroke="#1F2937" stroke-width="2" stroke-linecap="round"/>
<path d="M244,64 L244,80" stroke="#00E5FF" stroke-width="4" stroke-linecap="round"/>
</svg>
</div>
<div class="details-container">
<div class="step-name">Step 2滚动选择配对类型</div>
<table>
<tr><th>操作方式</th><td>短按 <span class="badge badge-white"></span><span class="badge badge-white"></span> 进行列表滚动。</td></tr>
<tr><th>屏幕显示</th><td>展示 3 行滚动列表,当前选中行(如 PIR加粗并加边框右侧有滚动条指示。</td></tr>
<tr><th>LED 灯效</th><td>持续白色快闪</td></tr>
<tr><th>选中指示</th><td>选中类型的边框会变粗,并在右侧提示对应的专属颜色块。</td></tr>
</table>
</div>
</div>
<!-- Card 2.3 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<circle cx="128" cy="42" r="22" fill="none" stroke="#00E676" stroke-width="3"/>
<path d="M118,42 L125,49 L138,34" fill="none" stroke="#00E676" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<text x="128" y="88" fill="#00E676" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">对码已保存</text>
<text x="128" y="110" fill="#B9F6CA" font-family="system-ui, sans-serif" font-size="12" text-anchor="middle">ADDR: 0x37A86 | TYPE: PIR</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">Step 3-A配对保存成功</div>
<table>
<tr><th>触发动作</th><td>触发目标传感器,发射码与选择类型相符,短按 <span class="badge badge-white">SOS</span> 保存。</td></tr>
<tr><th>屏幕显示</th><td>中央大号绿色 <span class="badge badge-green"></span> 图标,文字展示“对码已保存”及捕获的 24位地址码。</td></tr>
<tr><th>LED 灯效</th><td>绿色常亮 2 秒后熄灭</td></tr>
<tr><th>马达反馈</th><td>强力长振 1 次400ms确认写入成功</td></tr>
<tr><th>名称同步</th><td>接收来自 IPC 摄像头的广播,自动用自定义中文名称替换默认传感器类型名称。</td></tr>
</table>
</div>
</div>
<!-- Card 2.4 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<rect x="4" y="4" width="248" height="120" rx="6" fill="none" stroke="#FF1744" stroke-width="1.5"/>
<circle cx="128" cy="42" r="22" fill="none" stroke="#FF1744" stroke-width="3"/>
<path d="M118,32 L138,52 M138,32 L118,52" fill="none" stroke="#FF1744" stroke-width="4" stroke-linecap="round"/>
<text x="128" y="88" fill="#FF1744" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">对码匹配失败</text>
<text x="128" y="110" fill="#FF8A80" font-family="system-ui, sans-serif" font-size="11" text-anchor="middle">代码类型不一致,请重试</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">Step 3-B对码匹配失败类型不一致</div>
<table>
<tr><th>触发动作</th><td>触发了传感器,但其发射的代码类型与手环当前选中的菜单类型不符。</td></tr>
<tr><th>屏幕显示</th><td>红色大圆圈 <span class="badge badge-red"></span> 图标,大字“对码匹配失败”及提示“代码类型不一致”。</td></tr>
<tr><th>LED 灯效</th><td>红色快闪 3 次</td></tr>
<tr><th>马达反馈</th><td>双击快速短振100ms + 100ms</td></tr>
<tr><th>自动恢复</th><td>界面停留 2 秒后,自动退回到 Step 2 传感器列表选择页面。</td></tr>
</table>
</div>
</div>
<!-- Section 3 -->
<div class="section-title">三、 报警告警模式</div>
<!-- Card 3.1 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<rect x="4" y="4" width="248" height="120" rx="6" fill="none" stroke="#FF3D00" stroke-width="2" stroke-dasharray="8 4"/>
<g transform="translate(116, 20)">
<path d="M4,28 L4,2 L18,2 L18,28 Z" fill="none" stroke="#FF3D00" stroke-width="2"/>
<path d="M4,2 L18,5 L18,25 L4,28 Z" fill="#FF3D00" opacity="0.8"/>
<circle cx="14" cy="15" r="1.5" fill="#0A0D14"/>
</g>
<text x="128" y="82" fill="#FF3D00" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">🚪 前门门磁 触发</text>
<text x="128" y="105" fill="#FF8A80" font-family="system-ui, sans-serif" font-size="12" text-anchor="middle">ZONE 0 | 红色报警</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">3.1 传感器报警触发(以门磁为例)</div>
<table>
<tr><th>触发动作</th><td>待机状态下,接收到已配对传感器发送的报警 433MHz 数据帧。</td></tr>
<tr><th>屏幕显示</th><td>全屏红色闪烁虚线框,中央显示开门状态的 <span class="badge badge-red">🚪</span> 图标,底部显示自定义中文名称。</td></tr>
<tr><th>LED 灯效</th><td>对应传感器专属颜色门磁对应红色PIR对应橙色水浸对应黄色</td></tr>
<tr><th>马达反馈</th><td>对应传感器特定振动模式门磁为1次短振 300ms每 5 秒循环一次)</td></tr>
<tr><th>自动退出</th><td>报警发射停止后5 秒自动超时退出,恢复时钟待机。</td></tr>
</table>
</div>
</div>
<!-- Card 3.2 -->
<div class="card">
<div class="screen-container">
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="128" viewBox="0 0 256 128">
<rect width="256" height="128" rx="8" fill="#0A0D14"/>
<rect x="4" y="4" width="248" height="120" rx="6" fill="none" stroke="#FF1744" stroke-width="2"/>
<rect x="8" y="8" width="240" height="112" rx="4" fill="none" stroke="#FF1744" stroke-width="1" stroke-dasharray="6 3"/>
<g transform="translate(116, 20)" fill="#FF1744">
<rect x="2" y="18" width="20" height="6" rx="1"/>
<path d="M4,18 C4,8 20,8 20,18 Z"/>
<line x1="-4" y1="6" x2="2" y2="12" stroke="#FF1744" stroke-width="2" stroke-linecap="round"/>
<line x1="12" y1="-4" x2="12" y2="4" stroke="#FF1744" stroke-width="2" stroke-linecap="round"/>
<line x1="28" y1="6" x2="22" y2="12" stroke="#FF1744" stroke-width="2" stroke-linecap="round"/>
</g>
<text x="128" y="85" fill="#FF1744" font-family="system-ui, sans-serif" font-size="18" font-weight="bold" text-anchor="middle" letter-spacing="2">🚨 紧急求救 SOS</text>
<text x="128" y="108" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">手环触发 | 最高优先级</text>
</svg>
</div>
<div class="details-container">
<div class="step-name">3.2 紧急 SOS 触发(最高优先级)</div>
<table>
<tr><th>触发动作</th><td>用户在手环上短按 SOS 键,或接收到其它手环广播的 SOS 求救信号。</td></tr>
<tr><th>屏幕显示</th><td>红色宽警告边框,中央闪烁旋转警灯 <span class="badge badge-red">🚨</span>,全屏显示“紧急求救 SOS”。</td></tr>
<tr><th>LED 灯效</th><td>红色极速闪烁5Hz</td></tr>
<tr><th>马达反馈</th><td>持续不断的长周期振动1200ms 长振循环),用于在危急状态下唤醒睡眠或提醒用户。</td></tr>
<tr><th>解除机制</th><td>长按手环按键或在 IPC 主机/手机 APP 上点击“解除警报”。</td></tr>
</table>
</div>
</div>
<!-- Section 4 -->
<div class="section-title">四、 传感器与振动灯效映射表</div>
<div class="card" style="flex-direction: column; background-color: #0F172A; border: 1px solid #334155;">
<div class="step-name" style="color: #FFB74D;">7类传感器及手环动作参数汇总</div>
<table style="font-size: 0.95rem; line-height: 1.8;">
<thead>
<tr style="border-bottom: 2px solid #334155; color: #94A3B8;">
<th>代码</th>
<th>类型</th>
<th>LED 颜色</th>
<th>振动模式</th>
<th>单次振动时长</th>
<th>振动间隔</th>
<th>应用场景说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><b>0001 (A)</b></td>
<td>🚪 门磁/窗磁</td>
<td><span class="badge" style="background-color: #7f1d1d; color: #fca5a5;">● 红色</span></td>
<td>1 次短振</td>
<td>300 ms</td>
<td></td>
<td>进出口边界安全防护(最高优先级)</td>
</tr>
<tr>
<td><b>0010 (B)</b></td>
<td>👤 人体感应 PIR</td>
<td><span class="badge" style="background-color: #7c2d12; color: #ffedd5;">● 橙色</span></td>
<td>2 次短振</td>
<td>300 ms</td>
<td>200 ms</td>
<td>室内移动探测及婴儿防翻身/攀爬监控</td>
</tr>
<tr>
<td><b>0011 (C)</b></td>
<td>🔥 烟雾传感器</td>
<td><span class="badge" style="background-color: #064e3b; color: #6ee7b7;">● 绿色</span></td>
<td>3 次短振</td>
<td>200 ms</td>
<td>150 ms</td>
<td>火灾烟雾探测与厨房安全监控</td>
</tr>
<tr>
<td><b>0100 (D)</b></td>
<td>🆘 紧急按钮</td>
<td><span class="badge" style="background-color: #1e3a8a; color: #93c5fd;">● 蓝色</span></td>
<td>1 次长振</td>
<td>800 ms</td>
<td></td>
<td>人工手动紧急一键求助呼叫</td>
</tr>
<tr>
<td><b>0101 (E)</b></td>
<td>💨 气体传感器</td>
<td><span class="badge" style="background-color: #581c87; color: #e9d5ff;">● 紫色</span></td>
<td>4 次短振</td>
<td>200 ms</td>
<td>100 ms</td>
<td>一氧化碳/天然气泄漏高危报警</td>
</tr>
<tr>
<td><b>0110 (F)</b></td>
<td>💧 水浸传感器</td>
<td><span class="badge" style="background-color: #78350f; color: #fef3c7;">● 黄色</span></td>
<td>2 次长振</td>
<td>600 ms</td>
<td>300 ms</td>
<td>水管漏水/积水外溢高湿防护</td>
</tr>
<tr>
<td><b>0111 (G)</b></td>
<td>📳 振动传感器</td>
<td><span class="badge" style="background-color: #134e5e; color: #e0f7fa;">● 青色</span></td>
<td>连续 3 次</td>
<td>150 ms</td>
<td>100 ms</td>
<td>保险柜/主门防撬外力振动监测</td>
</tr>
<tr>
<td><b>1000 (SOS)</b></td>
<td>🚨 手环紧急求救</td>
<td><span class="badge" style="background-color: #7f1d1d; color: #fca5a5; animation: flash 1s infinite;">● 红色闪烁</span></td>
<td>持续长振</td>
<td>1200 ms 循环</td>
<td></td>
<td>手环端独立发起最高优先级报警凌驾所有Zone</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,440 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Wristband OLED UI Gallery</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: #0A0D14;
color: #E2E8F0;
margin: 0;
padding: 40px 20px;
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
font-size: 2.2rem;
color: #00E5FF;
text-align: center;
margin-bottom: 8px;
letter-spacing: 1px;
}
.subtitle {
text-align: center;
color: #94A3B8;
font-size: 1.1rem;
margin-bottom: 50px;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 40px;
justify-items: center;
}
.card {
background-color: #161B22;
border-radius: 16px;
border: 1px solid #30363D;
padding: 24px;
text-align: center;
width: 270px;
box-shadow: 0 8px 30px rgba(0,0,0,0.5);
transition: transform 0.2s, border-color 0.2s;
display: flex;
flex-direction: column;
}
.card:hover {
transform: translateY(-5px);
border-color: #00E5FF;
}
.card-title {
font-size: 1.1rem;
font-weight: bold;
color: #FFB74D;
margin-bottom: 8px;
}
.card-desc {
font-size: 0.85rem;
color: #8B949E;
margin-bottom: 20px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
/* Realistic Smartwatch CSS Simulator */
.watch-device {
position: relative;
width: 160px;
height: 280px;
background: linear-gradient(135deg, #2D3748 0%, #1A202C 100%);
border-radius: 35px;
border: 5px solid #4A5568;
box-shadow: inset 0 0 10px rgba(0,0,0,0.8), 0 10px 20px rgba(0,0,0,0.6);
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}
.watch-device::before {
content: '';
position: absolute;
top: -20px;
left: 45px;
width: 70px;
height: 20px;
background-color: #2D3748;
border-radius: 5px 5px 0 0;
z-index: -1;
}
.watch-device::after {
content: '';
position: absolute;
bottom: -20px;
left: 45px;
width: 70px;
height: 20px;
background-color: #2D3748;
border-radius: 0 0 5px 5px;
z-index: -1;
}
.screen-bezel {
position: relative;
width: 130px;
height: 250px;
background-color: #000000;
border-radius: 25px;
border: 2px solid #0D1117;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
/* Inlined SVG Scaling */
.screen-bezel svg {
width: 120px;
height: 240px;
display: block;
}
/* Button operations instruction block */
.card-ops {
font-size: 0.8rem;
color: #E2E8F0;
margin-top: 20px;
text-align: left;
background-color: #0D1117;
padding: 12px;
border-radius: 8px;
border: 1px solid #21262D;
min-height: 70px;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
.card-ops b {
color: #FFB74D;
display: block;
margin-bottom: 4px;
font-size: 0.85rem;
}
</style>
</head>
<body>
<div class="container">
<h1>手环 OLED 屏幕 UI 效果图画册 (V1.5)</h1>
<div class="subtitle">所有 10 类显示界面在手环硬件上的 1:1 视觉仿真效果及按键映射说明</div>
<div class="grid">
<!-- 1. Normal Clock -->
<div class="card">
<div class="card-title">1. 待机时钟界面</div>
<div class="card-desc">常规待机状态,顶部仅显示电量,界面宽裕</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Status Bar (Right: Battery Icon) -->
<rect x="82" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
<rect x="84" y="29" width="13" height="6" rx="1" fill="#10B981"/>
<rect x="103" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
<text x="76" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
<!-- Time -->
<text x="60" y="115" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" text-anchor="middle">10:35</text>
<!-- Date -->
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">THU 07-02</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
长按 ▲ 键 3 秒进入配对菜单;双击 ▲+▼ 组合键切换布防;长按 SOS 键 5 秒触发【本机求救】。
</div>
</div>
<!-- 2. Armed Clock -->
<div class="card">
<div class="card-title">2. 系统布防时钟</div>
<div class="card-desc">布防锁定 🔒 移至正下方,完美避免电池重叠</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Status Bar (Right: Battery Icon) -->
<rect x="82" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
<rect x="84" y="29" width="13" height="6" rx="1" fill="#10B981"/>
<rect x="103" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
<text x="76" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
<!-- Time -->
<text x="60" y="115" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" text-anchor="middle">10:35</text>
<!-- Date -->
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">THU 07-02</text>
<!-- Armed Status at the very bottom (Y=205) -->
<g transform="translate(36, 192)">
<rect x="0" y="0" width="12" height="12" rx="2" fill="none" stroke="#EF4444" stroke-width="1.2"/>
<circle cx="6" cy="4" r="2.5" fill="none" stroke="#EF4444" stroke-width="1.2"/>
<rect x="5" y="6" width="2" height="3" fill="#EF4444"/>
</g>
<text x="60" y="202" fill="#EF4444" font-family="system-ui, sans-serif" font-size="9" font-weight="bold" text-anchor="middle"> ARMED</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
双击 ▲+▼ 组合键本地切换为撤防状态;长按 SOS 键 5 秒触发【本机求救】。
</div>
</div>
<!-- 3. Disarmed Clock -->
<div class="card">
<div class="card-title">3. 系统撤防时钟</div>
<div class="card-desc">撤防解锁 🔓 移至正下方,界面均衡清爽</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Status Bar (Right: Battery Icon) -->
<rect x="82" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
<rect x="84" y="29" width="13" height="6" rx="1" fill="#10B981"/>
<rect x="103" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
<text x="76" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
<!-- Time -->
<text x="60" y="115" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" text-anchor="middle">10:35</text>
<!-- Date -->
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">THU 07-02</text>
<!-- Disarmed Status at the very bottom (Y=205) -->
<g transform="translate(32, 192)">
<rect x="0" y="3" width="12" height="9" rx="1.5" fill="none" stroke="#10B981" stroke-width="1.2"/>
<path d="M 3 3 L 3 1.5 C 3 0.7, 6 0.7, 8 1.5 L 8 4" fill="none" stroke="#10B981" stroke-width="1.2"/>
</g>
<text x="60" y="202" fill="#10B981" font-family="system-ui, sans-serif" font-size="9" font-weight="bold" text-anchor="middle"> DISARM</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
双击 ▲+▼ 组合键本地切换为布防状态;长按 SOS 键 5 秒触发【本机求救】。
</div>
</div>
<!-- 4. Pairing Menu -->
<div class="card">
<div class="card-title">4. 滚动选择菜单</div>
<div class="card-desc">选择要对码配对的传感器类型</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<text x="60" y="35" fill="#FFB74D" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">PAIR MENU P-00</text>
<text x="60" y="80" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">🚪 DOOR SENSOR</text>
<rect x="10" y="105" width="100" height="30" rx="6" fill="none" stroke="#00E5FF" stroke-width="1.5"/>
<text x="60" y="124" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">👤 PIR MOTION</text>
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">🔥 SMOKE DETECT</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
单击 ▲ 向上移动,单击 ▼ 向下移动;短按 SOS 确认选中进入搜索状态;长按 ▼ 3 秒退出。
</div>
</div>
<!-- 5. Pairing Search -->
<div class="card">
<div class="card-title">5. 配对对码搜索</div>
<div class="card-desc">雷达波纹 📡 扫射等待射频对码信号</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<g transform="translate(0, 10)">
<path d="M 60 70 L 60 90 M 52 75 A 10 10 0 0 1 68 75 M 48 70 A 15 15 0 0 1 72 70 M 44 65 A 20 20 0 0 1 76 65" stroke="#00E5FF" stroke-width="2" fill="none" stroke-linecap="round"/>
<circle cx="60" cy="92" r="2" fill="#00E5FF"/>
</g>
<text x="60" y="145" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">SEARCHING...</text>
<text x="60" y="170" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">TRIGGER SENSOR</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
等待传感器触发。捕获成功且类型匹配时,系统将<b>自动跳转至对码确认页面</b>。长按 ▼ 3 秒退出。
</div>
</div>
<!-- 6. Pairing Confirm -->
<div class="card">
<div class="card-title">6. 扫码成功确认</div>
<div class="card-desc">对码捕获成功后的长按保存提示</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<circle cx="60" cy="120" r="58" stroke="#334155" stroke-width="1" fill="none"/>
<g transform="translate(0, 10)">
<circle cx="60" cy="80" r="28" stroke="#FFB74D" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
<rect x="46" y="74" width="28" height="20" rx="3" fill="none" stroke="#FFB74D" stroke-width="2.5"/>
<circle cx="60" cy="81" r="2.5" fill="#FFB74D"/>
<path d="M 60 83.5 L 60 88" stroke="#FFB74D" stroke-width="2" stroke-linecap="round"/>
<path d="M 52 74 L 52 64 A 8 8 0 0 1 68 64 L 68 70" fill="none" stroke="#FFB74D" stroke-width="2.5" stroke-linecap="round"/>
</g>
<text x="60" y="145" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">CODE FOUND</text>
<text x="60" y="170" fill="#FFB74D" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">HOLD SOS TO SAVE</text>
<text x="60" y="192" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">ADDR: 0x37A86</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
长按 SOS 键 3 秒确认保存并写入 EEPROM ➔ 进入【对码成功】页面;长按 ▼ 3 秒放弃并返回菜单。
</div>
</div>
<!-- 7. Pair Saved -->
<div class="card">
<div class="card-title">7. 对码保存成功</div>
<div class="card-desc">高保真圆形对勾绿色成功徽章 (✓)</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Symmetrical Circular Success Badge -->
<circle cx="60" cy="90" r="24" stroke="#10B981" stroke-width="2.5" fill="none"/>
<path d="M 48 90 L 56 98 L 72 82" stroke="#10B981" stroke-width="3.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<text x="60" y="145" fill="#10B981" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">PAIR SUCCESS</text>
<text x="60" y="175" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">ADDR: 0x37A86</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
纯状态提示,自动显示 2 秒后回退到待机,无需任何按键操作。
</div>
</div>
<!-- 8. Pair Fail -->
<div class="card">
<div class="card-title">8. 对码匹配失败</div>
<div class="card-desc">高保真圆形红叉失败徽章 (❌)</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Symmetrical Circular Fail Badge -->
<circle cx="60" cy="90" r="24" stroke="#EF4444" stroke-width="2.5" fill="none"/>
<path d="M 50 80 L 70 100 M 70 80 L 50 100" stroke="#EF4444" stroke-width="3.5" fill="none" stroke-linecap="round"/>
<text x="60" y="155" fill="#EF4444" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">PAIR FAILED</text>
<text x="60" y="180" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">TYPE MISMATCH</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
自动显示 5 秒后回退到配对菜单,或短按任意键立即回退到配对菜单。
</div>
</div>
<!-- 9. Alarm Received -->
<div class="card">
<div class="card-title">9. 收到传感器警报</div>
<div class="card-desc">门磁/烟感等传感器触发的警报画面</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<rect x="4" y="4" width="112" height="232" rx="20" stroke="#EF4444" stroke-width="2.5" fill="none" stroke-dasharray="6 4"/>
<g transform="translate(0, 10)">
<rect x="52" y="55" width="16" height="30" rx="1" fill="none" stroke="#EF4444" stroke-width="2.5"/>
<circle cx="64" cy="70" r="1.5" fill="#EF4444"/>
</g>
<text x="60" y="130" fill="#EF4444" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">FRONT DOOR</text>
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">ZONE 0 | ALARM</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
短按手环任意键(▲/▼/SOS均可手动清除警报、消音并返回时钟待机。
</div>
</div>
<!-- 10. Emitted SOS -->
<div class="card">
<div class="card-title">10. 本机紧急求救 SOS</div>
<div class="card-desc">高保真闪光警报灯图标,字形避开边缘</div>
<div class="watch-device">
<div class="screen-bezel">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<rect x="4" y="4" width="112" height="232" rx="20" stroke="#EF4444" stroke-width="2.5" fill="none"/>
<rect x="8" y="8" width="104" height="224" rx="17" stroke="#FFFFFF" stroke-width="1" fill="none"/>
<!-- High-Fidelity Siren Icon -->
<g transform="translate(0, -3)">
<!-- Light Beams -->
<path d="M 60 48 L 60 54 M 45 52 L 50 57 M 75 52 L 70 57 M 40 65 L 46 67 M 80 65 L 74 67" stroke="#EF4444" stroke-width="2" stroke-linecap="round"/>
<!-- Siren Glass Dome -->
<path d="M 46 82 C 46 64, 74 64, 74 82 Z" fill="#EF4444" stroke="#EF4444" stroke-width="1.5"/>
<!-- Bulb inside -->
<circle cx="60" cy="77" r="4.5" fill="#FFFFFF"/>
<!-- Metallic Base -->
<rect x="42" y="82" width="36" height="6" rx="1.5" fill="#64748B"/>
</g>
<!-- Centered SOS Alarm Texts safely inside circular active area -->
<text x="60" y="138" fill="#EF4444" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">🆘 EMIT SOS</text>
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">BAND TRIGGERED</text>
</svg>
</div>
</div>
<div class="card-ops">
<b>按键操作:</b>
长按 SOS 键 5 秒解除报警;或接收到主机的远程撤防指令自动解除。
</div>
</div>
</div>
</div>
</body>
</html>

465
Drivers/lcd.c Normal file
View File

@@ -0,0 +1,465 @@
#include "lcd.h"
#include "lcd_font.h"
#include "../App/config.h"
#include "intrins.h"
// RM69310 屏幕接口引脚
sbit LCD_RST = P1^0; // 硬件复位
sbit LCD_DCX = P1^1; // 数据/命令选择
sbit LCD_SDI = P1^4; // SPI 数据输入 (MOSI)
sbit LCD_SCL = P1^5; // SPI 时钟 (SCLK)
sbit LCD_CS = P1^6; // SPI 片选 (CS)
// SGM3833 电源芯片控制脚
sbit SGM_CTRL = P3^4;
// External delay functions defined in main.c
extern void Delay_ms(u16 ms);
extern void Delay10us(void);
void SGM_SendPulse(u8 pulse_cnt)
{
u8 i;
SGM_CTRL = 0;
Delay_ms(5); // 确保进入关断/复位状态 (tOFF)
SGM_CTRL = 1;
Delay_ms(5); // 确保充分初始化 (tINIT >= 300us)
for(i = 0; i < pulse_cnt; i++)
{
SGM_CTRL = 0;
Delay10us();
SGM_CTRL = 1;
Delay10us();
}
SGM_CTRL = 1;
Delay_ms(5); // 确保数据稳定存储 (tSTORE >= 80us)
}
void SPI_SendData(u8 dat)
{
u8 i;
for(i = 0; i < 8; i++)
{
LCD_SCL = 0;
if(dat & 0x80)
LCD_SDI = 1;
else
LCD_SDI = 0;
_nop_();
LCD_SCL = 1;
_nop_();
dat <<= 1;
}
}
void WriteComm(u8 cmd)
{
LCD_CS = 0;
LCD_DCX = 0; // 命令模式
SPI_SendData(cmd);
LCD_CS = 1;
}
void WriteData(u8 dat)
{
LCD_CS = 0;
LCD_DCX = 1; // 数据模式
SPI_SendData(dat);
LCD_CS = 1;
}
void LCD_Reset(void)
{
LCD_RST = 1;
Delay_ms(10);
LCD_RST = 0;
Delay_ms(20);
LCD_RST = 1;
Delay_ms(120);
}
void LCD_Init(void)
{
// Configure LCD pins as push-pull output
P1M1 &= ~((1<<0) | (1<<1) | (1<<4) | (1<<5) | (1<<6));
P1M0 |= ((1<<0) | (1<<1) | (1<<4) | (1<<5) | (1<<6));
// Configure P3.4 (SGM_CTRL) as push-pull output
P3M1 &= ~(1 << 4);
P3M0 |= (1 << 4);
SGM_CTRL = 1;
LCD_CS = 1;
LCD_SCL = 1;
LCD_RST = 1;
LCD_DCX = 1;
LCD_Reset();
// 寄存器配置(源自 Truly 信利官方初始化配置)
WriteComm(0xFE);WriteData(0x01);
WriteComm(0x04);WriteData(0xa0); // SPI write ram enable
WriteComm(0x05);WriteData(0x70); // 128RGB
WriteComm(0x06);WriteData(0x3C); // NL = 240 line
WriteComm(0x25);WriteData(0x06); // normal mode: gamma1
WriteComm(0x26);WriteData(0x80); // T1A = 280
WriteComm(0x27);WriteData(0x12); // normal mode VBP = 12
WriteComm(0x28);WriteData(0x12); // normal mode VFP = 8
WriteComm(0x2A);WriteData(0x06); // idle mode: gamma1
WriteComm(0x2B);WriteData(0x80); // T1B = 280
WriteComm(0x2D);WriteData(0x12); // idle mode VBP = 12
WriteComm(0x2F);WriteData(0x12); // idle mode VFP = 8
WriteComm(0x37);WriteData(0x0C); // precharge to VGSP
WriteComm(0x6D);WriteData(0x18); // skip frame VGMP and VGSP regulator off
WriteComm(0x29);WriteData(0x01); // normal mode skip frame off
WriteComm(0x30);WriteData(0x43); // idle mode skip frame = 60/2 = 30Hz
WriteComm(0x0E);WriteData(0x83); // AVDD = 5.6V normal mode
WriteComm(0x0F);WriteData(0x83); // AVDD = 5.6V idle mode
WriteComm(0x10);WriteData(0x71); // AVDD = 3xVCI
WriteComm(0x11);WriteData(0xb3); // VCL = -2xVCI
WriteComm(0x12);WriteData(0xb3); // VCL = -2xVCI
WriteComm(0x13);WriteData(0x80); // VGH = AVDD normal mode
WriteComm(0x14);WriteData(0x80); // VGH = AVDD idle mode
WriteComm(0x15);WriteData(0x81); // VGL = VCL - VCI normal mode
WriteComm(0x16);WriteData(0x81); // VGL = VCL - VCI idle mode
WriteComm(0x18);WriteData(0x66); // VGHR = 6V normal/idle mode
WriteComm(0x19);WriteData(0x44); // VGLR = -6V normal/idle mode
WriteComm(0x1E);WriteData(0x02); // Switch EQ on
WriteComm(0x5B);WriteData(0x10); // VREFN5 on
WriteComm(0x62);WriteData(0x19); // VREFN5 = -3V normal mode
WriteComm(0x63);WriteData(0x19); // VREFN5 = -3V idle mode
WriteComm(0x70);WriteData(0x55); // display off SD to AVDD
WriteComm(0x1D);WriteData(0x02); // Switch EQ on
WriteComm(0x89);WriteData(0x18); // VGMP = 5.5V
WriteComm(0x8A);WriteData(0xb9); // VGSP = 2V
WriteComm(0x8B);WriteData(0x01); // VGMP VGSP high byte
WriteComm(0x8C);WriteData(0x10); // VGMP = 5.4V
WriteComm(0x8D);WriteData(0x90); // VGSP = 2V
WriteComm(0x8E);WriteData(0x01); // VGMP VGSP high byte
WriteComm(0x6E);WriteData(0x0A); // MIPI interface off
WriteComm(0x6A);WriteData(0x05); // MUX
WriteComm(0x3A);WriteData(0x08); // T1_sd
WriteComm(0x3B);WriteData(0x00); // Tp_sd
WriteComm(0x3D);WriteData(0x16); // Th_sd
WriteComm(0x3F);WriteData(0x27); // Tsw_sd
WriteComm(0x40);WriteData(0x0F); // Thsw_sd
WriteComm(0x41);WriteData(0x0D); // Thsd_sd
WriteComm(0x42);WriteData(0x14); // Mux 142536
WriteComm(0x43);WriteData(0x41);
WriteComm(0x44);WriteData(0x25);
WriteComm(0x45);WriteData(0x52);
WriteComm(0x46);WriteData(0x36);
WriteComm(0x47);WriteData(0x63);
WriteComm(0x48);WriteData(0x14);
WriteComm(0x49);WriteData(0x41);
WriteComm(0x4A);WriteData(0x25);
WriteComm(0x4B);WriteData(0x52);
WriteComm(0x4C);WriteData(0x36);
WriteComm(0x4D);WriteData(0x63);
WriteComm(0x4E);WriteData(0x14); // Data R1R2G1G2B1B2
WriteComm(0x4F);WriteData(0x41);
WriteComm(0x50);WriteData(0x25);
WriteComm(0x51);WriteData(0x52);
WriteComm(0x52);WriteData(0x36);
WriteComm(0x53);WriteData(0x63);
WriteComm(0x54);WriteData(0x14);
WriteComm(0x55);WriteData(0x41);
WriteComm(0x56);WriteData(0x25);
WriteComm(0x57);WriteData(0x52);
WriteComm(0x58);WriteData(0x36);
WriteComm(0x59);WriteData(0x63);
WriteComm(0x66);WriteData(0x90); // idle mode internal power
WriteComm(0x67);WriteData(0x40); // internal power delay 1 frame off
WriteComm(0x72);WriteData(0x1A); // internal OVDD = 4.6V
WriteComm(0x73);WriteData(0x07); // internal OVSS = -2V
WriteComm(0x74);WriteData(0x0C); // OVDD power from AVDD
WriteComm(0x6A);WriteData(0x3D); // swire 61=0x3D pulse
WriteComm(0x6B);WriteData(0x29); // swire 41=0x29 pulse
WriteComm(0xFE);WriteData(0x04);
WriteComm(0x5E);WriteData(0x01);
WriteComm(0x5F);WriteData(0xB8);
WriteComm(0x60);WriteData(0xBB);
WriteComm(0x61);WriteData(0xBB);
WriteComm(0x62);WriteData(0xBB);
WriteComm(0x76);WriteData(0xBB);
WriteComm(0x77);WriteData(0x3B);
WriteComm(0x78);WriteData(0x92);
WriteComm(0x79);WriteData(0xBB);
WriteComm(0x7A);WriteData(0xBB);
WriteComm(0x00);WriteData(0xDC); // SN_CK1
WriteComm(0x01);WriteData(0x00);
WriteComm(0x02);WriteData(0x02);
WriteComm(0x03);WriteData(0x00);
WriteComm(0x04);WriteData(0x08);
WriteComm(0x05);WriteData(0x01);
WriteComm(0x06);WriteData(0x70);
WriteComm(0x07);WriteData(0x0A);
WriteComm(0x08);WriteData(0x00);
WriteComm(0x09);WriteData(0xDC); // SN_CK2
WriteComm(0x0a);WriteData(0x00);
WriteComm(0x0b);WriteData(0x02);
WriteComm(0x0C);WriteData(0x00);
WriteComm(0x0D);WriteData(0x08);
WriteComm(0x0E);WriteData(0x00);
WriteComm(0x0F);WriteData(0x70);
WriteComm(0x10);WriteData(0x0A);
WriteComm(0x11);WriteData(0x00);
WriteComm(0x12);WriteData(0xCC); // EM_CK1
WriteComm(0x13);WriteData(0x00);
WriteComm(0x14);WriteData(0x02);
WriteComm(0x15);WriteData(0x00);
WriteComm(0x16);WriteData(0x20);
WriteComm(0x17);WriteData(0x00);
WriteComm(0x18);WriteData(0x28);
WriteComm(0x19);WriteData(0x26);
WriteComm(0x1A);WriteData(0x00);
WriteComm(0x1B);WriteData(0xCC); // EM_CK2
WriteComm(0x1C);WriteData(0x00);
WriteComm(0x1D);WriteData(0x02);
WriteComm(0x1E);WriteData(0x00);
WriteComm(0x1F);WriteData(0x20);
WriteComm(0x20);WriteData(0x01);
WriteComm(0x21);WriteData(0x28);
WriteComm(0x22);WriteData(0x26);
WriteComm(0x23);WriteData(0x00);
WriteComm(0x4C);WriteData(0x89); // SN_STV
WriteComm(0x4D);WriteData(0x00);
WriteComm(0x4E);WriteData(0x01);
WriteComm(0x4F);WriteData(0x00);
WriteComm(0x50);WriteData(0x01);
WriteComm(0x51);WriteData(0xBB);
WriteComm(0x52);WriteData(0xBB);
WriteComm(0x53);WriteData(0xCA); // EM_STV
WriteComm(0x54);WriteData(0x00);
WriteComm(0x55);WriteData(0x03);
WriteComm(0x56);WriteData(0x00);
WriteComm(0x58);WriteData(0x00);
WriteComm(0x59);WriteData(0x00);
WriteComm(0x65);WriteData(0x45); // 04
WriteComm(0x66);WriteData(0x0C); // 03
WriteComm(0x67);WriteData(0x00); // 10
WriteComm(0xFE);WriteData(0x01); // ID
WriteComm(0xE5);WriteData(0x00);
WriteComm(0xE6);WriteData(0x10);
WriteComm(0xE7);WriteData(0x31);
WriteComm(0xFE);WriteData(0x00); // 切换到 Page 0
WriteComm(0xC4);WriteData(0x80);
WriteComm(0x2A);WriteData(0x00);WriteData(0x04);WriteData(0x00);WriteData(0x7B); // 设置列
// 显式设置 16 位像素格式 (COLMOD = 0x75)
WriteComm(0x3A);WriteData(0x75);
WriteComm(0x11);WriteData(0x00); // 退出睡眠
Delay_ms(150);
WriteComm(0x29);WriteData(0x00); // 开启显示
Delay_ms(20);
}
void LCD_SetWindow(u16 x_start, u16 x_end, u16 y_start, u16 y_end)
{
WriteComm(0x2A);
WriteData((u8)(x_start >> 8));
WriteData((u8)(x_start & 0xFF));
WriteData((u8)(x_end >> 8));
WriteData((u8)(x_end & 0xFF));
WriteComm(0x2B);
WriteData((u8)(y_start >> 8));
WriteData((u8)(y_start & 0xFF));
WriteData((u8)(y_end >> 8));
WriteData((u8)(y_end & 0xFF));
}
void LCD_Clear(u16 color)
{
u16 i, j;
LCD_SetWindow(4, 123, 0, 239);
WriteComm(0x2C);
for(i = 0; i < 120; i++)
{
for(j = 0; j < 240; j++)
{
WriteData((u8)(color >> 8));
WriteData((u8)(color & 0xFF));
}
}
}
void LCD_FillRect(u16 x, u16 y, u16 w, u16 h, u16 color)
{
u16 i, count;
u8 ch = (u8)(color >> 8);
u8 cl = (u8)(color & 0xFF);
LCD_SetWindow(x + 4, x + w - 1 + 4, y, y + h - 1);
WriteComm(0x2C);
count = w * h;
for(i = 0; i < count; i++)
{
WriteData(ch);
WriteData(cl);
}
}
void LCD_DrawRectBorder(u16 x, u16 y, u16 w, u16 h, u16 color)
{
LCD_FillRect(x, y, w, 1, color);
LCD_FillRect(x, y + h - 1, w, 1, color);
LCD_FillRect(x, y, 1, h, color);
LCD_FillRect(x + w - 1, y, 1, h, color);
}
void LCD_DrawMonoBitmap(u16 x, u16 y, u16 w, u16 h, unsigned char code *bmp, u16 color, u16 bg_color)
{
u16 r, c;
u16 byte_width = (w + 7) / 8;
u8 ch = (u8)(color >> 8);
u8 cl = (u8)(color & 0xFF);
u8 bgh = (u8)(bg_color >> 8);
u8 bgl = (u8)(bg_color & 0xFF);
LCD_SetWindow(x + 4, x + w - 1 + 4, y, y + h - 1);
WriteComm(0x2C);
for(r = 0; r < h; r++)
{
for(c = 0; c < w; c++)
{
u16 byte_idx = r * byte_width + (c / 8);
u8 bit_shift = 7 - (c % 8);
if(bmp[byte_idx] & (1 << bit_shift))
{
WriteData(ch);
WriteData(cl);
}
else
{
WriteData(bgh);
WriteData(bgl);
}
}
}
}
void LCD_ShowChar8x16(u16 x, u16 y, char ch, u16 color, u16 bg_color)
{
u8 r, c;
u8 char_idx = ch - 0x20;
u8 f_h = (u8)(color >> 8);
u8 f_l = (u8)(color & 0xFF);
u8 b_h = (u8)(bg_color >> 8);
u8 b_l = (u8)(bg_color & 0xFF);
if(ch < 0x20 || ch > 0x7E) return;
LCD_SetWindow(x + 4, x + 8 - 1 + 4, y, y + 16 - 1);
WriteComm(0x2C);
for(r = 0; r < 16; r++)
{
u8 line = FONT_8x16[char_idx][r];
for(c = 0; c < 8; c++)
{
if(line & (0x80 >> c))
{
WriteData(f_h);
WriteData(f_l);
}
else
{
WriteData(b_h);
WriteData(b_l);
}
}
}
}
void LCD_ShowString(u16 x, u16 y, char *str, u16 color, u16 bg_color)
{
while(*str)
{
LCD_ShowChar8x16(x, y, *str, color, bg_color);
x += 8;
str++;
}
}
void LCD_ShowStringCentered(u16 y, char *str, u16 color, u16 bg_color)
{
u16 len = 0;
char *p = str;
while(*p++) len++;
if(len * 8 >= 120)
LCD_ShowString(0, y, str, color, bg_color);
else
LCD_ShowString((120 - len * 8) / 2, y, str, color, bg_color);
}
void LCD_ShowChar16x32(u16 x, u16 y, char ch, u16 color, u16 bg_color)
{
u8 r, c, i, j;
u8 char_idx = ch - 0x20;
u8 f_h = (u8)(color >> 8);
u8 f_l = (u8)(color & 0xFF);
u8 b_h = (u8)(bg_color >> 8);
u8 b_l = (u8)(bg_color & 0xFF);
if(ch < 0x20 || ch > 0x7E) return;
LCD_SetWindow(x + 4, x + 16 - 1 + 4, y, y + 32 - 1);
WriteComm(0x2C);
for(r = 0; r < 16; r++)
{
u8 line = FONT_8x16[char_idx][r];
for(i = 0; i < 2; i++)
{
for(c = 0; c < 8; c++)
{
u8 val_bit = (line & (0x80 >> c));
for(j = 0; j < 2; j++)
{
if(val_bit)
{
WriteData(f_h);
WriteData(f_l);
}
else
{
WriteData(b_h);
WriteData(b_l);
}
}
}
}
}
}
void LCD_ShowString16x32(u16 x, u16 y, char *str, u16 color, u16 bg_color)
{
while(*str)
{
LCD_ShowChar16x32(x, y, *str, color, bg_color);
x += 16;
str++;
}
}
void LCD_ShowString16x32Centered(u16 y, char *str, u16 color, u16 bg_color)
{
u16 len = 0;
char *p = str;
while(*p++) len++;
if(len * 16 >= 120)
LCD_ShowString16x32(0, y, str, color, bg_color);
else
LCD_ShowString16x32((120 - len * 16) / 2, y, str, color, bg_color);
}

51
Drivers/lcd.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef __LCD_H__
#define __LCD_H__
#include "../App/config.h"
#include "stc32g.h"
// Color Constants (RGB565)
#define COLOR_BLACK 0x0000
#define COLOR_WHITE 0xFFFF
#define COLOR_CYAN 0x073F
#define COLOR_RED 0xF800
#define COLOR_GREEN 0x07E0
#define COLOR_BLUE 0x001F
#define COLOR_GRAY 0x5AEB
#define COLOR_AMBER 0xFDC0
// Public screen functions
void SGM_SendPulse(u8 pulse_cnt);
void LCD_Reset(void);
void LCD_Init(void);
void LCD_SetWindow(u16 x_start, u16 x_end, u16 y_start, u16 y_end);
void LCD_Clear(u16 color);
// Drawing Primitives
void LCD_FillRect(u16 x, u16 y, u16 w, u16 h, u16 color);
void LCD_DrawRectBorder(u16 x, u16 y, u16 w, u16 h, u16 color);
void LCD_DrawMonoBitmap(u16 x, u16 y, u16 w, u16 h, unsigned char code *bmp, u16 color, u16 bg_color);
void LCD_ShowChar8x16(u16 x, u16 y, char ch, u16 color, u16 bg_color);
void LCD_ShowString(u16 x, u16 y, char *str, u16 color, u16 bg_color);
void LCD_ShowStringCentered(u16 y, char *str, u16 color, u16 bg_color);
void LCD_ShowChar16x32(u16 x, u16 y, char ch, u16 color, u16 bg_color);
void LCD_ShowString16x32(u16 x, u16 y, char *str, u16 color, u16 bg_color);
void LCD_ShowString16x32Centered(u16 y, char *str, u16 color, u16 bg_color);
// Font and Bitmap externs (defined in lcd_font.h via lcd.c)
extern unsigned char code FONT_8x16[95][16];
extern unsigned char code bmp_battery_20x10[];
extern unsigned char code bmp_lock_16x16[];
extern unsigned char code bmp_unlock_16x16[];
extern unsigned char code bmp_radar_32x32_f1[];
extern unsigned char code bmp_radar_32x32_f2[];
extern unsigned char code bmp_radar_32x32_f3[];
extern unsigned char code bmp_confirm_lock_32x32[];
extern unsigned char code bmp_checkmark_32x32[];
extern unsigned char code bmp_cross_32x32[];
extern unsigned char code bmp_door_32x32[];
extern unsigned char code bmp_siren_32x32[];
#endif

284
Drivers/lcd_font.h Normal file
View File

@@ -0,0 +1,284 @@
#ifndef __FONT_H__
#define __FONT_H__
// 1. Horizontal Battery Icon (20x10 pixels)
// Width: 20 pixels (3 bytes per row), Height: 10 rows
unsigned char code bmp_battery_20x10[30] = {
0xFF, 0xFF, 0x00, // ####################..
0x80, 0x00, 0x80, // #..................#
0xBF, 0xFB, 0x80, // ##.###############.#
0xBF, 0xFB, 0xE0, // ##.###############.###
0xBF, 0xFB, 0xE0, // ##.###############.###
0xBF, 0xFB, 0xE0, // ##.###############.###
0xBF, 0xFB, 0xE0, // ##.###############.###
0xBF, 0xFB, 0x80, // ##.###############.#
0x80, 0x00, 0x80, // #..................#
0xFF, 0xFF, 0x00 // ####################..
};
// 2. Lock Icon (16x16 pixels)
// Width: 16 pixels (2 bytes per row), Height: 16 rows
unsigned char code bmp_lock_16x16[32] = {
0x07, 0xE0, // ######
0x0C, 0x30, // ## ##
0x18, 0x18, // ## ##
0x18, 0x18, // ## ##
0x18, 0x18, // ## ##
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xE7, 0xE7, // ### ###### ###
0xE7, 0xE7, // ### ###### ###
0xE1, 0x87, // ### #### ###
0xE1, 0x87, // ### #### ###
0xE7, 0xE7, // ### ###### ###
0xE7, 0xE7, // ### ###### ###
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0x00, 0x00 //
};
// 3. Unlock Icon (16x16 pixels)
// Width: 16 pixels (2 bytes per row), Height: 16 rows
unsigned char code bmp_unlock_16x16[32] = {
0x07, 0xE0, // ######
0x0C, 0x30, // ## ##
0x18, 0x00, // ##
0x18, 0x00, // ##
0x18, 0x00, // ##
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0xE7, 0xE7, // ### ###### ###
0xE7, 0xE7, // ### ###### ###
0xE1, 0x87, // ### #### ###
0xE1, 0x87, // ### #### ###
0xE7, 0xE7, // ### ###### ###
0xE7, 0xE7, // ### ###### ###
0xFF, 0xFF, // ################
0xFF, 0xFF, // ################
0x00, 0x00 //
};
// 4. Radar Icon Frame 1 (32x32 pixels, 4 bytes per row)
unsigned char code bmp_radar_32x32_f1[128] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x10, 0x08, 0x00,
0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x07, 0xE0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 5. Radar Icon Frame 2
unsigned char code bmp_radar_32x32_f2[128] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xE0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x40, 0x02, 0x00,
0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
0x00, 0x40, 0x02, 0x00, 0x00, 0x47, 0xE2, 0x00, 0x00, 0x48, 0x12, 0x00, 0x00, 0x50, 0x0A, 0x00,
0x00, 0x50, 0x0A, 0x00, 0x00, 0x50, 0x0A, 0x00, 0x00, 0x48, 0x12, 0x00, 0x00, 0x47, 0xE2, 0x00,
0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
0x00, 0x40, 0x02, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x07, 0xE0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 6. Radar Icon Frame 3 (Complete circles)
unsigned char code bmp_radar_32x32_f3[128] = {
0x00, 0x07, 0xE0, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x40, 0x02, 0x00,
0x00, 0x87, 0xE1, 0x00, 0x01, 0x18, 0x18, 0x80, 0x02, 0x20, 0x04, 0x40, 0x04, 0x40, 0x02, 0x20,
0x04, 0x40, 0x02, 0x20, 0x04, 0x40, 0x02, 0x20, 0x04, 0x40, 0x02, 0x20, 0x04, 0x40, 0x02, 0x20,
0x04, 0x40, 0x02, 0x20, 0x04, 0x47, 0xE2, 0x20, 0x04, 0x48, 0x12, 0x20, 0x04, 0x50, 0x0A, 0x20,
0x04, 0x50, 0x0A, 0x20, 0x04, 0x50, 0x0A, 0x20, 0x04, 0x48, 0x12, 0x20, 0x04, 0x47, 0xE2, 0x20,
0x04, 0x40, 0x02, 0x20, 0x04, 0x40, 0x02, 0x20, 0x04, 0x40, 0x02, 0x20, 0x04, 0x40, 0x02, 0x20,
0x04, 0x40, 0x02, 0x20, 0x02, 0x20, 0x04, 0x40, 0x01, 0x18, 0x18, 0x80, 0x00, 0x87, 0xE1, 0x00,
0x00, 0x40, 0x02, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x07, 0xE0, 0x00
};
// 7. Checkmark Icon (32x32 pixels)
unsigned char code bmp_checkmark_32x32[128] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xFC, 0x00,
0x00, 0xF8, 0x1F, 0x00, 0x01, 0xC0, 0x03, 0x80,
0x03, 0x80, 0x01, 0xC0, 0x07, 0x00, 0x00, 0xE0,
0x0E, 0x00, 0x00, 0x70, 0x0C, 0x00, 0x00, 0x30,
0x18, 0x00, 0x02, 0x18, 0x18, 0x00, 0x07, 0x18,
0x38, 0x00, 0x0E, 0x1C, 0x30, 0x00, 0x1C, 0x0C,
0x30, 0x20, 0x38, 0x0C, 0x30, 0x70, 0x70, 0x0C,
0x30, 0x38, 0xE0, 0x0C, 0x30, 0x1D, 0xC0, 0x0C,
0x30, 0x0F, 0x80, 0x0C, 0x38, 0x07, 0x00, 0x1C,
0x18, 0x02, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18,
0x0C, 0x00, 0x00, 0x30, 0x0E, 0x00, 0x00, 0x70,
0x07, 0x00, 0x00, 0xE0, 0x03, 0x80, 0x01, 0xC0,
0x01, 0xC0, 0x03, 0x80, 0x00, 0xF8, 0x1F, 0x00,
0x00, 0x3F, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 8. Cross Icon (32x32 pixels)
unsigned char code bmp_cross_32x32[128] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xFC, 0x00,
0x00, 0xF8, 0x1F, 0x00, 0x01, 0xC0, 0x03, 0x80,
0x03, 0x80, 0x01, 0xC0, 0x07, 0x00, 0x00, 0xE0,
0x0E, 0x00, 0x00, 0x70, 0x0C, 0x00, 0x00, 0x30,
0x18, 0x10, 0x08, 0x18, 0x18, 0x38, 0x1C, 0x18,
0x38, 0x1C, 0x38, 0x1C, 0x30, 0x0E, 0x70, 0x0C,
0x30, 0x07, 0xE0, 0x0C, 0x30, 0x03, 0xC0, 0x0C,
0x30, 0x03, 0xC0, 0x0C, 0x30, 0x07, 0xE0, 0x0C,
0x30, 0x0E, 0x70, 0x0C, 0x38, 0x1C, 0x38, 0x1C,
0x18, 0x38, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x18,
0x0C, 0x00, 0x00, 0x30, 0x0E, 0x00, 0x00, 0x70,
0x07, 0x00, 0x00, 0xE0, 0x03, 0x80, 0x01, 0xC0,
0x01, 0xC0, 0x03, 0x80, 0x00, 0xF8, 0x1F, 0x00,
0x00, 0x3F, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 9. Door Icon (32x32 pixels)
unsigned char code bmp_door_32x32[128] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0,
0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0,
0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0,
0x0F, 0x00, 0x7C, 0xF0, 0x0F, 0x00, 0x7C, 0xF0, 0x0F, 0x00, 0x7C, 0xF0, 0x0F, 0x00, 0x00, 0xF0,
0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0,
0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0,
0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 10. Siren Icon (32x32 pixels)
unsigned char code bmp_siren_32x32[128] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00,
0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00,
0x06, 0x01, 0x80, 0x60, 0x07, 0x01, 0x80, 0xE0,
0x03, 0x81, 0x81, 0xC0, 0x01, 0xC0, 0x03, 0x80,
0x00, 0xE0, 0x07, 0x00, 0x00, 0x60, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7C, 0x0F, 0xF0, 0x3E, 0x00, 0x1F, 0xF8, 0x00,
0x00, 0x3F, 0xFC, 0x00, 0x00, 0x7F, 0xFE, 0x00,
0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00,
0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x80,
0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0,
0x03, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xC0,
0x03, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 11. Unlocked Padlock Icon (32x32 pixels, for confirmation page)
unsigned char code bmp_confirm_lock_32x32[128] = {
0x00, 0x03, 0xC0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x1C, 0x38, 0x00, 0x00, 0x38, 0x1C, 0x00,
0x00, 0x30, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
0x00, 0x30, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0,
0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x03, 0xC0, 0xF0,
0x0F, 0x03, 0xC0, 0xF0, 0x0F, 0x03, 0xC0, 0xF0, 0x0F, 0x03, 0xC0, 0xF0, 0x0F, 0x01, 0x80, 0xF0,
0x0F, 0x01, 0x80, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF0,
0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xE0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// Standard ASCII 8x16 Font Library
// 95 printable characters (0x20 to 0x7E)
// Each character takes 16 bytes.
unsigned char code FONT_8x16[95][16] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x20 Space
{0x00,0x00,0x0C,0x1C,0x1C,0x1C,0x0C,0x0C,0x08,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00}, // 0x21 !
{0x00,0x00,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x22 "
{0x00,0x00,0x24,0x24,0x7E,0x24,0x24,0x7E,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00}, // 0x23 #
{0x00,0x00,0x08,0x1C,0x2A,0x0A,0x0A,0x1C,0x28,0x28,0x2A,0x1C,0x08,0x00,0x00,0x00}, // 0x24 $
{0x00,0x00,0x62,0x94,0x98,0x68,0x10,0x26,0x49,0x49,0x26,0x00,0x00,0x00,0x00,0x00}, // 0x25 %
{0x00,0x00,0x00,0x0C,0x12,0x12,0x0C,0x15,0x22,0x22,0x1D,0x00,0x00,0x00,0x00,0x00}, // 0x26 &
{0x00,0x00,0x0C,0x0C,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x27 '
{0x00,0x00,0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00,0x00}, // 0x28 (
{0x00,0x00,0x10,0x08,0x04,0x04,0x02,0x02,0x02,0x02,0x04,0x04,0x08,0x10,0x00,0x00}, // 0x29 )
{0x00,0x00,0x00,0x08,0x2A,0x1C,0x08,0x1C,0x2A,0x08,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x2A *
{0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x7F,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00}, // 0x2B +
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x08,0x10,0x00,0x00}, // 0x2C ,
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x2D -
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00}, // 0x2E .
{0x00,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x00,0x00}, // 0x2F /
{0x00,0x00,0x1C,0x22,0x22,0x26,0x2A,0x32,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x30 0
{0x00,0x00,0x08,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x31 1
{0x00,0x00,0x1C,0x22,0x22,0x04,0x08,0x10,0x20,0x22,0x3F,0x00,0x00,0x00,0x00,0x00}, // 0x32 2
{0x00,0x00,0x1C,0x22,0x02,0x06,0x18,0x02,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x33 3
{0x00,0x00,0x02,0x06,0x0A,0x12,0x22,0x7F,0x02,0x02,0x07,0x00,0x00,0x00,0x00,0x00}, // 0x34 4
{0x00,0x00,0x3F,0x20,0x20,0x3C,0x22,0x02,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x35 5
{0x00,0x00,0x1C,0x22,0x20,0x3C,0x22,0x22,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x36 6
{0x00,0x00,0x3F,0x22,0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00}, // 0x37 7
{0x00,0x00,0x1C,0x22,0x22,0x1C,0x22,0x22,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x38 8
{0x00,0x00,0x1C,0x22,0x22,0x22,0x22,0x1E,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x39 9
{0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00}, // 0x3A :
{0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x0C,0x0C,0x08,0x10,0x00,0x00,0x00}, // 0x3B ;
{0x00,0x00,0x02,0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x02,0x00,0x00,0x00,0x00,0x00}, // 0x3C <
{0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x3D =
{0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x04,0x08,0x10,0x20,0x00,0x00,0x00,0x00,0x00}, // 0x3E >
{0x00,0x00,0x1C,0x22,0x22,0x02,0x04,0x08,0x08,0x00,0x08,0x08,0x00,0x00,0x00,0x00}, // 0x3F ?
{0x00,0x00,0x1C,0x22,0x4A,0x56,0x52,0x52,0x4C,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x40 @
{0x00,0x00,0x08,0x14,0x22,0x22,0x3E,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x41 A
{0x00,0x00,0x3C,0x22,0x22,0x3C,0x22,0x22,0x22,0x22,0x3C,0x00,0x00,0x00,0x00,0x00}, // 0x42 B
{0x00,0x00,0x1C,0x22,0x20,0x20,0x20,0x20,0x20,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x43 C
{0x00,0x00,0x38,0x24,0x22,0x22,0x22,0x22,0x22,0x24,0x38,0x00,0x00,0x00,0x00,0x00}, // 0x44 D
{0x00,0x00,0x3E,0x20,0x20,0x3C,0x20,0x20,0x20,0x20,0x3E,0x00,0x00,0x00,0x00,0x00}, // 0x45 E
{0x00,0x00,0x3E,0x20,0x20,0x3C,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00}, // 0x46 F
{0x00,0x00,0x1C,0x22,0x20,0x20,0x27,0x22,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x47 G
{0x00,0x00,0x22,0x22,0x22,0x22,0x3E,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x48 H
{0x00,0x00,0x1C,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x49 I
{0x00,0x00,0x0E,0x02,0x02,0x02,0x02,0x02,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x4A J
{0x00,0x00,0x22,0x24,0x28,0x30,0x20,0x30,0x28,0x24,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x4B K
{0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3E,0x00,0x00,0x00,0x00,0x00}, // 0x4C L
{0x00,0x00,0x22,0x36,0x2A,0x2A,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x4D M
{0x00,0x00,0x22,0x32,0x2A,0x26,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x4E N
{0x00,0x00,0x1C,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x4F O
{0x00,0x00,0x3C,0x22,0x22,0x3C,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00}, // 0x50 P
{0x00,0x00,0x1C,0x22,0x22,0x22,0x22,0x2A,0x24,0x22,0x1D,0x00,0x00,0x00,0x00,0x00}, // 0x51 Q
{0x00,0x00,0x3C,0x22,0x22,0x3C,0x28,0x24,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x52 R
{0x00,0x00,0x1C,0x22,0x20,0x1C,0x02,0x02,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x53 S
{0x00,0x00,0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x54 T
{0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x55 U
{0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x56 V
{0x00,0x00,0x22,0x22,0x22,0x2A,0x2A,0x2A,0x2A,0x14,0x14,0x00,0x00,0x00,0x00,0x00}, // 0x57 W
{0x00,0x00,0x22,0x22,0x14,0x08,0x08,0x08,0x14,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x58 X
{0x00,0x00,0x22,0x22,0x22,0x14,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x59 Y
{0x00,0x00,0x3E,0x02,0x04,0x08,0x10,0x20,0x20,0x20,0x3E,0x00,0x00,0x00,0x00,0x00}, // 0x5A Z
{0x00,0x00,0x1E,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1E,0x00,0x00,0x00,0x00,0x00}, // 0x5B [
{0x00,0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00,0x00,0x00,0x00,0x00}, // 0x5C Backslash
{0x00,0x00,0x3C,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x3C,0x00,0x00,0x00,0x00,0x00}, // 0x5D ]
{0x00,0x00,0x08,0x14,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x5E ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00}, // 0x5F _
{0x00,0x00,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x60 `
{0x00,0x00,0x00,0x00,0x1C,0x02,0x1E,0x22,0x22,0x26,0x1F,0x00,0x00,0x00,0x00,0x00}, // 0x61 a
{0x00,0x00,0x20,0x20,0x3C,0x22,0x22,0x22,0x22,0x22,0x3C,0x00,0x00,0x00,0x00,0x00}, // 0x62 b
{0x00,0x00,0x00,0x00,0x1C,0x22,0x20,0x20,0x20,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x63 c
{0x00,0x00,0x02,0x02,0x1E,0x22,0x22,0x22,0x22,0x22,0x1E,0x00,0x00,0x00,0x00,0x00}, // 0x64 d
{0x00,0x00,0x00,0x00,0x1C,0x22,0x3E,0x20,0x20,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x65 e
{0x00,0x00,0x0E,0x10,0x10,0x3C,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00}, // 0x66 f
{0x00,0x00,0x00,0x00,0x1E,0x22,0x22,0x22,0x1E,0x02,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x67 g
{0x00,0x00,0x20,0x20,0x3C,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x68 h
{0x00,0x00,0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x69 i
{0x00,0x00,0x02,0x00,0x06,0x02,0x02,0x02,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x6A j
{0x00,0x00,0x20,0x20,0x22,0x24,0x28,0x30,0x28,0x24,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x6B k
{0x00,0x00,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x6C l
{0x00,0x00,0x00,0x00,0x3A,0x2A,0x2A,0x2A,0x2A,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x6D m
{0x00,0x00,0x00,0x00,0x2E,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x6E n
{0x00,0x00,0x00,0x00,0x1C,0x22,0x22,0x22,0x22,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x6F o
{0x00,0x00,0x00,0x00,0x3C,0x22,0x22,0x3C,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00}, // 0x70 p
{0x00,0x00,0x00,0x00,0x1E,0x22,0x22,0x1E,0x02,0x02,0x02,0x02,0x02,0x00,0x00,0x00}, // 0x71 q
{0x00,0x00,0x00,0x00,0x2E,0x12,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00}, // 0x72 r
{0x00,0x00,0x00,0x00,0x1E,0x20,0x1C,0x02,0x02,0x22,0x1C,0x00,0x00,0x00,0x00,0x00}, // 0x73 s
{0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x08,0x08,0x08,0x04,0x00,0x00,0x00,0x00,0x00}, // 0x74 t
{0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x26,0x1F,0x00,0x00,0x00,0x00,0x00}, // 0x75 u
{0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x14,0x14,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x76 v
{0x00,0x00,0x00,0x00,0x22,0x22,0x2A,0x2A,0x2A,0x14,0x14,0x00,0x00,0x00,0x00,0x00}, // 0x77 w
{0x00,0x00,0x00,0x00,0x22,0x14,0x08,0x08,0x14,0x22,0x22,0x00,0x00,0x00,0x00,0x00}, // 0x78 x
{0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x1E,0x02,0x1C,0x00,0x00,0x00,0x00,0x00,0x00}, // 0x79 y
{0x00,0x00,0x00,0x00,0x3E,0x04,0x08,0x10,0x20,0x20,0x3E,0x00,0x00,0x00,0x00,0x00}, // 0x7A z
{0x00,0x00,0x06,0x08,0x08,0x08,0x10,0x08,0x08,0x08,0x06,0x00,0x00,0x00,0x00,0x00}, // 0x7B {
{0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // 0x7C |
{0x00,0x00,0x60,0x10,0x10,0x10,0x08,0x10,0x10,0x10,0x60,0x00,0x00,0x00,0x00,0x00}, // 0x7D }
{0x00,0x00,0x00,0x12,0x2C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // 0x7E ~
};
#endif

288
Drivers/rf.c Normal file
View File

@@ -0,0 +1,288 @@
#include "rf.h"
#include "../App/config.h"
#include "intrins.h"
// ATR5179 射频开关控制脚
sbit RF_TX = P2^0; // V1 控制端 (1: 选通天线到 TX 路径)
sbit RF_RX = P3^7; // V2 控制端 (1: 选通天线到 RX 路径)
// 射频数据与控制引脚
sbit RF_TX_DAT = P3^6; // LT4455 数据输入 (DIN)
sbit RF_RX_DATA = P2^1; // LR690L 数据输出 (DATA)
sbit SHUT = P2^2; // LR690L 休眠脚 (0:工作, 1:休眠)
// External functions defined in main.c
extern void Delay_us(u16 us);
extern void Delay_ms(u16 ms);
extern u16 GetTimer0_Safe(void);
extern void Uart_SendString(char *s);
extern void Uart_SendHex4(u8 val);
extern void Uart_SendHex8(u8 val);
extern void Uart_SendHex16(u16 val);
extern void Uart_SendHex20(u32 val);
extern void Uart_SendByte(u8 dat);
void RF_Init(void)
{
// P2.0 (RF_TX) 和 P2.2 (SHUT) 配置为推挽输出P2.1 (RF_RX_DATA) 配置为双向口/输入
P2M1 &= ~((1 << 0) | (1 << 1) | (1 << 2));
P2M0 &= ~(1 << 1);
P2M0 |= ((1 << 0) | (1 << 2));
// P3.6 (RF_TX_DAT), P3.7 (RF_RX) 配置为推挽输出
P3M1 &= ~((1 << 6) | (1 << 7));
P3M0 |= ((1 << 6) | (1 << 7));
RF_TX = 0;
SHUT = 1; // 默认关闭接收芯片
RF_RX = 0;
RF_TX_DAT = 0;
}
void RF_SetMode(u8 mode)
{
if (mode == 0) // Sleep/Idle
{
SHUT = 1; // LR690L Sleep
RF_RX = 0; // 断开接收天线
RF_TX = 0; // 断开发射天线
}
else if (mode == 1) // Rx Mode
{
SHUT = 0; // LR690L 工作
RF_RX = 1; // 天线切至接收端
RF_TX = 0;
}
else if (mode == 2) // Tx Mode
{
SHUT = 1; // LR690L 睡眠
RF_RX = 0;
RF_TX = 1; // 天线切至发射端
}
}
void EV1527_TxFrame(u32 addr, u8 dat)
{
u8 i;
// 1. 同步脉冲: 1T 高电平 + 31T 低电平
RF_TX_DAT = 1;
Delay_us(320);
RF_TX_DAT = 0;
Delay_us(9920);
// 2. 20位地址码 (MSB first)
for (i = 0; i < 20; i++)
{
if ((addr >> (19 - i)) & 1)
{
// 逻辑 1: 3T 高电平 + 1T 低电平
RF_TX_DAT = 1;
Delay_us(960);
RF_TX_DAT = 0;
Delay_us(320);
}
else
{
// 逻辑 0: 1T 高电平 + 3T 低电平
RF_TX_DAT = 1;
Delay_us(320);
RF_TX_DAT = 0;
Delay_us(960);
}
}
// 3. 4位数据码 (MSB first)
for (i = 0; i < 4; i++)
{
if ((dat >> (3 - i)) & 1)
{
// 逻辑 1: 3T 高电平 + 1T 低电平
RF_TX_DAT = 1;
Delay_us(960);
RF_TX_DAT = 0;
Delay_us(320);
}
else
{
// 逻辑 0: 1T 高电平 + 3T 低电平
RF_TX_DAT = 1;
Delay_us(320);
RF_TX_DAT = 0;
Delay_us(960);
}
}
}
void EV1527_Transmit(u32 addr, u8 dat)
{
u8 r;
for (r = 0; r < 25; r++) // 增加到 25 帧(约 340ms
{
EV1527_TxFrame(addr, dat);
}
}
u16 GetPulseDuration(u8 state, u16 timeout_us)
{
u16 timeout_ticks = (u16)((u32)timeout_us * (MAIN_Fosc / 1000000UL) / 12UL);
TL0 = 0;
TH0 = 0;
TR0 = 1; // 启动定时器0
while (RF_RX_DATA == state)
{
if (GetTimer0_Safe() > timeout_ticks)
{
TR0 = 0;
return 0; // 超时
}
}
TR0 = 0;
return (u16)((u32)GetTimer0_Safe() * 12UL / (MAIN_Fosc / 1000000UL)); // 返回微秒数
}
bit EV1527_Decode(u32 *out_addr, u8 *out_data)
{
u16 high_time, low_time;
u8 i;
u32 addr = 0;
u8 dat = 0;
u16 T;
u16 idata raw_h[24];
u16 idata raw_l[24];
// 1. 同步头捕获: 必须是低电平状态之后变高电平开始
if (RF_RX_DATA == 0)
{
u16 wait_cnt = 0;
while (RF_RX_DATA == 0)
{
Delay_us(10);
wait_cnt++;
if (wait_cnt > 3000) // 30ms 超时
return 0;
}
}
// 测量同步头高电平时间 (放宽至 2500us)
high_time = GetPulseDuration(1, 2500);
if (high_time < 50 || high_time > 2500)
return 0;
// 测量同步头低电平时间 (放宽至 60000us)
low_time = GetPulseDuration(0, 60000);
if (low_time < 1500 || low_time > 60000)
return 0;
// 计算高低电平时间之比。对于标准 EV1527低电平是高电平的 31 倍。
// 放宽比例范围为 15 到 48以应对各种不同的遥控器电阻。
{
u32 ratio = (u32)low_time / high_time;
if (ratio < 15 || ratio > 48)
return 0;
}
// 估算基准脉冲周期 T = low_time / 31
T = low_time / 31;
if (T == 0) T = 1;
// 2. 连续抓取 24 个数据脉冲
for (i = 0; i < 24; i++)
{
u16 wait_cnt = 0;
// 等待下一个数据脉冲的上升沿 (如果当前是低电平,等待它变高)
while (RF_RX_DATA == 0)
{
Delay_us(5);
wait_cnt++;
if (wait_cnt > 1000) // 5ms 超时
{
return 0; // 解码失败
}
}
// 测量高电平持续时间和低电平持续时间
raw_h[i] = GetPulseDuration(1, 5000);
if (raw_h[i] == 0) return 0;
raw_l[i] = GetPulseDuration(0, 5000);
if (raw_l[i] == 0) return 0;
}
// 3. 将抓到的全部 24 位脉冲数据无条件输出到串口 (缩短输出信息以防止阻塞接收)
Uart_SendString("Captured: Sync H=");
Uart_SendHex16(high_time);
Uart_SendString("us, L=");
Uart_SendHex16(low_time);
Uart_SendString("us, T=");
Uart_SendHex16(T);
Uart_SendString("us\r\n");
// 4. 组合成 24 位地址与数据,使用自适应阈值:如果高电平时间比低电平时间长,判定为 1反之为 0
for (i = 0; i < 24; i++)
{
if (raw_h[i] > raw_l[i])
{
if (i < 20) addr = (addr << 1) | 1;
else dat = (dat << 1) | 1;
}
else
{
if (i < 20) addr = (addr << 1);
else dat = (dat << 1);
}
}
*out_addr = addr;
*out_data = dat;
// 串口打印解码结果方便现场调试
Uart_SendString("Decoded ADDR: 0x");
Uart_SendHex20(addr);
Uart_SendString(", DATA: 0x");
Uart_SendHex4(dat);
Uart_SendString("\r\n");
return 1;
}
void Loopback_Test(void)
{
u16 match_count = 0;
u16 i;
SHUT = 0; // 使能接收芯片
RF_RX = 1; // 选通天线到接收端
RF_TX = 0; // 发送侧断开
Delay_ms(100);
Uart_SendString("Starting RF Loopback Self-Test...\r\n");
for (i = 0; i < 100; i++)
{
RF_TX_DAT = 1;
Delay_us(500);
if (RF_RX_DATA == 1) match_count++;
RF_TX_DAT = 0;
Delay_us(500);
if (RF_RX_DATA == 0) match_count++;
}
Uart_SendString("Loopback Match Count: ");
Uart_SendHex16(match_count);
Uart_SendString("/200\r\n");
if (match_count > 150)
{
Uart_SendString("Result: PASS! Transmitter is emitting RF, and Receiver is picking it up!\r\n");
}
else
{
Uart_SendString("Result: FAIL! No RF signal detected. Check hardware.\r\n");
}
SHUT = 1;
RF_RX = 0;
}

16
Drivers/rf.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __RF_H__
#define __RF_H__
#include "../App/config.h"
#include "stc32g.h"
// Public RF functions
void RF_Init(void);
void RF_SetMode(u8 mode); // mode: 0=Sleep, 1=Rx, 2=Tx
void EV1527_TxFrame(u32 addr, u8 dat);
void EV1527_Transmit(u32 addr, u8 dat);
u16 GetPulseDuration(u8 state, u16 timeout_us);
bit EV1527_Decode(u32 *out_addr, u8 *out_data);
void Loopback_Test(void);
#endif

1487
Drivers/stc32g.h Normal file

File diff suppressed because it is too large Load Diff

47181
Hardware/text.kicad_pcb Normal file

File diff suppressed because it is too large Load Diff

138
Hardware/text.kicad_prl Normal file
View File

@@ -0,0 +1,138 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_netclasses": [],
"hidden_nets": [
"GND"
],
"high_contrast_mode": 1,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"shapes": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"prototype_zone_fills": false,
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": false,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
"vias",
"footprint_text",
"footprint_anchors",
"ratsnest",
"grid",
"footprints_front",
"footprints_back",
"tracks",
"drc_errors",
"drawing_sheet",
"bitmaps",
"pads",
"zones",
"drc_warnings",
"drc_exclusions",
"locked_item_shadows",
"conflict_shadows",
"shapes",
"board_outline_area",
"ly_points"
],
"visible_layers": "ffffffff_ffffffff_ffffffff_ffffffff",
"zone_display_mode": 0
},
"git": {
"integration_disabled": false,
"repo_type": "",
"repo_username": "",
"ssh_key": ""
},
"meta": {
"filename": "text.kicad_prl",
"version": 5
},
"net_inspector_panel": {
"col_hidden": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false
],
"col_order": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
],
"col_widths": [
174,
159,
100,
63,
100,
100,
100,
63,
100,
100
],
"custom_group_rules": [],
"expanded_rows": [],
"filter_by_net_name": true,
"filter_by_netclass": true,
"filter_text": "",
"group_by_constraint": false,
"group_by_netclass": false,
"show_time_domain_details": false,
"show_unconnected_nets": false,
"show_zero_pad_nets": false,
"sort_ascending": true,
"sorting_column": 0
},
"open_jobsets": [],
"project": {
"files": []
},
"schematic": {
"hierarchy_collapsed": [],
"selection_filter": {
"graphics": true,
"images": true,
"labels": true,
"lockedItems": false,
"otherItems": true,
"pins": false,
"ruleAreas": true,
"symbols": true,
"text": true,
"wires": true
}
}
}

691
Hardware/text.kicad_pro Normal file
View File

@@ -0,0 +1,691 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_barcodes": false,
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.05,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": true,
"text_position": 0,
"units_format": 0
},
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.1,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.0,
"height": 0.310008,
"width": 0.529997
},
"silk_line_width": 0.1,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
"border_display_style": 2,
"border_hatch_pitch": 0.5,
"corner_radius": 0.0,
"corner_smoothing": 0,
"fill_mode": 0,
"hatch_gap": 1.5,
"hatch_orientation": 0.0,
"hatch_smoothing_level": 0,
"hatch_smoothing_value": 0.1,
"hatch_thickness": 1.0,
"min_clearance": 0.5,
"min_island_area": 10.0,
"min_thickness": 0.25,
"pad_connection": 1,
"remove_islands": 0,
"thermal_relief_gap": 0.5,
"thermal_relief_spoke_width": 0.5
}
},
"diff_pair_dimensions": [
{
"gap": 0.0,
"via_gap": 0.0,
"width": 0.0
}
],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"creepage": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_filters_mismatch": "ignore",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_to_hole": "warning",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "error",
"padstack": "warning",
"pth_inside_courtyard": "error",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_on_edge_cuts": "error",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_angle": "error",
"track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error",
"track_width": "error",
"tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.5,
"min_groove_width": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 1,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.1,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpthpad": true,
"td_onroundshapesonly": false,
"td_onsmdpad": true,
"td_ontrackend": false,
"td_onvia": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [
0.0
],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [
{
"diameter": 0.0,
"drill": 0.0
}
],
"zones_allow_external_fillets": true
},
"ipc2581": {
"bom_rev": "",
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": "",
"sch_revision": ""
},
"layer_pairs": [
{
"bottomLayer": 2,
"enabled": true,
"topLayer": 0
}
],
"layer_presets": [],
"viewports": []
},
"boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [
[
"power_pin_not_driven|3200400|1346200|270b45f3-22a3-458a-a43c-db627535af63|00000000-0000-0000-0000-000000000000|/72df0bee-e55e-4d81-989a-168573031a0a|/72df0bee-e55e-4d81-989a-168573031a0a|",
""
]
],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"field_name_whitespace": "warning",
"footprint_filter": "ignore",
"footprint_link_issues": "warning",
"four_way_junction": "ignore",
"ground_pin_not_ground": "warning",
"hier_label_mismatch": "error",
"isolated_pin_label": "warning",
"label_dangling": "error",
"label_multiple_wires": "warning",
"lib_symbol_issues": "warning",
"lib_symbol_mismatch": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"same_local_global_label": "warning",
"similar_label_and_power": "warning",
"similar_labels": "warning",
"similar_power": "warning",
"simulation_model_issue": "ignore",
"single_global_label": "ignore",
"stacked_pin_name": "warning",
"unannotated": "error",
"unconnected_wire_endpoint": "warning",
"undefined_netclass": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "text.kicad_pro",
"version": 3
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.15,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.6,
"via_drill": 0.3,
"wire_width": 6
}
],
"meta": {
"version": 5
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"idf": "",
"netlist": "",
"plot": "",
"specctra_dsn": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"annotation": {
"method": 0,
"sort_order": 0
},
"bom_export_filename": "${PROJECTNAME}.csv",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
},
{
"group_by": true,
"label": "Exclude from BOM",
"name": "${EXCLUDE_FROM_BOM}",
"show": true
},
{
"group_by": true,
"label": "Exclude from Board",
"name": "${EXCLUDE_FROM_BOARD}",
"show": true
},
{
"group_by": true,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"include_excluded_from_bom": true,
"name": "Default Editing",
"sort_asc": true,
"sort_field": "位号"
},
"bus_aliases": {},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"hop_over_size_choice": 0,
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"page_layout_descr_file": "",
"plot_directory": "",
"reuse_designators": true,
"subpart_first_id": 65,
"subpart_id_separator": 0,
"top_level_sheets": [
{
"filename": "text.kicad_sch",
"name": "text",
"uuid": "72df0bee-e55e-4d81-989a-168573031a0a"
}
],
"used_designators": "#PWR28,#PWR57-58",
"variants": []
},
"sheets": [
[
"72df0bee-e55e-4d81-989a-168573031a0a",
"text"
]
],
"text_variables": {},
"tuning_profiles": {
"meta": {
"version": 0
},
"tuning_profiles_impedance_geometric": []
}
}

25670
Hardware/text.kicad_sch Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<rect x="4" y="4" width="112" height="232" rx="20" stroke="#EF4444" stroke-width="2.5" fill="none" stroke-dasharray="6 4"/>
<g transform="translate(0, 10)">
<rect x="52" y="55" width="16" height="30" rx="1" fill="none" stroke="#EF4444" stroke-width="2.5"/>
<circle cx="64" cy="70" r="1.5" fill="#EF4444"/>
</g>
<text x="60" y="130" fill="#EF4444" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">FRONT DOOR</text>
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">ZONE 0 | ALARM</text>
</svg>

After

Width:  |  Height:  |  Size: 748 B

View File

@@ -0,0 +1,23 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Status Bar (Right: Battery Icon) -->
<rect x="82" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
<rect x="84" y="29" width="13" height="6" rx="1" fill="#10B981"/>
<rect x="103" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
<text x="76" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
<!-- Time -->
<text x="60" y="115" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" text-anchor="middle">10:35</text>
<!-- Date -->
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">THU 07-02</text>
<!-- Armed Status at the very bottom (Y=205) -->
<g transform="translate(36, 192)">
<rect x="0" y="0" width="12" height="12" rx="2" fill="none" stroke="#EF4444" stroke-width="1.2"/>
<circle cx="6" cy="4" r="2.5" fill="none" stroke="#EF4444" stroke-width="1.2"/>
<rect x="5" y="6" width="2" height="3" fill="#EF4444"/>
</g>
<text x="60" y="202" fill="#EF4444" font-family="system-ui, sans-serif" font-size="9" font-weight="bold" text-anchor="middle"> ARMED</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Status Bar (Right: Battery Icon) -->
<rect x="82" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
<rect x="84" y="29" width="13" height="6" rx="1" fill="#10B981"/>
<rect x="103" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
<text x="76" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
<!-- Time -->
<text x="60" y="115" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" text-anchor="middle">10:35</text>
<!-- Date -->
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">THU 07-02</text>
</svg>

After

Width:  |  Height:  |  Size: 854 B

View File

@@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Status Bar (Right: Battery Icon) -->
<rect x="82" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
<rect x="84" y="29" width="13" height="6" rx="1" fill="#10B981"/>
<rect x="103" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
<text x="76" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
<!-- Time -->
<text x="60" y="115" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" text-anchor="middle">10:35</text>
<!-- Date -->
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">THU 07-02</text>
<!-- Disarmed Status at the very bottom (Y=205) -->
<g transform="translate(32, 192)">
<rect x="0" y="3" width="12" height="9" rx="1.5" fill="none" stroke="#10B981" stroke-width="1.2"/>
<path d="M 3 3 L 3 1.5 C 3 0.7, 6 0.7, 8 1.5 L 8 4" fill="none" stroke="#10B981" stroke-width="1.2"/>
</g>
<text x="60" y="202" fill="#10B981" font-family="system-ui, sans-serif" font-size="9" font-weight="bold" text-anchor="middle"> DISARM</text>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<circle cx="60" cy="120" r="58" stroke="#334155" stroke-width="1" fill="none"/>
<g transform="translate(0, 10)">
<circle cx="60" cy="80" r="28" stroke="#FFB74D" stroke-width="1.2" stroke-dasharray="3 3" fill="none"/>
<rect x="46" y="74" width="28" height="20" rx="3" fill="none" stroke="#FFB74D" stroke-width="2.5"/>
<circle cx="60" cy="81" r="2.5" fill="#FFB74D"/>
<path d="M 60 83.5 L 60 88" stroke="#FFB74D" stroke-width="2" stroke-linecap="round"/>
<path d="M 52 74 L 52 64 A 8 8 0 0 1 68 64 L 68 70" fill="none" stroke="#FFB74D" stroke-width="2.5" stroke-linecap="round"/>
</g>
<text x="60" y="145" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">CODE FOUND</text>
<text x="60" y="170" fill="#FFB74D" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">HOLD SOS TO SAVE</text>
<text x="60" y="192" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">ADDR: 0x37A86</text>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Symmetrical Circular Fail Badge -->
<circle cx="60" cy="90" r="24" stroke="#EF4444" stroke-width="2.5" fill="none"/>
<path d="M 50 80 L 70 100 M 70 80 L 50 100" stroke="#EF4444" stroke-width="3.5" fill="none" stroke-linecap="round"/>
<text x="60" y="155" fill="#EF4444" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">PAIR FAILED</text>
<text x="60" y="180" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">TYPE MISMATCH</text>
</svg>

After

Width:  |  Height:  |  Size: 673 B

View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<g transform="translate(0, 10)">
<path d="M 60 70 L 60 90 M 52 75 A 10 10 0 0 1 68 75 M 48 70 A 15 15 0 0 1 72 70 M 44 65 A 20 20 0 0 1 76 65" stroke="#00E5FF" stroke-width="2" fill="none" stroke-linecap="round"/>
<circle cx="60" cy="92" r="2" fill="#00E5FF"/>
</g>
<text x="60" y="145" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">SEARCHING...</text>
<text x="60" y="170" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">TRIGGER SENSOR</text>
</svg>

After

Width:  |  Height:  |  Size: 702 B

View File

@@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<text x="60" y="35" fill="#FFB74D" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">PAIR MENU P-00</text>
<text x="60" y="80" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">🚪 DOOR SENSOR</text>
<rect x="10" y="105" width="100" height="30" rx="6" fill="none" stroke="#00E5FF" stroke-width="1.5"/>
<text x="60" y="124" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">👤 PIR MOTION</text>
<text x="60" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">🔥 SMOKE DETECT</text>
</svg>

After

Width:  |  Height:  |  Size: 818 B

View File

@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<!-- Symmetrical Circular Success Badge -->
<circle cx="60" cy="90" r="24" stroke="#10B981" stroke-width="2.5" fill="none"/>
<path d="M 48 90 L 56 98 L 72 82" stroke="#10B981" stroke-width="3.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<text x="60" y="145" fill="#10B981" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">PAIR SUCCESS</text>
<text x="60" y="175" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">ADDR: 0x37A86</text>
</svg>

After

Width:  |  Height:  |  Size: 692 B

View File

@@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="240" viewBox="0 0 120 240">
<rect width="120" height="240" fill="#000000"/>
<rect x="4" y="4" width="112" height="232" rx="20" stroke="#EF4444" stroke-width="2.5" fill="none"/>
<rect x="8" y="8" width="104" height="224" rx="17" stroke="#FFFFFF" stroke-width="1" fill="none"/>
<!-- High-Fidelity Siren Icon -->
<g transform="translate(0, -3)">
<!-- Light Beams -->
<path d="M 60 48 L 60 54 M 45 52 L 50 57 M 75 52 L 70 57 M 40 65 L 46 67 M 80 65 L 74 67" stroke="#EF4444" stroke-width="2" stroke-linecap="round"/>
<!-- Siren Glass Dome -->
<path d="M 46 82 C 46 64, 74 64, 74 82 Z" fill="#EF4444" stroke="#EF4444" stroke-width="1.5"/>
<!-- Bulb inside -->
<circle cx="60" cy="77" r="4.5" fill="#FFFFFF"/>
<!-- Metallic Base -->
<rect x="42" y="82" width="36" height="6" rx="1.5" fill="#64748B"/>
</g>
<!-- Centered SOS Alarm Texts safely inside circular active area -->
<text x="60" y="138" fill="#EF4444" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">🆘 EMIT SOS</text>
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">BAND TRIGGERED</text>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

204
wristband.uvopt Normal file
View File

@@ -0,0 +1,204 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<ProjectOpt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_opt.xsd">
<SchemaVersion>1.0</SchemaVersion>
<Header>### uVision Project, (C) Keil Software</Header>
<Extensions>
<cExt>*.c</cExt>
<aExt>*.s*; *.src; *.a*</aExt>
<oExt>*.obj; *.o</oExt>
<lExt>*.lib</lExt>
<tExt>*.txt; *.h; *.inc; *.md</tExt>
<pExt>*.plm</pExt>
<CppX>*.cpp</CppX>
<nMigrate>0</nMigrate>
</Extensions>
<DaveTm>
<dwLowDateTime>0</dwLowDateTime>
<dwHighDateTime>0</dwHighDateTime>
</DaveTm>
<Target>
<TargetName>Wristband</TargetName>
<ToolsetNumber>0x1</ToolsetNumber>
<ToolsetName>MCS-251</ToolsetName>
<TargetOption>
<CLK251>35000000</CLK251>
<OPTTT>
<gFlags>1</gFlags>
<BeepAtEnd>1</BeepAtEnd>
<RunSim>1</RunSim>
<RunTarget>0</RunTarget>
<RunAbUc>0</RunAbUc>
</OPTTT>
<OPTHX>
<HexSelection>1</HexSelection>
<FlashByte>65535</FlashByte>
<HexRangeLowAddress>0</HexRangeLowAddress>
<HexRangeHighAddress>0</HexRangeHighAddress>
<HexOffset>0</HexOffset>
</OPTHX>
<OPTLEX>
<PageWidth>120</PageWidth>
<PageLength>65</PageLength>
<TabStop>8</TabStop>
<ListingPath>.\Build\</ListingPath>
</OPTLEX>
<ListingPage>
<CreateCListing>1</CreateCListing>
<CreateAListing>1</CreateAListing>
<CreateLListing>1</CreateLListing>
<CreateIListing>0</CreateIListing>
<AsmCond>1</AsmCond>
<AsmSymb>1</AsmSymb>
<AsmXref>0</AsmXref>
<CCond>1</CCond>
<CCode>0</CCode>
<CListInc>0</CListInc>
<CSymb>0</CSymb>
<LinkerCodeListing>0</LinkerCodeListing>
</ListingPage>
<OPTXL>
<LMap>1</LMap>
<LComments>1</LComments>
<LGenerateSymbols>1</LGenerateSymbols>
<LLibSym>1</LLibSym>
<LLines>1</LLines>
<LLocSym>1</LLocSym>
<LPubSym>1</LPubSym>
<LXref>0</LXref>
<LExpSel>0</LExpSel>
</OPTXL>
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>1</IsCurrentTarget>
</OPTFL>
<CpuCode>255</CpuCode>
<DebugOpt>
<uSim>1</uSim>
<uTrg>0</uTrg>
<sLdApp>1</sLdApp>
<sGomain>1</sGomain>
<sRbreak>1</sRbreak>
<sRwatch>1</sRwatch>
<sRmem>1</sRmem>
<sRfunc>1</sRfunc>
<sRbox>1</sRbox>
<tLdApp>1</tLdApp>
<tGomain>0</tGomain>
<tRbreak>1</tRbreak>
<tRwatch>1</tRwatch>
<tRmem>1</tRmem>
<tRfunc>0</tRfunc>
<tRbox>1</tRbox>
<tRtrace>1</tRtrace>
<sRSysVw>1</sRSysVw>
<tRSysVw>1</tRSysVw>
<sRunDeb>0</sRunDeb>
<sLrtime>0</sLrtime>
<bEvRecOn>1</bEvRecOn>
<bSchkAxf>0</bSchkAxf>
<bTchkAxf>0</bTchkAxf>
<nTsel>-1</nTsel>
<sDll />
<sDllPa />
<sDlgDll />
<sDlgPa />
<sIfile />
<tDll />
<tDllPa />
<tDlgDll />
<tDlgPa />
<tIfile />
<pMon />
</DebugOpt>
<TargetDriverDllRegistry>
<SetRegEntry>
<Number>0</Number>
<Key>DLGDC51</Key>
<Name>(94=-1,-1,-1,-1,0)(120=-1,-1,-1,-1,0)(119=-1,-1,-1,-1,0)(107=-1,-1,-1,-1,0)(103=-1,-1,-1,-1,0)(108=-1,-1,-1,-1,0)(114=-1,-1,-1,-1,0)(115=-1,-1,-1,-1,0)</Name>
</SetRegEntry>
</TargetDriverDllRegistry>
<Breakpoint />
<Tracepoint>
<THDelay>0</THDelay>
</Tracepoint>
<DebugFlag>
<trace>0</trace>
<periodic>0</periodic>
<aLwin>1</aLwin>
<aCover>0</aCover>
<aSer1>0</aSer1>
<aSer2>0</aSer2>
<aPa>0</aPa>
<viewmode>1</viewmode>
<vrSel>0</vrSel>
<aSym>0</aSym>
<aTbox>0</aTbox>
<AscS1>0</AscS1>
<AscS2>0</AscS2>
<AscS3>0</AscS3>
<aSer3>0</aSer3>
<eProf>0</eProf>
<aLa>0</aLa>
<aPa1>0</aPa1>
<AscS4>0</AscS4>
<aSer4>0</aSer4>
<StkLoc>0</StkLoc>
<TrcWin>0</TrcWin>
<newCpu>0</newCpu>
<uProt>0</uProt>
</DebugFlag>
<LintExecutable />
<LintConfigFile />
<bLintAuto>0</bLintAuto>
<bAutoGenD>0</bAutoGenD>
<LntExFlags>0</LntExFlags>
<pMisraName />
<pszMrule />
<pSingCmds />
<pMultCmds />
<pMisraNamep />
<pszMrulep />
<pSingCmdsp />
<pMultCmdsp />
</TargetOption>
</Target>
<Group>
<GroupName>Source</GroupName>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<cbSel>0</cbSel>
<RteFlg>0</RteFlg>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>1</FileNumber>
<FileType>1</FileType>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>.\main.c</PathWithFileName>
<FilenameWithoutPath>main.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>1</GroupNumber>
<FileNumber>2</FileNumber>
<FileType>5</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>.\功能说明.txt</PathWithFileName>
<FilenameWithoutPath>功能说明.txt</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group>
</ProjectOpt>

326
wristband.uvproj Normal file
View File

@@ -0,0 +1,326 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_proj.xsd">
<SchemaVersion>1.1</SchemaVersion>
<Header>### uVision Project, (C) Keil Software</Header>
<Targets>
<Target>
<TargetName>Wristband</TargetName>
<ToolsetNumber>0x1</ToolsetNumber>
<ToolsetName>MCS-251</ToolsetName>
<uAC6>0</uAC6>
<TargetOption>
<TargetCommonOption>
<Device>STC32G12K128 Series</Device>
<Vendor>STC</Vendor>
<Cpu>IRAM(0-0xFFF) XRAM(0x10000-0x11FFF) IROM(0xFE0000-0xFFFFFF) CLOCK(35000000)</Cpu>
<FlashUtilSpec />
<StartupFile>"LIB\STARTUP251.ASM" ("80251 Startup Code")</StartupFile>
<FlashDriverDll />
<DeviceId>63457</DeviceId>
<RegisterFile>STC16F.H</RegisterFile>
<MemoryEnv />
<Cmp />
<Asm />
<Linker />
<OHString />
<InfinionOptionDll />
<SLE66CMisc />
<SLE66AMisc />
<SLE66LinkerMisc />
<SFDFile />
<bCustSvd>0</bCustSvd>
<UseEnv>0</UseEnv>
<BinPath />
<IncludePath />
<LibPath />
<RegisterFilePath>STC\</RegisterFilePath>
<DBRegisterFilePath>STC\</DBRegisterFilePath>
<TargetStatus>
<Error>0</Error>
<ExitCodeStop>0</ExitCodeStop>
<ButtonStop>0</ButtonStop>
<NotGenerated>0</NotGenerated>
<InvalidFlash>1</InvalidFlash>
</TargetStatus>
<OutputDirectory>.\Build\</OutputDirectory>
<OutputName>wristband</OutputName>
<CreateExecutable>1</CreateExecutable>
<CreateLib>0</CreateLib>
<CreateHexFile>1</CreateHexFile>
<DebugInformation>1</DebugInformation>
<BrowseInformation>1</BrowseInformation>
<ListingPath>.\Build\</ListingPath>
<HexFormatSelection>1</HexFormatSelection>
<Merge32K>0</Merge32K>
<CreateBatchFile>0</CreateBatchFile>
<BeforeCompile>
<RunUserProg1>0</RunUserProg1>
<RunUserProg2>0</RunUserProg2>
<UserProg1Name />
<UserProg2Name />
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
<nStopU1X>0</nStopU1X>
<nStopU2X>0</nStopU2X>
</BeforeCompile>
<BeforeMake>
<RunUserProg1>0</RunUserProg1>
<RunUserProg2>0</RunUserProg2>
<UserProg1Name />
<UserProg2Name />
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
<nStopB1X>0</nStopB1X>
<nStopB2X>0</nStopB2X>
</BeforeMake>
<AfterMake>
<RunUserProg1>0</RunUserProg1>
<RunUserProg2>0</RunUserProg2>
<UserProg1Name />
<UserProg2Name />
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
<nStopA1X>0</nStopA1X>
<nStopA2X>0</nStopA2X>
</AfterMake>
<SelectedForBatchBuild>0</SelectedForBatchBuild>
<SVCSIdString />
</TargetCommonOption>
<CommonProperty>
<UseCPPCompiler>0</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>1</IncludeInBuild>
<AlwaysBuild>0</AlwaysBuild>
<GenerateAssemblyFile>0</GenerateAssemblyFile>
<AssembleAssemblyFile>0</AssembleAssemblyFile>
<PublicsOnly>0</PublicsOnly>
<StopOnExitCode>3</StopOnExitCode>
<CustomArgument />
<IncludeLibraryModules />
<ComprImg>1</ComprImg>
<BankNo>65535</BankNo>
</CommonProperty>
<DllOption>
<SimDllName>S251.DLL</SimDllName>
<SimDllArguments />
<SimDlgDll>DCORE51.DLL</SimDlgDll>
<SimDlgDllArguments>-p251</SimDlgDllArguments>
<TargetDllName>S251.DLL</TargetDllName>
<TargetDllArguments />
<TargetDlgDll>TCORE51.DLL</TargetDlgDll>
<TargetDlgDllArguments>-p251</TargetDlgDllArguments>
</DllOption>
<DebugOption>
<OPTHX>
<HexSelection>1</HexSelection>
<HexRangeLowAddress>0</HexRangeLowAddress>
<HexRangeHighAddress>0</HexRangeHighAddress>
<HexOffset>0</HexOffset>
<Oh166RecLen>16</Oh166RecLen>
</OPTHX>
<Simulator>
<UseSimulator>1</UseSimulator>
<LoadApplicationAtStartup>1</LoadApplicationAtStartup>
<RunToMain>1</RunToMain>
<RestoreBreakpoints>1</RestoreBreakpoints>
<RestoreWatchpoints>1</RestoreWatchpoints>
<RestoreMemoryDisplay>1</RestoreMemoryDisplay>
<RestoreFunctions>1</RestoreFunctions>
<RestoreToolbox>1</RestoreToolbox>
<LimitSpeedToRealTime>0</LimitSpeedToRealTime>
<RestoreSysVw>1</RestoreSysVw>
</Simulator>
<Target>
<UseTarget>0</UseTarget>
<LoadApplicationAtStartup>1</LoadApplicationAtStartup>
<RunToMain>0</RunToMain>
<RestoreBreakpoints>1</RestoreBreakpoints>
<RestoreWatchpoints>1</RestoreWatchpoints>
<RestoreMemoryDisplay>1</RestoreMemoryDisplay>
<RestoreFunctions>0</RestoreFunctions>
<RestoreToolbox>1</RestoreToolbox>
<RestoreTracepoints>1</RestoreTracepoints>
<RestoreSysVw>1</RestoreSysVw>
</Target>
<RunDebugAfterBuild>0</RunDebugAfterBuild>
<TargetSelection>-1</TargetSelection>
<SimDlls>
<CpuDll />
<CpuDllArguments />
<PeripheralDll />
<PeripheralDllArguments />
<InitializationFile />
</SimDlls>
<TargetDlls>
<CpuDll />
<CpuDllArguments />
<PeripheralDll />
<PeripheralDllArguments />
<InitializationFile />
<Driver />
</TargetDlls>
</DebugOption>
<Utilities>
<Flash1>
<UseTargetDll>1</UseTargetDll>
<UseExternalTool>0</UseExternalTool>
<RunIndependent>0</RunIndependent>
<UpdateFlashBeforeDebugging>0</UpdateFlashBeforeDebugging>
<Capability>0</Capability>
<DriverSelection>-1</DriverSelection>
</Flash1>
<bUseTDR>0</bUseTDR>
<Flash2 />
<Flash3 />
<Flash4 />
<pFcarmOut />
<pFcarmGrp />
<pFcArmRoot />
<FcArmLst>0</FcArmLst>
</Utilities>
<Target251>
<Target251Misc>
<MemoryModel>3</MemoryModel>
<RTOS>0</RTOS>
<RomSize>3</RomSize>
<NearDataHold>0</NearDataHold>
<XDataHold>0</XDataHold>
<FarDataHold>0</FarDataHold>
<uocRom>0</uocRom>
<uocXRAM>0</uocXRAM>
<uSrcBin>1</uSrcBin>
<uFrame4>0</uFrame4>
<hadIRAM>1</hadIRAM>
<hadXRAM>1</hadXRAM>
<hadIROM>1</hadIROM>
<Use_Code_Banking>0</Use_Code_Banking>
<uCC7>0</uCC7>
<fp_hp>0</fp_hp>
<CBANKS2>0</CBANKS2>
<OnChipMemories>
<RCB>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x10000</Size>
</RCB>
<IROM>
<Type>1</Type>
<StartAddress>0xfe0000</StartAddress>
<Size>0x20000</Size>
</IROM>
<IRAM>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x1000</Size>
</IRAM>
<XRAM>
<Type>0</Type>
<StartAddress>0x10000</StartAddress>
<Size>0x2000</Size>
</XRAM>
<Ocm1>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm1>
<Ocm2>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm2>
<Ocm3>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm3>
<Ocm4>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm4>
<Ocm5>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm5>
<Ocm6>
<Type>0</Type>
<StartAddress>0x0</StartAddress>
<Size>0x0</Size>
</Ocm6>
</OnChipMemories>
</Target251Misc>
<C251>
<RegColor>0</RegColor>
<uOrder>0</uOrder>
<uAlias>1</uAlias>
<uRentF>0</uRentF>
<uUch>0</uUch>
<uFlt64>0</uFlt64>
<Fuzzy>3</Fuzzy>
<Optim>7</Optim>
<wLevel>2</wLevel>
<SizSpd>1</SizSpd>
<AcaOpt>0</AcaOpt>
<VariousControls>
<MiscControls />
<Define />
<Undefine />
<IncludePath />
</VariousControls>
</C251>
<Ax51>
<UseMpl>0</UseMpl>
<UseStandard>1</UseStandard>
<UseCase>0</UseCase>
<UseMod51>0</UseMod51>
<VariousControls>
<MiscControls />
<Define />
<Undefine />
<IncludePath />
</VariousControls>
</Ax51>
<Lx51>
<useFile>0</useFile>
<linkonly>0</linkonly>
<UseMemoryFromTarget>1</UseMemoryFromTarget>
<CaseSensitiveSymbols>1</CaseSensitiveSymbols>
<WarningLevel>2</WarningLevel>
<DataOverlaying>1</DataOverlaying>
<OverlayString />
<MiscControls />
<DisableWarningNumbers />
<LinkerCmdFile />
<Assign />
<ReserveString />
<CClasses />
<UserClasses />
<CSection />
<UserSection />
<CodeBaseAddress />
<XDataBaseAddress />
<PDataBaseAddress />
<BitBaseAddress />
<DataBaseAddress />
<IDataBaseAddress />
<Precede />
<Stack />
<CodeSegmentName />
<XDataSegmentName />
<BitSegmentName />
<DataSegmentName />
<IDataSegmentName />
</Lx51>
</Target251>
</TargetOption>
<Groups><Group><GroupName>App</GroupName><Files><File><FileName>main.c</FileName><FileType>1</FileType><FilePath>.\App\main.c</FilePath></File></Files></Group><Group><GroupName>Drivers</GroupName><Files><File><FileName>lcd.c</FileName><FileType>1</FileType><FilePath>.\Drivers\lcd.c</FilePath></File><File><FileName>rf.c</FileName><FileType>1</FileType><FilePath>.\Drivers\rf.c</FilePath></File></Files></Group></Groups></Target>
</Targets>
</Project>