Compare commits
12 Commits
1168e747e6
...
ee69d25efe
| Author | SHA1 | Date | |
|---|---|---|---|
| ee69d25efe | |||
| 039029ab20 | |||
| 9f54220e27 | |||
| 2068edd205 | |||
| 471b61107e | |||
| 96a23da617 | |||
| afaf0bf360 | |||
| b15fca3629 | |||
| fb781f4f2a | |||
| 56fbe68dba | |||
| 16deeb6662 | |||
| 32c07c0466 |
@@ -1,11 +1,11 @@
|
||||
# 总体需求 (Docs/10_requirements-overview/main.md)
|
||||
|
||||
## 1. 项目整体框架与系统拓扑
|
||||
本项目主要实现随身手环终端的底层驱动、核心业务管理以及低功耗待机逻辑。
|
||||
|
||||
本项目**仅包含手环端核心业务及驱动代码的实现**。
|
||||
* **被动接收**:手环作为随身告警终端,独立接收来自 **7类 433MHz 传感器**的探测射频信号(本地安防联动系统)。
|
||||
* **主动发射**:手环在本地触发 SOS 求救时,必须向外主动发射 **433MHz SOS 呼救射频信号**,使周边的 IPC 摄像头接收并联动。
|
||||
* 周围的其他组件(如 IPC 摄像头和手机 APP)不在本项目编码范围内,仅作外部仿真与对接边界。
|
||||
## 1. 项目系统拓扑与边界
|
||||
|
||||
* **业务流向**:手环作为智能家居安防的便携式告警与求救终端,与无线传感器以及 IPC 摄像头(网络摄像机)构成以下星型网络架构。
|
||||
* **设计边界**:本项目**仅开发手环端的软件代码**,传感器和 IPC 摄像头侧的软件仅作为对接调试的外界仿真源。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
@@ -13,18 +13,34 @@ graph TD
|
||||
Wristband -->|433MHz SOS 呼救信号| IPC[IPC 摄像头 (仿真对接)]
|
||||
```
|
||||
|
||||
## 2. 核心信号流向与手环行为要求
|
||||
---
|
||||
|
||||
1. **传感器触发**:探测到异常时,发射固定编码信号(24位 EV1527 协议数据,包含 20位地址码 + 4位数据码)。
|
||||
2. **手环独立接收**:手环配备 LR690L 433MHz 接收解调芯片,独立进行软件自适应时序解码。
|
||||
3. **手环响应行为**:
|
||||
* **屏幕显示**:1.14寸(135x240 像素,**竖直排版**,型号为 **SPEC LHS114TC-IF03 VER A**)TFT LCD 屏幕,**保持常亮显示时间**。报警时呈现对应的报警 ICON + 传感器法语名称。
|
||||
* **灯效响应**:可编程 RGB 灯珠根据传感器类型亮起对应颜色并进行特定波形闪烁。
|
||||
* **马达响应**:马达触发特定的振动次数与时长组合。
|
||||
4. **手环主动发射与辨识**:
|
||||
* **主动求救**:用户短按手环上部的 SOS 键,手环进入 SOS 状态,并使用**出厂固定唯一 ID (Factory ID)** 作为源地址发射 433MHz 的 SOS 编码电报。
|
||||
* **身份辨识**:该出厂 ID 作为手环的唯一物理地址标识,以便 IPC 摄像头可以通过与该 ID 配对,唯一识别该手环并将其与具体的用户绑定。
|
||||
## 2. 总体功能需求
|
||||
|
||||
## 3. 协作规范与门禁说明
|
||||
本项目的开发协作基于《开发规范.md》定义的“七个环节”。任何目录下文件的修改应当保证其依赖项是同步的。
|
||||
在每次完成阶段性工作或代码调整后,应运行 `python .xagent/check-dirty.py` 进行脏检测自检。
|
||||
手环系统应具备以下六大核心总体功能:
|
||||
|
||||
### 2.1 显示时间日期与状态栏
|
||||
* 手环应支持软时钟走时,在主页面清晰直观地显示当前的小时、分钟、星期及日期信息。
|
||||
* 主页面状态栏应实时指示当前电池电量、USB 充电状态,以及当前的系统安防运行状态(布防/撤防)。
|
||||
|
||||
### 2.2 系统安防布防与撤防控制
|
||||
* 系统支持两种安防警戒模式:
|
||||
* **布防状态**:对所有类型已配对的传感器报警信号(如门磁、红外等)均执行本地声光振动告警。
|
||||
* **撤防状态**:对普通盗防类传感器信号予以忽略,仅对危及安全和紧急求救的传感器信号进行报警响应。
|
||||
|
||||
### 2.3 传感器无线对码配对
|
||||
* 手环能捕获周围 433MHz 传感器发出的 EV1527 对码射频包,将其地址码与类型绑定记录在非易失存储区(掉电不丢失)。
|
||||
* 手环支持多达 16 个传感器防区槽位的配对与法语前缀加数字序号的命名保存。
|
||||
|
||||
### 2.4 主动呼救与 IPC 绑定配对
|
||||
* **主动求救**:当遇到紧急情况时,用户可一键快速触发主动 SOS 求救广播,向外以 2 秒为周期循环发射带有手环出厂固定唯一 ID 的 433MHz 载波信号。
|
||||
* **IPC 绑定**:手环提供主动向 IPC发射对码信号的功能,以便 IPC 摄像头将该手环地址绑定至特定用户,识别求救来源。
|
||||
|
||||
### 2.5 多维告警响应反馈
|
||||
* 手环根据捕获到报警传感器的类型,执行差异化的硬件声光、马达振动和屏幕图标文字反馈,提供直观的物理告警。
|
||||
|
||||
### 2.6 低功耗待机与中断秒级唤醒
|
||||
* 手环必须具备优秀的低功耗休眠机制,在连续无按键操作 10 秒后,自动关闭屏幕并切断屏幕供电电路,使单片机进入深度休眠(Power-Down 挂起状态)。
|
||||
* 手环在休眠状态下,支持任何物理按键按下瞬间被唤醒,以及接收到 433MHz 无线射频载波信号瞬间被唤醒,唤醒后应在极短时间内恢复系统运行与屏幕显示。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -2,28 +2,45 @@
|
||||
|
||||
本章节定义手环终端的物理按键交互、报警矩阵(可编程 RGB 灯颜色与振动)以及防区划分详细需求。
|
||||
|
||||
## 1. 物理按键与交互定义
|
||||
## 1. 物理按键与菜单交互定义
|
||||
|
||||
手环共配备 **5 个物理按键**:侧边 3 个(▲ 上移、▼ 下移、■ 确认),上部 2 个(相同的 SOS1、SOS2,具备完全一致的并联电气逻辑)。
|
||||
手环共配备 **5 个物理按键**:侧边 3 个(▲ 上移、▼ 下移、■ 确认/CONFIRM),上部 2 个(相同的 SOS1、SOS2,具备完全一致的并联电气逻辑)。
|
||||
|
||||
| 按键类别 | 按键动作 | 常态 (时钟待机) | 对码配对模式 | 警报触发状态 |
|
||||
### 1.1 页面与状态定义
|
||||
* **时钟待机状态 (STATE_CLOCK)**:正常显示时间、日期、电量及布撤防状态(大字版)。
|
||||
* **低功耗休眠状态 (STATE_SLEEP)**:无按键操作 10 秒后自动进入。屏幕完全关闭,拉低 `SGM_CTRL = 0` 关闭 SGM3833 供电,单片机进入 Power-Down 挂起状态。
|
||||
* **主选择菜单 (STATE_MENU)**:在 `STATE_CLOCK` 下长按 **■ 确认键** 3 秒进入。单屏只显示 1 个功能,通过 ▲/▼ 键来回翻页,CONFIRM 键确认进入:
|
||||
1. `1. DATE/HEURE` (进入时间日期修改界面 `STATE_SET_TIME`)
|
||||
2. `2. APPAIRAGE` (进入对码配对搜索界面 `STATE_PAIR_SEARCH`)
|
||||
3. `3. ARM/DISARM` (进入系统布撤防手动设定界面 `STATE_ARM_DISARM_SELECT`)
|
||||
4. `4. LIAISON IPC` (进入 IPC 摄像头绑定发送界面 `STATE_IPC_BIND`)
|
||||
|
||||
### 1.2 按键动作状态机映射
|
||||
|
||||
| 当前状态 | ▲ 上移键动作 | ▼ 下移键动作 | ■ 确认键 (CONFIRM) 动作 | SOS1 / SOS2 按键动作 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **侧边按键** | **▲ 上移键** | 短按:时间微调 | 菜单向上滚动 / **确认对码时自增序号 (01->99)** | 无动作 |
|
||||
| **侧边按键** | **▼ 下移键** | 短按:时间微调 | 菜单向下滚动 / **确认对码时自减序号 (99->01)** | 长按 2 秒:解除当前告警并退回时钟 |
|
||||
| **侧边按键** | **▲ + ▼ (同时长按3秒)** | **进入对码配对模式** | 无动作 | 无动作 |
|
||||
| **侧边按键** | **■ 确认键 (CONFIRM)** | 无动作 | 菜单确认 / **对码确认页:确认保存配置** | 短按:解除当前告警并退回时钟 |
|
||||
| **上部按键** | **SOS1 / SOS2 (短按)** | **触发本地主动 SOS 呼救 + 循环发射 433MHz 呼救包** | **对码确认页:确认保存配置** | 短按:解除告警并退回时钟 |
|
||||
| **上部按键** | **SOS1 / SOS2 (长按5秒)** | **触发 IPC 绑定对码广播** | 无动作 | 长按:解除告警并退回时钟 |
|
||||
| **时钟待机 (STATE_CLOCK)** | 无动作 | 无动作 | 长按 3 秒:进入主选择菜单 | 短按/长按:立即跳转至发送 SOS 报警 (`STATE_SOS_EMITTED`) |
|
||||
| **低功耗休眠 (STATE_SLEEP)** | 短按:唤醒并恢复至时钟待机 | 短按:唤醒并恢复至时钟待机 | 短按:唤醒并恢复至时钟待机 | 短按/长按:唤醒系统并立即触发 SOS 报警 |
|
||||
| **主选择菜单 (STATE_MENU)** | 短按:上一个菜单条目(切换大图标与大字) | 短按:下一个菜单条目(切换大图标与大字) | 短按:确认进入选中分支;长按 3 秒:退出菜单返回时钟 | 短按/长按:立即跳转至发送 SOS 报警 |
|
||||
| **时间修改 (STATE_SET_TIME)** | 短按:增加当前选中数值 | 短按:减少当前选中数值 | 短按:保存并切换到下一个修改参数;长按 3 秒:放弃修改返回时钟 | 短按/长按:立即跳转至发送 SOS 报警 |
|
||||
| **对码配对 (STATE_PAIR_SEARCH)** | 无动作 | 长按 2 秒:放弃对码返回主菜单 | 无动作 | 短按/长按:立即跳转至发送 SOS 报警 |
|
||||
| **对码确认微调 (STATE_PAIR_CONFIRM)** | 短按:自增后缀序号 (01->99) | 短按:自减后缀序号 (99->01) | 短按:确认保存配置并存入 Flash,返回时钟;长按 3 秒:放弃保存返回时钟 | 短按/长按:立即跳转至发送 SOS 报警 |
|
||||
| **布撤防手动设定 (STATE_ARM_DISARM_SELECT)** | 短按:切换布撤防高亮项 | 短按:切换布撤防高亮项 | 短按:保存选定状态返回时钟 | 短按/长按:立即跳转至发送 SOS 报警 |
|
||||
| **IPC 绑定发送 (STATE_IPC_BIND)** | 无动作 | 长按 2 秒:放弃绑定返回时钟 | 短按:立刻再次发射绑定射频包;长按 3 秒:退出返回时钟 | 短按/长按:立即跳转至发送 SOS 报警 |
|
||||
| **警报触发状态 (STATE_ALARMING)** | 短按:解除报警并退回时钟 | 短按:解除报警并退回时钟 | 短按:解除报警并退回时钟 | 短按/长按:解除报警并退回时钟 |
|
||||
| **本地主动 SOS 发送 (STATE_SOS_EMITTED)** | 短按:解除 SOS 发送退回时钟 | 短按:解除 SOS 发送退回时钟 | 短按:解除 SOS 发送退回时钟 | 短按/长按:解除 SOS 发送退回时钟 |
|
||||
|
||||
> [!NOTE]
|
||||
> 1. **双 SOS 按键冗余**:上部的两个 SOS 键在电路与软件上完全等价。按下其中任意一个按键,均会触发相同的 SOS 信号采集与求救动作。
|
||||
> 2. **警报快速解除**:在手环发出主动 SOS 呼救或响应被动防区报警时,按下“确认键”或任意一个“SOS 键”(或者长按“▼键”2秒)均会立刻切断声光电反馈,安全重置至时钟待机状态。
|
||||
> 3. **确认页序号手动修改**:当捕获到匹配 of 射频信号进入对码确认页时,界面将显示当前选定的前缀和初始序号。用户可以使用 ▲ 键增加序号,使用 ▼ 键减少序号(范围 `01` 到 `99`,达到边界自动截断),选中后按下“确认键”或任意“SOS 键”进行保存。
|
||||
> 4. **屏幕常亮与全时射频监测**:系统不进行任何低功耗关屏或停机操作。TFT LCD 屏幕始终常亮显示时钟待机画面。主频与 1ms 定时中断全时运转,配置 **`P0.0` (ADC 通道 8)** 进行电池电量采样,配置 **`P2.7`** 监测充电插拔状态。使 433MHz 射频解调模块保持 100% 实时无线监听接收,并在任何时候(包括待机和菜单状态)按下 SOS 均能实现即刻发送求救包。
|
||||
> 2. **一键报警优先级**:除了在报警状态和本地 SOS 发送状态下按 SOS 键为解除报警外,在其它任意状态下,短按或长按 SOS 键均拥有最高优先级,立刻强行中止当前业务并跳转至 SOS 呼救状态。
|
||||
> 3. **对码自动类型识别与后缀选择**:
|
||||
> * 手环在接收到 433MHz 射频对码信号时,**自动根据数据码(Data Code)识别传感器类型**,并直接跳转到对码微调页面。
|
||||
> * 在微调确认页面中,传感器类型和图标以大字只读显示,用户仅需通过 ▲/▼ 键增减微调该传感器的超大数字后缀序号(01~99)。按 CONFIRM 键即可一键保存并写入 Flash 数据库。
|
||||
> 4. **低功耗休眠与唤醒**:在待机、菜单或非报警页面下,若 **10秒内无任何按键操作**,系统将自动关闭 OLED 屏幕、切断 SGM3833 PMIC 电源,并将 MCU 挂起进入 Power-Down 停机模式。任何按键的按下或射频信号的接收都会通过中断将 CPU 瞬间唤醒。
|
||||
|
||||
## 2. 传感器对码与报警映射矩阵
|
||||
|
||||
手环接收到 433MHz 传感器射频数据后,通过匹配预设数据码(高 4 位为类型)和地址码,根据下表驱动多色 LED、马达振动波形并更新 LCD 显示。本系统支持 7 种不同的外部传感器类型,并预留了出厂预设的固定名称前缀。
|
||||
手环接收到 433MHz 传感器射频数据后,通过匹配预设数据码(高 4 位为类型)和地址码,根据下表驱动多色 LED、马达振动波形并更新 LCD 显示。为了方便视障及老年用户识别,显示均采用超大图标与闪烁红边框。
|
||||
|
||||
| 传感器类型 | 数据码标识 | 预设名前缀 | LED 颜色 | 默认防区类型 | 马达振动波形 (周期 5 秒) |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
@@ -43,9 +60,6 @@
|
||||
> * **数据码**:固定为 **`0x08`** (即 `1000`)。
|
||||
> * **目的**:使 IPC 摄像头能接收解码,将其与配对列表中该手环 of Factory ID 匹对,从而识别求救来源。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **屏蔽 SOS 被动报警**:为避免两个手环互发 SOS 相互触发造成死循环报警,手环**必须强行过滤**并排除对外界发射的 SOS 求救广播(数据码为 `0x08`,或其它手环发射源)的被动接收。
|
||||
|
||||
## 3. ZONE 防区划分
|
||||
|
||||
手环支持将配对的传感器划分至不同的防区:
|
||||
|
||||
@@ -1,107 +1,283 @@
|
||||
# 架构设计 (Docs/30_architecture/main.md)
|
||||
# 架构设计说明书 (Docs/30_architecture/main.md)
|
||||
|
||||
本章节阐述手环的硬件拓扑、引脚分配、软件状态机设计、以及 IAP Flash 数据库存储设计。
|
||||
本章节定义手环的系统软硬件架构设计,包括引脚分配、核心状态机迁移关系、持久化数据存储结构以及软件分层框架与主循环调度流程。
|
||||
|
||||
## 1. 硬件规格与引脚映射
|
||||
---
|
||||
|
||||
主控芯片采用 **STC32G12K128** 单片机(工作频率 24.0 MHz,单周期 8051 内核,32位乘除法器)。
|
||||
显示端采用 **1.14寸 TFT LCD 屏幕**,物理分辨率为 **135x240 像素**。
|
||||
## 1. 硬件原理图与引脚分配架构
|
||||
|
||||
### 1.1 GPIO 引脚配置表
|
||||
手环的完整电路连接设计参见以下 KiCad 硬件工程文件:
|
||||
* **硬件原理图**:[text.kicad_sch](file:///c:/workfile/105/stc32g12k128/Hardware/text.kicad_sch)
|
||||
* **PCB 布局图**:[text.kicad_pcb](file:///c:/workfile/105/stc32g12k128/Hardware/text.kicad_pcb)
|
||||
|
||||
| 引脚号 | 引脚定义 | 模式配置 | 物理外设与功能说明 |
|
||||
主控芯片采用 **STC32G12K128**(工作频率 24.0 MHz,单周期 8051 内核,32位乘除法器)。
|
||||
显示端采用 **Truly 0.95寸 AMOLED 屏幕**,物理分辨率为 **120x240 像素**,控制芯片为 **RM69310**。
|
||||
|
||||
### 1.1 GPIO 物理映射表
|
||||
|
||||
| 引脚号 | 引脚名称 | IO 模式 | 连接外设与功能描述 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **P2.3** | `WS2812_DI` | 双向/SPI MOSI | 连接可编程 RGB 灯珠(WS2812B/FCOB-2.7)的 DIN 信号输入 |
|
||||
| **P2.5** | `MOTOR` | 推挽输出/SCLK | 连接振动马达驱动电路。高电平震动,低电平静止 |
|
||||
| **P0.0** | `BAT_ADC` | 模拟输入 | 电池电压采样输入端口,对应硬件 ADC 通道 8 (A8) |
|
||||
| **P0.1** | `KEY_UP` | 高阻输入+上拉 | 侧边按键 ▲ (上移),按下为低电平 |
|
||||
| **P0.2** | `KEY_SOS1` | 高阻输入+上拉 | 上部按键 SOS 1,按下为低电平 |
|
||||
| **P0.3** | `KEY_DOWN` | 高阻输入+上拉 | 侧边按键 ▼ (下移),按下为低电平 |
|
||||
| **P0.4** | `KEY_CONFIRM`| 高阻输入+上拉 | 侧边按键 ■ (确认),按下为低电平 |
|
||||
| **P0.2** | `KEY_SOS1` | 高阻输入+上拉 | 上部按键 SOS 1,按下为低电平 |
|
||||
| **P0.5** | `KEY_SOS2` | 高阻输入+上拉 | 上部按键 SOS 2,按下为低电平 |
|
||||
| **P3.4** | `LCD_PWR_CTRL` | 推挽输出 | LCD 屏幕背光与芯片电源控制引脚。高电平使能,低电平关闭 |
|
||||
| **P1.1** | `LCD_RST` | 推挽输出 | LCD 屏幕复位引脚 |
|
||||
| **P1.3** | `LCD_RS` | 推挽输出 | LCD 屏幕 SPI 数据/命令寄存器选择 (D/C) |
|
||||
| **P1.4** | `LCD_CS` | 推挽输出 | LCD 屏幕 SPI 片选信号 |
|
||||
| **P1.5** | `LCD_SCL` | 推挽输出 | LCD 屏幕 SPI 时钟信号 |
|
||||
| **P1.6** | `LCD_SDA` | 推挽输出 | LCD 屏幕 SPI 数据信号 |
|
||||
| **P0.0** | `BAT_ADC` | 模拟输入 | 电池电压采样输入端口,对应硬件 ADC 通道 8 (A8) |
|
||||
| **P2.3** | `WS2812_DI` | SPI MOSI | 连接可编程双级联 RGB 灯珠的 DIN 信号输入 |
|
||||
| **P2.5** | `MOTOR` | 推挽输出 | 连接振动马达驱动电路。高电平震动,低电平静止 |
|
||||
| **P2.7** | `USB_DET` | 高阻输入 | USB 插入充电检测引脚,高电平代表正在充电 |
|
||||
|
||||
### 1.2 上部双 SOS 键并联逻辑设计
|
||||
|
||||
为了保证两颗 SOS 按键在软件逻辑上等价,软件在按键消抖和长按状态判定时,采用“逻辑并联”设计。定义一个虚拟的 `is_sos_pressed` 状态标志:
|
||||
```c
|
||||
// 只要 SOS1 或 SOS2 有任意一个被按下(低电平),即判定为 SOS 按下
|
||||
bit is_sos_pressed = (KEY_SOS1 == 0) || (KEY_SOS2 == 0);
|
||||
```
|
||||
该标志后续被直接送入消抖状态机和长按计时器,生成 `KEY_SOS_SHORT` 或 `KEY_SOS_LONG` 事件,从而完全对上层业务层屏蔽双按键硬件细节。
|
||||
|
||||
### 1.3 出厂唯一固定 ID (Factory ID) 的设计与获取
|
||||
|
||||
手环在主动发射对码广播与主动 SOS 报警时,需要以唯一的出厂 ID (Factory ID) 作源地址以供接收端(IPC)进行辨识。
|
||||
为避免每台手环烧写不同固件,程序从 STC32G 内置的全球唯一硬件 ID (UID) 中提取地址码:
|
||||
* **硬件读取源**:STC32G 芯片在出厂时会在程序存储器(ROM)的末尾扇区存储一个 **7 字节的唯一 ID**,同样在 RAM 空间的特定区(如 `0xF1`~`0xF7`)也会在启动时映射。
|
||||
* **Factory ID 生成**:系统初始化时,通过读取 UID 寄存器,将其中的 3 个字节提取出来,并进行 `& 0x0FFFFF`(20位掩码限制,以符合 EV1527 的 20 位地址规范),存入全局变量 `bracelet_factory_id` 中。若读取 UID 失败,则默认使用硬编码预置 ID `0x37A86UL`。
|
||||
|
||||
### 1.4 SPI 复用与马达防噪硬件规避设计
|
||||
|
||||
由于 `P2.5` 同时作为马达引脚和硬件 SPI 的 SCLK 引脚,为了避免在高频发送 24-bit 灯效数据时引脚电平抖动导致马达异常鸣叫:
|
||||
1. **发送前**:调用 `EA = 0` 关闭总中断。临时将 `P2.5` 引脚配置为 **高阻输入模式**。此时 SCLK 输出时钟不会使马达导通。
|
||||
2. **发送中**:通过硬件 SPI 直接串行写入 72 位转换数据(24位 RGB 经过 LUT 展宽)。
|
||||
3. **发送后**:将 `P2.5` 引脚改回 **推挽输出模式**。调用 `EA = 1` 开启中断,继续通过常规 IO 控制马达电平。
|
||||
|
||||
### 1.5 确认配对时的后缀序号调整机制
|
||||
|
||||
在对码确认状态 (`STATE_PAIR_CONFIRM`) 下,系统支持用户手动微调所要保存同类防区的数字序号:
|
||||
* **全局变量定义**:`u8 selected_suffix_num` 用以记录当前的数字选择值。
|
||||
* **初始默认分配**:当信号被捕获跳转到该状态时,系统自动检索当前内存对码表,统计捕获类型已登记的个数 $C$,将 `selected_suffix_num` 初始化为 $C + 1$。
|
||||
* **按键调整行为**:
|
||||
* 读取到 `KEY_EVENT_UP_CLICK` 时:`if (selected_suffix_num < 99) selected_suffix_num++`。
|
||||
* 读取到 `KEY_EVENT_DOWN_CLICK` 时:`if (selected_suffix_num > 1) selected_suffix_num--`。
|
||||
* 调值完成后置 `Redraw = 1` 以触发 LCD 快速局部刷新。
|
||||
* **最终确认写入**:当用户按下 CONFIRM 键或 SOS 键时,系统自动取出对应的预设名前缀(如 `PORTE`),并将 `selected_suffix_num` 转换为两位字符串格式(如 `02`),以 `[前缀] [序号]` 格式拼装后(最大 15 字节,如 `PORTE 02`),调用数据库写入函数。
|
||||
| **P3.4** | `SGM_CTRL` | 推挽输出 | OLED 供电芯片 SGM3833 控制引脚。高电平使能,低电平关闭 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心软件业务状态机 (SystemState)
|
||||
## 2. 软件核心业务状态机
|
||||
|
||||
系统处于主循环中,根据事件和计数器在以下状态(`SystemState`)间迁移:
|
||||
系统包含 10 个业务状态,其状态迁移关系如下图所示:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> STATE_NORMAL
|
||||
STATE_NORMAL --> STATE_ARMED : 接收到布防广播
|
||||
STATE_ARMED --> STATE_DISARMED : 接收到撤防广播
|
||||
STATE_DISARMED --> STATE_NORMAL : 自动恢复/按键返回
|
||||
[*] --> STATE_CLOCK
|
||||
|
||||
STATE_NORMAL --> STATE_PAIR_MENU : ▲ + ▼ 长按 3 秒
|
||||
STATE_PAIR_MENU --> STATE_PAIR_WAIT : 确认选中类型
|
||||
STATE_PAIR_WAIT --> STATE_PAIR_CONFIRM : 捕获 433MHz 匹配数据
|
||||
STATE_PAIR_CONFIRM --> STATE_PAIR_SUCCESS : 按 CONFIRM/SOS 键并保存名称
|
||||
STATE_PAIR_CONFIRM --> STATE_PAIR_FAIL : 超时/长按▼取消
|
||||
STATE_PAIR_SUCCESS --> STATE_PAIR_MENU : 2秒后自动返回
|
||||
STATE_PAIR_FAIL --> STATE_PAIR_MENU : 2秒后自动返回
|
||||
%% 休眠与唤醒
|
||||
STATE_CLOCK --> STATE_SLEEP : 10秒无操作超时
|
||||
STATE_SLEEP --> STATE_CLOCK : 中断唤醒 (按键/无线信号)
|
||||
|
||||
STATE_NORMAL --> STATE_SOS_EMITTED : 短按 SOS
|
||||
STATE_ARMED --> STATE_ALARMING : 捕获已配对传感器报警
|
||||
STATE_ALARMING --> STATE_NORMAL : 按任意键/超时解除
|
||||
STATE_SOS_EMITTED --> STATE_NORMAL : 长按任意键/超时解除
|
||||
%% 主选择菜单迁移
|
||||
STATE_CLOCK --> STATE_MENU : CONFIRM 长按 3 秒
|
||||
STATE_MENU --> STATE_CLOCK : CONFIRM 长按 3 秒 / 10秒无操作超时
|
||||
STATE_MENU --> STATE_SLEEP : 10秒无操作超时
|
||||
|
||||
%% 子设置页面迁移
|
||||
STATE_MENU --> STATE_SET_TIME : 选中 "1. HORLOGE" + 确认键单击
|
||||
STATE_SET_TIME --> STATE_CLOCK : 保存退出 / 10秒无操作超时
|
||||
|
||||
STATE_MENU --> STATE_PAIR_SEARCH : 选中 "2. APPAIR." + 确认键单击
|
||||
STATE_PAIR_SEARCH --> STATE_PAIR_CONFIRM : 捕获 433MHz 传感器数据 (自动识别传感器类型)
|
||||
STATE_PAIR_CONFIRM --> STATE_CLOCK : 序号微调后 CONFIRM 确认保存
|
||||
STATE_PAIR_SEARCH --> STATE_MENU : 长按 ▼ 键退出
|
||||
|
||||
STATE_MENU --> STATE_ARM_DISARM_SELECT : 选中 "3. ALARME" + 确认键单击
|
||||
STATE_ARM_DISARM_SELECT --> STATE_CLOCK : 选择完成并返回
|
||||
|
||||
STATE_MENU --> STATE_IPC_BIND : 选中 "4. LIAISON" + 确认键单击
|
||||
STATE_IPC_BIND --> STATE_CLOCK : 发射结束 / 确认键长按 3s 退出 / ▼键长按 2s 退出
|
||||
|
||||
%% 报警迁移
|
||||
STATE_CLOCK --> STATE_SOS_EMITTED : 按下上部任意 SOS 键 (点击/长按)
|
||||
STATE_SLEEP --> STATE_SOS_EMITTED : 中断唤醒直接报警
|
||||
STATE_SOS_EMITTED --> STATE_CLOCK : 按任意键/超时退出
|
||||
|
||||
STATE_CLOCK --> STATE_ALARMING : 捕获已配对传感器报警 (ZONE 0 或布防下的 ZONE 1)
|
||||
STATE_ALARMING --> STATE_CLOCK : 按任意键/超时退出
|
||||
```
|
||||
|
||||
### 2.1 低功耗设计与唤醒架构
|
||||
为实现超低功耗,系统在 `STATE_SLEEP` 状态下使用以下硬件与软件协同设计:
|
||||
1. **彻底切断 PMIC**:拉低 `SGM_CTRL = 0`,使 SGM3833 停止工作,彻底消除 Truly AMOLED 屏的负压静态功耗。
|
||||
2. **休眠配置**:允许 P0 口电平变化中断与射频接收引脚的中断使能。
|
||||
3. **进入停机**:将单片机挂起写入 `PCON |= 0x02` 进入停机模式,关闭主时钟。
|
||||
4. **中断唤醒**:按键按下或 LR690L 接收到载波变化时,触发中断唤醒 MCU,ISR 立即拉高 `SGM_CTRL = 1` 并延时约 50ms 重新初始化 RM69310 屏幕控制器以恢复显示。
|
||||
|
||||
---
|
||||
|
||||
## 3. 持久化配置数据库架构
|
||||
|
||||
为了确保配对数据掉电不丢失,手环使用内置 IAP 读写 Flash 扇区:
|
||||
* **物理存储扇区**:`0xFE0000` (末尾扇区,大小为 512 字节)。
|
||||
* **数据库容量**:共 16 组传感器配置槽位。
|
||||
* **存储结构定义**:
|
||||
```c
|
||||
typedef struct {
|
||||
u8 is_used; // 有效标志 (0x01: 有效, 其它: 空闲)
|
||||
u8 addr[3]; // 24位射频物理地址 (EV1527)
|
||||
u8 type; // 传感器类型 (0: 门磁, 1: 红外, 2: 烟感, 3: 紧急, 4: 气体, 5: 水浸, 6: 振动)
|
||||
u8 zone; // 防区类别 (0: 永久防区, 1: 普通可撤布防区)
|
||||
char name_gbk[16]; // 法语自定义防区名称 (格式化为: [名前缀] [两位序号])
|
||||
} Sensor_Slot;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. IAP Flash 传感器数据库设计
|
||||
## 4. 软件层级架构与核心代码框架
|
||||
|
||||
为了断电保存传感器配对信息,使用 STC32G 的 IAP 功能读写 Flash:
|
||||
* **扇区基地址**:`0xFE0000` (末尾扇区)。
|
||||
* **存储结构**:`Sensor_Slot` 结构体:
|
||||
```c
|
||||
typedef struct {
|
||||
u8 is_used; // 登记标志(0x01表示有效,其它代表空闲)
|
||||
u8 addr[3]; // 24位射频物理地址 (EV1527)
|
||||
u8 type; // 传感器类型 (0:门磁, 1:红外, 2:烟感, 3:紧急, 4:气体, 5:水浸, 6:振动)
|
||||
u8 zone; // 防区类别 (0: 永久防区, 1: 普通可撤防区)
|
||||
char name_gbk[16]; // 法语自定义防区名称 (以 [前缀] [序号] 自动格式化写入)
|
||||
} Sensor_Slot;
|
||||
```
|
||||
* 一共支持 **16** 个传感器槽位,通过 `Load_Database()` 和 `Save_Database()` 进行统一序列化读写。
|
||||
软件系统采用 **非阻塞** 的三层级模块化架构设计:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Layer3 [应用层 (APP)]
|
||||
MainScheduler[主循环轮询 & 喂狗]
|
||||
SysStateMachine[SystemState 业务状态机]
|
||||
SoftRTC[软件 RTC 计时器]
|
||||
end
|
||||
subgraph Layer2 [外设驱动层 (DRV)]
|
||||
AMOLED[RM69310 AMOLED 屏幕绘制]
|
||||
RF[LR690L 编解码 & 接收处理]
|
||||
KEY[按键消抖 & 长按长计时]
|
||||
PM[低功耗休眠与唤醒]
|
||||
LED[WS2812B 级联双彩灯时序]
|
||||
MOTOR[振动马达脉冲时序]
|
||||
end
|
||||
subgraph Layer1 [硬件抽象与时基层 (HW)]
|
||||
Timer1[Timer 1 中断 (1ms 滴答)]
|
||||
ADC[12位电压采集]
|
||||
Flash[IAP 读写]
|
||||
GPIO[数字 I/O 与电平中断]
|
||||
end
|
||||
Layer1 --> Layer2
|
||||
Layer2 --> Layer3
|
||||
```
|
||||
|
||||
### 4.1 核心主程序调度框架 (main.c)
|
||||
|
||||
主程序采用完全解耦的时间片轮询加事件触发的非阻塞循环结构:
|
||||
|
||||
```c
|
||||
#include "config.h"
|
||||
|
||||
// 全局状态变量
|
||||
SystemState current_state;
|
||||
u16 inactivity_timer;
|
||||
u32 rx_addr;
|
||||
u8 rx_type;
|
||||
|
||||
void main(void) {
|
||||
// 1. 初始化底层硬件与外设驱动
|
||||
System_Init();
|
||||
Power_Init(); // SGM_CTRL 默认拉高工作
|
||||
LCD_Init(); // Truly AMOLED 初始化
|
||||
RF_Init(); // LR690L 接收中断与发射初始化
|
||||
WS2812_Init(); // 双级联彩灯初始化
|
||||
Motor_Init(); // 马达脉冲时序初始化
|
||||
ADC_Init(); // 电池采样初始化
|
||||
|
||||
// 2. 载入持久化数据配置
|
||||
Load_Database();
|
||||
|
||||
// 3. 初始化软件状态与计时器
|
||||
current_state = STATE_CLOCK;
|
||||
inactivity_timer = 0;
|
||||
Redraw = 1;
|
||||
|
||||
// 开启全局中断
|
||||
EA = 1;
|
||||
|
||||
// 4. 核心主循环轮询调度
|
||||
while (1) {
|
||||
// A. 轮询射频接收
|
||||
if (EV1527_Decode(&rx_addr, &rx_type)) {
|
||||
inactivity_timer = 0; // 重置休眠计数
|
||||
Process_RF_Event(rx_addr, rx_type);
|
||||
}
|
||||
|
||||
// B. 轮询并消耗按键事件
|
||||
if (key_event_buf != KEY_EVENT_NONE) {
|
||||
KeyEvent evt = key_event_buf;
|
||||
key_event_buf = KEY_EVENT_NONE; // 清空事件
|
||||
inactivity_timer = 0; // 重置休眠计数
|
||||
|
||||
Process_System_Event(evt);
|
||||
}
|
||||
|
||||
// C. 超时低功耗检测判定
|
||||
if (inactivity_timer >= 1000) { // 10秒无操作
|
||||
inactivity_timer = 0;
|
||||
current_state = STATE_SLEEP;
|
||||
|
||||
// 执行硬件关屏断电并让单片机进入深度休眠
|
||||
Enter_Low_Power_Sleep();
|
||||
|
||||
// 被外部中断唤醒后从此处开始继续向下运行,执行电源与显示恢复
|
||||
Wakeup_Restore();
|
||||
current_state = STATE_CLOCK;
|
||||
Redraw = 1;
|
||||
}
|
||||
|
||||
// D. 屏幕刷新渲染调度
|
||||
if (Redraw) {
|
||||
Redraw = 0; // 清除标志
|
||||
Render_UI_Screen(current_state);
|
||||
}
|
||||
|
||||
// E. 喂狗操作
|
||||
WDT_CONTR = 0x17;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 模块间输入/输出事件与流转处理消耗图
|
||||
|
||||
为了使各功能模块(Drivers & App)交互逻辑清晰可见,下表整理了各模块产生的事件源(输入)及其被消费(输出)的处理链路:
|
||||
|
||||
### 5.1 模块输入/输出事件矩阵
|
||||
|
||||
| 模块名称 | 输入源 (触发源) | 产生/发出事件 | 输出消费对象 (消费处理) |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **按键模块 (KEY)** | 物理引脚(P0.1~P0.5)电平状态改变 | `KeyEvent`<br>- `KEY_UP_SHORT` / `KEY_DOWN_SHORT`<br>- `KEY_DOWN_LONG` (长按▼ 2秒)<br>- `KEY_CONFIRM_CLICK`<br>- `KEY_CONFIRM_LONG` (长按■ 3秒)<br>- `KEY_SOS_SHORT` / `KEY_SOS_LONG` (SOS键短按或长按) | 写入全局事件缓冲队列 `key_event_buf`。由 **APP 应用状态机** 读出后用于控制页面导航、退出告警或启动对码。 |
|
||||
| **无线射频 (RF)** | LR690L 433MHz 载波信号接收(输入电平变化) | `RFEvent` (包含 `rx_addr` 与 `rx_type`) | 传递至 **APP 状态机** 的 `Process_RF_Event` 进行报警分发。 |
|
||||
| **状态机 (APP)** | 消耗 `key_event_buf` 或 `RFEvent` | `SysState` 业务状态跳转及动作指令 | 1. 改变 `current_state` 并设置 `Redraw = 1`;<br>2. 调度 **LED** 及 **MOTOR** 开启报警灯效/马达振动;<br>3. 写入 **IAP Flash 数据库** 配对记录;<br>4. 调用 **RF** 发送对码或主动SOS信号。 |
|
||||
| **显示模块 (LCD)** | 状态机重绘请求 `Redraw == 1` | SPI 像素渲染显示流 | 驱动 **Truly AMOLED** 渲染当前状态所对应的时钟、主菜单、对码、时间设定或报警画面。 |
|
||||
| **供电管理 (POWER)**| 1. `inactivity_timer >= 1000` (10秒超时)<br>2. 中断唤醒信号 (GPIO/INT2) | 电源电平控制及停机状态 | 1. **进入休眠**:发出关屏指令 -> 拉低 `SGM_CTRL = 0` -> 执行停机挂起(主循环暂停在 `Enter_Low_Power_Sleep` 内);<br>2. **唤醒恢复**:拉高 `SGM_CTRL = 1` -> 延时 50ms -> 重新初始化 RM69310 屏幕控制器(主循环恢复运行并重绘时钟)。 |
|
||||
| **彩灯模块 (LED)** | 状态机调用报警指示请求 | SPI 48-bit 灯珠级联控制字 | 向两颗级联的 WS2812B 发送颜色数据(报警时交替闪烁,配对时常亮)。 |
|
||||
| **马达模块 (MOTOR)**| 状态机请求按键反馈/告警振动 | IO 电平状态控制字 (P2.5) | 定时驱动 `P2.5` 引脚电平产生不同振动波形(如短振、长振、间歇循环振动)。 |
|
||||
|
||||
### 5.2 事件流转与消费链路拓扑
|
||||
|
||||
手环系统的输入事件(按键中断与无线载波中断)在主循环中的处理与消耗流转关系如下:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 硬件输入事件
|
||||
PinKey[物理按键按下 / 下降沿] -->|P0.1-P0.5 端口中断| ISR_Port0[Port0 中断 ISR]
|
||||
Carrier[433MHz 射频载波信号] -->|INT2 中断| ISR_INT2[INT2 唤醒中断 ISR]
|
||||
|
||||
%% 中断服务层 (ISR)
|
||||
ISR_Port0 -->|唤醒系统并每10ms扫描| KeyScan[消抖与长短按判定]
|
||||
ISR_INT2 -->|唤醒系统并使能软解码| RFDecode[EV1527 自适应比值解码]
|
||||
|
||||
%% 事件过滤与缓冲层
|
||||
KeyScan -->|判定有效按键事件| BufKey[写入 key_event_buf 缓冲区]
|
||||
RFDecode --> ProcessRF[生成合法传感器 RFEvent]
|
||||
|
||||
%% APP 状态机消费处理
|
||||
BufKey -->|主循环读取并重置| SM_Key[消费按键事件]
|
||||
ProcessRF -->|主循环调用并比对配置| SM_RF[消费已配对防区报警]
|
||||
|
||||
SM_Key -->|CONFIRM 长按 3s| StateMenu[切入 STATE_MENU 并 Redraw=1]
|
||||
SM_Key -->|子页面确认操作| StateSub[执行配对/布防/时间设定并 IAP 写入]
|
||||
SM_Key -->|点击/长按 SOS 键| EmitSOS[调用 RF 主动发射 0x08 SOS 信号]
|
||||
SM_Key -->|告警状态任意键| ClearAlarm[清除本地报警状态并退回时钟]
|
||||
|
||||
SM_RF -->|匹配成功且处于布防| LocalAlarm[触发 LED 交替闪烁 & 马达间歇振动]
|
||||
|
||||
%% 显示与控制响应
|
||||
StateMenu -->|Redraw == 1| LcdPaint[Truly AMOLED 屏幕局部像素重绘]
|
||||
StateSub -->|Redraw == 1| LcdPaint
|
||||
LocalAlarm -->|Redraw == 1| LcdPaint
|
||||
EmitSOS -->|Redraw == 1| LcdPaint
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 核心业务事件输入输出 (I/O) 架构明细表
|
||||
|
||||
为实现绝对清晰的软硬件交互链路,以下为手环核心业务事件的端到端输入、输出及流转逻辑汇总:
|
||||
|
||||
### 6.1 核心事件 I/O 矩阵
|
||||
|
||||
| 事件名称 | 输入源 (触发条件与参数) | 状态机判定逻辑 (当前状态与条件) | 输出结果 & 动作执行 (显示、灯效、马达与无线) |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **按键操作事件**<br>`KEY_EVENT` | **源**:P0.1~P0.5 下降沿中断。<br>**参数**:`KEY_UP`、`KEY_DOWN`、`KEY_CONFIRM` (短按/长按)。 | **当前状态**:`STATE_CLOCK` / `STATE_MENU` 等。<br>**条件**:在待机下长按确认键 3 秒进入菜单;在菜单下短按 ▲/▼ 键翻页。 | 1. **显示**:置 `Redraw = 1`,LCD 刷新切换对应页面;<br>2. **触觉**:发出 50ms 极短振动作按键反馈。 |
|
||||
| **主动求救事件**<br>`SOS_ACTIVE_EVENT` | **源**:上部任意 SOS 按键按下(短按或长按)。 | **当前状态**:除已报警外的任意业务状态。<br>**条件**:无视当前状态,拥有最高抢占优先级。 | 1. **状态**:切入 `STATE_SOS_EMITTED`;<br>2. **无线**:通过 LR690L 周期性(2s)发射手环 Factory ID 及 `0x08` (SOS) 数据包;<br>3. **显示**:LCD 闪烁呈现超大警灯与分行 `SOS EMIS` 字样;<br>4. **灯效**:WS2812B 红色高速交替闪烁(50ms周期);<br>5. **马达**:持续间歇长振(振 1000ms,停 200ms)。 |
|
||||
| **无线对码捕获事件**<br>`RF_PAIR_RECV_EVENT` | **源**:LR690L 接收 433MHz 对码载波包。<br>**参数**:24-bit 物理地址 + 4-bit 传感器类型数据码。 | **当前状态**:`STATE_PAIR_SEARCH` (搜索对码中)。<br>**条件**:捕获到合法 EV1527 帧。 | 1. **状态**:切换至 `STATE_PAIR_CONFIRM` (确认微调);<br>2. **显示**:只读显示自动识别的传感器名称(如 `PORTE`)、大图标,以及超大 `[ 01 ]` 序号选框;<br>3. **马达**:发出 300ms 短振提醒成功捕获。 |
|
||||
| **传感器入侵警报事件**<br>`RF_ALARM_RECV_EVENT` | **源**:LR690L 接收 433MHz 警报载波包。<br>**参数**:传感器地址 + 4-bit 状态码。 | **当前状态**:`STATE_CLOCK` (待机)。<br>**条件**:1. 地址与 Flash 数据库匹配;<br>2. 该防区属于 ZONE 0 (24h) 或处于已布防状态下的 ZONE 1。 | 1. **状态**:切入 `STATE_ALARMING`;<br>2. **显示**:LCD 亮起 4px 闪烁红边框与 64x64px 对应传感器报警图标,显示 `PORTE 01 INTRUSION!`;<br>3. **灯效**:WS2812B 闪烁对应传感器防区色彩(500ms闪烁);<br>4. **马达**:根据传感器类型,输出对应的间歇振动波形(如门磁短振 1 次)。 |
|
||||
| **系统自动休眠事件**<br>`AUTO_SLEEP_EVENT` | **源**:软件时钟 `inactivity_timer >= 1000` (10s)。 | **当前状态**:`STATE_CLOCK` / `STATE_MENU` / `STATE_SET_TIME` 等非报警状态。 | 1. **状态**:切入 `STATE_SLEEP`;<br>2. **硬件**:拉低 `SGM_CTRL = 0` 切断 AMOLED PMIC 供电;<br>3. **电源**:使能 P0 口电平中断及 INT2,挂起 CPU 进入 Power-Down 极低功耗模式。 |
|
||||
| **中断唤醒系统事件**<br>`SYSTEM_WAKEUP_EVENT` | **源**:P0口按键沿变化或 INT2 载波接收中断。 | **当前状态**:`STATE_SLEEP` (深度休眠中)。 | 1. **状态**:切回 `STATE_CLOCK`;<br>2. **电源**:拉高 `SGM_CTRL = 1` 恢复 OLED 供电;<br>3. **延迟**:延时 50ms 避开冲击电流并完成 RM69310 的重初始化;<br>4. **显示**:置 `Redraw = 1` 重绘时钟走时界面。 |
|
||||
| **IPC 摄像头对码事件**<br>`IPC_BIND_SEND_EVENT` | **源**:在菜单中确认进入 `4. LIAISON`。 | **当前状态**:`STATE_IPC_BIND`。 | 1. **无线**:连发 433MHz 手环 Factory ID 及 `0x01` 绑定对码包;<br>2. **显示**:呈现 48x48px 摄像头大图标及 `LIAISON EN COURS`;<br>3. **退出**:长按确认键 3 秒或长按 ▼ 键 2 秒,退出并恢复时钟。 |
|
||||
| **警报解除复位事件**<br>`ALARM_CLEAR_EVENT` | **源**:报警状态下侧边或上部任意按键按下。 | **当前状态**:`STATE_ALARMING` 或 `STATE_SOS_EMITTED`。 | 1. **状态**:切回 `STATE_CLOCK`;<br>2. **灯效**:WS2812B 彻底熄灭;<br>3. **马达**:清空马达状态并立即停振;<br>4. **显示**:置 `Redraw = 1`,LCD 重绘走时时钟。 |
|
||||
|
||||
@@ -1,85 +1,124 @@
|
||||
# UI 设计 (Docs/40_ui-design/main.md)
|
||||
|
||||
本章节定义手环 135x240 TFT LCD 屏幕的画面布局、各页面坐标位置、中文字体/ASCII 字符对齐基线以及局部刷新逻辑。
|
||||
本章节定义手环 120x240 Truly AMOLED 屏幕的画面布局、各页面坐标位置、中文字体/ASCII 字符对齐基线以及局部刷新逻辑。
|
||||
针对**特殊人群(如视力障碍者、老年人)**的需求,本界面采取了**大字版与大图标无障碍(Accessibility / A11y)设计系统**。
|
||||
|
||||
## 1. 屏幕物理参数与刷新机制
|
||||
---
|
||||
|
||||
* **屏幕规格**:1.14寸 TFT LCD 屏,物理分辨率 **`135x240`**。
|
||||
* **竖向屏规范**:屏幕窗口配置为 **`135` 像素宽,`240` 像素高**。页面中的时钟、菜单、报警元素均采用竖屏垂直居中排版。
|
||||
* **坐标偏移修正**:TFT LCD 驱动芯片(ST7789V)的显示 RAM 大小为 240x320 像素。在控制 135x240 的竖屏物理面板时,为了将显示窗口完美对齐至显示区域,防止花屏或偏置错误,写屏窗口渲染必须应用 **X 轴偏移量 +52,Y 轴偏移量 +40**。即:`LCD_SetWindow(x1 + 52, x2 + 52, y1 + 40, y2 + 40)`。
|
||||
* **局部刷新防抖机制**:清除重绘标志(`Redraw`)的动作必须在具体的刷新绘制块结束时重置,防止因为主循环高速轮询而产生屏幕闪烁。
|
||||
## 1. 无障碍(A11y)大字设计系统规范
|
||||
|
||||
为确保特殊人群能清晰阅读,且文本在 120 像素宽的屏幕内**不超出边界**,设计遵循以下准则:
|
||||
1. **文本宽度与换行原则**:
|
||||
* 在 120 像素宽的屏幕上,单行 16x32px 大字符最多显示 **7 个字符**。
|
||||
* 如果提示语较长(如 `APPEL EN COURS`),必须将其**缩短或分成多行显示**(如第一行 `APPEL`,第二行 `SOS`)。
|
||||
* 菜单项名称进行合理缩短,如 `1. DATE/HEURE` 缩短为 `1. HORLOGE`,`2. APPAIRAGE` 缩短为 `2. APPAIR.`,以保证在 16x32px 字体下不溢出。
|
||||
2. **最小字号限制**:取消所有 8x16px 或更小的微缩文本。基础信息字号不小于 **16x32px**。
|
||||
3. **核心电量与状态图标放大**:
|
||||
* 为了使用户能清晰看清剩余电量,电池电量数字放大为 **16x32px** 粗体。
|
||||
* 电池图标放大为 **24x12px** 粗边框,放置在状态栏右上角。
|
||||
* 状态锁图标放大为 **32x32px**,放置在状态栏左上角。
|
||||
4. **超大核心数据**:时间数字、设定参数、传感器序号等使用 **32x64px**(超大点阵字模)呈现。
|
||||
5. **大图标辅助**:所有页面均配备 **48x48px 或 64x64px 的超大单色位图图标**,结合高对比度色彩(红/绿/黄/黑),方便用户一眼识别功能。
|
||||
6. **单页单焦点排版**:避免多行数据堆叠。菜单、时间设定、对码等页面在屏幕中**每次只显示当前编辑或选中的一个条目**,把所有的屏幕空间留给最大化的字体和图标。
|
||||
7. **坐标偏移修正**: Truly AMOLED 屏幕写屏窗口渲染必须应用 **X 轴偏移量 +4,Y 轴偏移量 +0**。即:`LCD_SetWindow(x1 + 4, x2 + 4, y1, y2)`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 页面布局与坐标坐标规范
|
||||
|
||||
### 2.1 时钟待机界面 (STATE_NORMAL / STATE_ARMED / STATE_DISARMED)
|
||||
### 2.1 时钟待机界面 (STATE_CLOCK)
|
||||
|
||||
时钟页面作为常态显示,包括状态栏、数字时钟和日期行。
|
||||
|
||||
```
|
||||
+-----------------------------------------+
|
||||
| 🔒 ARME 🔋 85% | <- 状态栏 (Y=24~27)
|
||||
| [🔒 32x32] 🔋 85%+ | <- 状态栏 (Y=15~35) (电池图标与16x32px电量)
|
||||
| |
|
||||
| |
|
||||
| 10:35 | <- 中央时间 (Y=80~128)
|
||||
| 10:35 | <- 居中超大时间 (Y=70~134) (32x64px字模)
|
||||
| |
|
||||
| |
|
||||
| VEN. 07-10 | <- 底部日期 (Y=180)
|
||||
| VEN. 07-10 | <- 底部大日期 (Y=180~212) (16x32px字模)
|
||||
| |
|
||||
+-----------------------------------------+
|
||||
```
|
||||
|
||||
* **状态栏电量显示(极重要)**:
|
||||
* **电池图标** 绘制在 `X=107, Y=27`。
|
||||
* **电量百分比** 绘制在 `X=77, Y=24`。如果处于充电状态,追加 `+` 号后缀显示为 `85%+`,起始绘制点向左平移(如 `X=69`)以确保与电池图标之间依然有安全间距。
|
||||
* 两个控件在 `135` 像素宽的屏幕上保持 **6 像素安全间距**,彻底防范乱码和字符相撞。
|
||||
* **电池图标** 放大绘制在 `X=86, Y=19, W=24, H=13`。
|
||||
* **电量百分比** 采用 `16x32px` 字模,右对齐。充电时显示 `+` 号。
|
||||
* **安防状态显示**:
|
||||
* **布防状态 (ARMED)**:状态栏左侧显示红色闭锁 `🔒` 图标,显示 `ARME`。
|
||||
* **撤防状态 (DISARMED)**:状态栏左侧显示绿色开锁 `🔓` 图标,显示 `DESARME`。
|
||||
* 状态栏左侧绘制 **32x32px** 的超大布撤防锁图标:红色闭锁 `🔒`(布防),绿色开锁 `🔓`(撤防),不再显示小文字,使用户看图即懂。
|
||||
|
||||
### 2.2 传感器配对选择菜单 (STATE_PAIR_MENU)
|
||||
### 2.2 主选择菜单页面 (STATE_MENU)
|
||||
|
||||
* **顶部标题**:显示 `MODE PAIR P-XX`(其中 XX 为当前已配对的传感器数量)。
|
||||
* **列表滚动框**:采用 3 行滚动列表,可在 **7 种传感器类型**(门磁、红外、烟感、紧急、气体、水浸、振动)中上下循环滚动选中。当前行高亮并显示粗体外框,字号放大(如 `DETEC. PORTE`),非当前行暗淡显示。
|
||||
* **按键确认行为**:在配对菜单页面,短按侧边 **■ 确认键** 进入所选防区类型的对码等待状态。
|
||||
|
||||
### 2.3 报警触发与本地 SOS 界面 (STATE_ALARMING / STATE_SOS_EMITTED)
|
||||
|
||||
* **报警提示边框**:全屏闪烁的红色警告虚线/实线边框。
|
||||
* **中央图标**:根据触发的防区传感器类型,居中绘制对应的单色位图图标(32x32px):
|
||||
* 门磁:`🚪` 开门图标。
|
||||
* 红外:`👤` 人体辐射波纹图标。
|
||||
* 烟感:`🔥` 火苗图标。
|
||||
* 紧急按钮:`🆘` 求救图标。
|
||||
* 燃气:`💨` 毒气云雾图标。
|
||||
* 水浸:`💧` 滴水波纹图标。
|
||||
* 振动:`📳` 震动线框图标。
|
||||
* **主动 SOS 界面**:大字显示 `SOS EMIS`,居中显示 `🚨` 旋转警灯图标。
|
||||
* **绑定 IPC 界面 (STATE_BINDING)**:
|
||||
* 顶部标题:`LIAISON IPC` (法语:与 IPC 绑定)。
|
||||
* 中央:正在发送提示,显示 `ENVOI EN COURS`,配对确认锁图标。
|
||||
* **手环 Factory ID 显示**:底部居中显示手环自身出厂地址:`ID: 0xXXXXX`,以便用户配对及辨识。
|
||||
|
||||
### 2.4 对码确认与序号微调界面 (STATE_PAIR_CONFIRM)
|
||||
|
||||
当手环解码到传感器对码信号后,切入此确认页:
|
||||
由时钟待机长按 CONFIRM 键 3 秒进入。显示四个功能条目,供滚动选择:
|
||||
```
|
||||
+-----------------------------------------+
|
||||
✓ RECU (对码成功) (Y=40)
|
||||
|
||||
[ 🚪 ICON ] (Y=80)
|
||||
|
||||
PORTE (Y=135)
|
||||
|
||||
[ 01 ] (Y=165) <- 序号微调框 (可按 ▲/▼ 修改)
|
||||
| - MENU - | <- 标题 (Y=20) (16x32px)
|
||||
| |
|
||||
| [⏰ 48x48] | <- 选中项大图标 (Y=60~108)
|
||||
| |
|
||||
| 1. HORLOGE | <- 选中项大字文本 (Y=150~182) (16x32px)
|
||||
| |
|
||||
| ▲ / ▼ | <- 翻页提示符 (Y=205) (16x32px)
|
||||
+-----------------------------------------+
|
||||
```
|
||||
* **元素定位**:
|
||||
* 顶部显示提示语 `✓ RECU`(法语:已接收),绿字。
|
||||
* 中央显示捕获传感器 32x32 对应位图图标。
|
||||
* 下方第一行展示传感器名称前缀(如 `PORTE`)。
|
||||
* 下方第二行展示序号选框 `[ 01 ]`:其中包含两个外括号,中间的数字即为 `selected_suffix_num`(01~99)。当用户按 ▲ 或 ▼ 键时,中间数字动态增减并实时局部刷新,外括号保持静止,增强可编辑交互感。
|
||||
* **确认行为**:短按 CONFIRM 键或 SOS 键保存退出。
|
||||
* 屏幕中央显示当前选中功能的 **48x48px** 图标,下方以 **16x32px** 粗体显示功能名称。
|
||||
* 用户按 ▲ 或 ▼ 键时,页面以幻灯片形式切换:
|
||||
1. `1. HORLOGE` (对应 ⏰ 时钟图标)
|
||||
2. `2. APPAIR.` (对应 📡 雷达对码图标)
|
||||
3. `3. ALARME` (对应 🔒 防区盾牌图标)
|
||||
4. `4. LIAISON` (对应 📷 摄像头图标)
|
||||
* 短按 CONFIRM 键确认进入当前显示的功能。
|
||||
|
||||
### 2.3 功能设定与子界面设计
|
||||
|
||||
#### 2.3.1 时间日期修改界面 (STATE_SET_TIME)
|
||||
为了避免小字,时间设置每次只微调一个数值:
|
||||
* **页面指示**:顶部大字显示当前修改的字段,例如 `REGLER` (16x32px)。
|
||||
* **中央数值**:正中央显示正在修改的两位数值(如小时 `10`),字号采用 **32x64px** 超大号。数值上下有明显的闪烁三角箭头指示。
|
||||
* **交互**:按 ▲ / ▼ 调整该值。短按 CONFIRM 保存该值并切入下一项(分 $
|
||||
ightarrow$ 秒 $
|
||||
ightarrow$ 年 $
|
||||
ightarrow$ 月 $
|
||||
ightarrow$ 日)。
|
||||
|
||||
#### 2.3.2 传感器对码等待与配对界面 (STATE_PAIR_SEARCH)
|
||||
* **顶部标题**:显示 `APPAIRAGE` (16x32px)。
|
||||
* **中央图案**:绘制占满屏幕中部的雷达搜索大图标(64x64px)并闪烁。
|
||||
|
||||
#### 2.3.3 对码确认与序号微调界面 (STATE_PAIR_CONFIRM)
|
||||
当手环解码到传感器对码信号后,系统自动依据 4-bit 数据码解析出传感器类型,直接切入此确认页进行序号编辑:
|
||||
```
|
||||
+-----------------------------------------+
|
||||
| ✓ RECU | <- 状态提示 (Y=20) (16x32px)
|
||||
| |
|
||||
| [🚪 48x48] | <- 传感器大图标 (Y=55~103)
|
||||
| |
|
||||
| PORTE | <- 类型名称 (Y=120) (16x32px)
|
||||
| |
|
||||
| [ 01 ] | <- 序号微调框 (Y=170~234) (32x64px)
|
||||
+-----------------------------------------+
|
||||
```
|
||||
* **元素布局**:
|
||||
* **传感器图标** 使用 **48x48px** 超大单色位图。
|
||||
* **类型前缀** 使用 **16x32px**。
|
||||
* **数字序号选框** 使用 **32x64px** 超大数字。用户按 ▲/▼ 直接微调序号,CONFIRM 键保存。
|
||||
|
||||
#### 2.3.4 系统布撤防手动选择界面 (STATE_ARM_DISARM_SELECT)
|
||||
* **页面显示**:屏幕正中央显示当前拟设定的状态:
|
||||
* `[ ARME ]`(配 48x48px 盾牌图标)
|
||||
* `[ DESARME ]`(配 48x48px 虚线开锁图标)
|
||||
* 字体全部使用 **16x32px**。按 ▲/▼ 键来回切换,按 CONFIRM 键保存生效。
|
||||
|
||||
#### 2.3.5 IPC 绑定发射界面 (STATE_IPC_BIND)
|
||||
* **图形指示**:正中央显示 **48x48px** 的摄像头绑定大图标,配合动态声波向外发射动画。
|
||||
* **大字提示**:上方显示 `LIAISON` (16x32px),下方显示 `EN COURS` (16x32px)。
|
||||
* **物理地址展示**:底部以 8x16px 显示手环地址 `ID: 0xXXXXX`。
|
||||
* **退出/返回**:长按 CONFIRM 键 3 秒 或 长按 ▼ 键 2 秒主动退出。
|
||||
|
||||
### 2.4 报警触发与本地 SOS 界面 (STATE_ALARMING / STATE_SOS_EMITTED)
|
||||
|
||||
手环发生报警时的显示要具有极强的视觉冲击力:
|
||||
* **警告框**:全屏外围红绿交替闪烁的 4 像素宽粗线警告框。
|
||||
* **中央图标**:根据传感器类型,居中绘制对应的 **64x64px** 的超大单色位图图标(如巨大的火苗 `🔥`、门锁 `🚪`)。
|
||||
@@ -87,6 +126,6 @@
|
||||
|
||||
---
|
||||
|
||||
* 对于标准 8px 宽字符:X 轴绘制起点为 `(135 - len * 8) / 2`。
|
||||
* 对于双倍放大 16px 宽时钟字符:X 轴绘制起点为 `(135 - len * 16) / 2`。
|
||||
## 3. 文字居中对齐与字模基线规范
|
||||
|
||||
为保证排版美观,[Drivers/lcd_font.h](file:///c:/workfile/105/stc32g12k128/Drivers/lcd_font.h) 内的标准字模点阵需要满足如下基线对齐:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Wristband LCD UI Gallery</title>
|
||||
<title>手环 AMOLED 屏幕无障碍大字版 UI 效果图画册 (A11y V3.4)</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
@@ -27,7 +27,16 @@
|
||||
text-align: center;
|
||||
color: #94A3B8;
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 50px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 1.4rem;
|
||||
color: #FFB74D;
|
||||
border-left: 4px solid #FFB74D;
|
||||
padding-left: 12px;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
@@ -54,7 +63,7 @@
|
||||
.card-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: bold;
|
||||
color: #FFB74D;
|
||||
color: #FFFFFF;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.card-desc {
|
||||
@@ -70,7 +79,7 @@
|
||||
/* Realistic Smartwatch CSS Simulator */
|
||||
.watch-device {
|
||||
position: relative;
|
||||
width: 175px;
|
||||
width: 160px;
|
||||
height: 280px;
|
||||
background: linear-gradient(135deg, #2D3748 0%, #1A202C 100%);
|
||||
border-radius: 35px;
|
||||
@@ -105,7 +114,7 @@
|
||||
}
|
||||
.screen-bezel {
|
||||
position: relative;
|
||||
width: 145px;
|
||||
width: 130px;
|
||||
height: 250px;
|
||||
background-color: #000000;
|
||||
border-radius: 25px;
|
||||
@@ -118,7 +127,7 @@
|
||||
|
||||
/* Inlined SVG Scaling */
|
||||
.screen-bezel svg {
|
||||
width: 135px;
|
||||
width: 120px;
|
||||
height: 240px;
|
||||
display: block;
|
||||
}
|
||||
@@ -149,294 +158,476 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>手环 LCD 屏幕 UI 效果图画册 (V2.0)</h1>
|
||||
<div class="subtitle">所有 10 类显示界面在手环硬件上的 1:1 视觉仿真效果及按键映射说明</div>
|
||||
<h1>手环 AMOLED 无障碍大字版 UI 效果图画册 (A11y V3.4)</h1>
|
||||
<div class="subtitle">针对特殊人群优化的大字体、大图标单页集中展示界面效果及按键交互说明(共 15 类全套界面)</div>
|
||||
|
||||
<!-- ==================== PART 1 ==================== -->
|
||||
<div class="section-title">第一部分:系统常态待机界面 (STATE_CLOCK)</div>
|
||||
<div class="grid">
|
||||
<!-- 1. Normal Clock -->
|
||||
<div class="card">
|
||||
<div class="card-title">1. 待机时钟界面</div>
|
||||
<div class="card-desc">常规待机状态,顶部仅显示电量,界面宽裕</div>
|
||||
<div class="card-title">1. 待机时钟 (撤防 DESARME)</div>
|
||||
<div class="card-desc">正常走时,电量百分比大字显示,左侧带大解锁图标 🔓</div>
|
||||
<div class="watch-device">
|
||||
<div class="screen-bezel">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<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="107" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
|
||||
<rect x="109" y="29" width="13" height="6" rx="1" fill="#10B981"/>
|
||||
<rect x="128" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
|
||||
<text x="101" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
|
||||
<!-- Status Bar (Left: Big Unlock, Right: Battery 16x32px text + battery icon) -->
|
||||
<!-- 🔓 Unlock Icon (32x32px style) -->
|
||||
<g transform="translate(10, 15)">
|
||||
<rect x="0" y="8" width="20" height="15" rx="3" fill="none" stroke="#10B981" stroke-width="2"/>
|
||||
<path d="M 5 8 L 5 4 C 5 2, 12 2, 15 4 L 15 10" fill="none" stroke="#10B981" stroke-width="2" stroke-linecap="round"/>
|
||||
</g>
|
||||
<!-- Large Battery info and Large Battery Icon -->
|
||||
<text x="82" y="32" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="end">85%</text>
|
||||
<rect x="86" y="19" width="24" height="13" rx="2" fill="none" stroke="#FFFFFF" stroke-width="1.8"/>
|
||||
<rect x="89" y="22" width="15" height="7" rx="0.5" fill="#10B981"/>
|
||||
<rect x="110" y="23" width="1.5" height="5" rx="0.5" fill="#FFFFFF"/>
|
||||
|
||||
<!-- Time -->
|
||||
<text x="67.5" y="115" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="24" font-weight="bold" text-anchor="middle">10:35</text>
|
||||
<!-- Central Big Time (32x64px equivalent in SVG) -->
|
||||
<text x="60" y="115" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="34" font-weight="bold" text-anchor="middle">10:35</text>
|
||||
|
||||
<!-- Date -->
|
||||
<text x="67.5" y="165" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">THU 07-02</text>
|
||||
<!-- Bottom Large Date (16x32px equivalent) -->
|
||||
<text x="60" y="195" fill="#94A3B8" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">VEN. 07-10</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
长按 ▲ 键 3 秒进入配对菜单;双击 ▲+▼ 组合键切换布防;长按 SOS 键 5 秒触发【本机求救】。
|
||||
长按 ■ 确认键 3 秒进入主选择菜单;短按或长按 SOS 键均直接触发【本地主动报警】。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. Armed Clock -->
|
||||
<div class="card">
|
||||
<div class="card-title">2. 系统布防时钟</div>
|
||||
<div class="card-desc">布防锁定 🔒 移至正下方,完美避免电池重叠</div>
|
||||
<div class="card-title">2. 系统待机时钟 (布防 ARME)</div>
|
||||
<div class="card-desc">正常走时,电量百分比大字显示,左侧带大红色锁图标 🔒</div>
|
||||
<div class="watch-device">
|
||||
<div class="screen-bezel">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<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="107" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
|
||||
<rect x="109" y="29" width="13" height="6" rx="1" fill="#10B981"/>
|
||||
<rect x="128" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
|
||||
<text x="101" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%+</text>
|
||||
|
||||
<!-- Time -->
|
||||
<text x="67.5" 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="67.5" 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(46, 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"/>
|
||||
<text x="18" y="10" fill="#EF4444" font-family="system-ui, sans-serif" font-size="9" font-weight="bold" text-anchor="start">ARME</text>
|
||||
<!-- Status Bar (Left: Big Lock 32x32px, Right: Battery with + charging indicator) -->
|
||||
<!-- 🔒 Lock Icon -->
|
||||
<g transform="translate(10, 15)">
|
||||
<rect x="0" y="8" width="20" height="15" rx="3" fill="none" stroke="#EF4444" stroke-width="2"/>
|
||||
<path d="M 5 8 L 5 3 C 5 1, 15 1, 15 3 L 15 8" fill="none" stroke="#EF4444" stroke-width="2" stroke-linecap="round"/>
|
||||
</g>
|
||||
<!-- Large Battery info & Icon -->
|
||||
<text x="82" y="32" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="end">85%+</text>
|
||||
<rect x="86" y="19" width="24" height="13" rx="2" fill="none" stroke="#FFFFFF" stroke-width="1.8"/>
|
||||
<rect x="89" y="22" width="15" height="7" rx="0.5" fill="#10B981"/>
|
||||
<rect x="110" y="23" width="1.5" height="5" rx="0.5" fill="#FFFFFF"/>
|
||||
|
||||
<!-- Central Big Time -->
|
||||
<text x="60" y="115" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="34" font-weight="bold" text-anchor="middle">10:35</text>
|
||||
|
||||
<!-- Bottom Large Date -->
|
||||
<text x="60" y="195" fill="#94A3B8" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">VEN. 07-10</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
双击 ▲+▼ 组合键本地切换为撤防状态;长按 SOS 键 5 秒触发【本机求救】。
|
||||
长按 ■ 确认键 3 秒进入主选择菜单;短按或长按 SOS 键均直接触发【本地主动报警】。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. Disarmed Clock -->
|
||||
<!-- ==================== PART 2 ==================== -->
|
||||
<div class="section-title">第二部分:系统主选择菜单界面 (STATE_MENU)</div>
|
||||
<div class="grid">
|
||||
<!-- 3. Main Menu - Date/Time -->
|
||||
<div class="card">
|
||||
<div class="card-title">3. 系统撤防时钟</div>
|
||||
<div class="card-desc">撤防解锁 🔓 移至正下方,界面均衡清爽</div>
|
||||
<div class="card-title">3. 主菜单: 1.时间修改</div>
|
||||
<div class="card-desc">菜单项 1:大时钟图标配合超大功能项文字</div>
|
||||
<div class="watch-device">
|
||||
<div class="screen-bezel">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<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="#94A3B8" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">- MENU -</text>
|
||||
|
||||
<!-- Status Bar (Right: Battery Icon) -->
|
||||
<rect x="107" y="27" width="20" height="10" rx="2" fill="none" stroke="#64748B" stroke-width="1.2"/>
|
||||
<rect x="109" y="29" width="13" height="6" rx="1" fill="#10B981"/>
|
||||
<rect x="128" y="30" width="1.5" height="4" rx="0.5" fill="#64748B"/>
|
||||
<text x="101" y="36" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="end">85%</text>
|
||||
|
||||
<!-- Time -->
|
||||
<text x="67.5" 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="67.5" 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(34, 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"/>
|
||||
<text x="18" y="10" fill="#10B981" font-family="system-ui, sans-serif" font-size="9" font-weight="bold" text-anchor="start">DESARME</text>
|
||||
</g>
|
||||
</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="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<text x="67.5" 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="67.5" 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="115" height="30" rx="6" fill="none" stroke="#00E5FF" stroke-width="1.5"/>
|
||||
<text x="67.5" y="124" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="10" font-weight="bold" text-anchor="middle">👤 PIR MOTION</text>
|
||||
<text x="67.5" 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="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<g transform="translate(0, 10)">
|
||||
<path d="M 60 70 L 67.5 90 M 59.5 75 A 10 10 0 0 1 75.5 75 M 55.5 70 A 15 15 0 0 1 79.5 70 M 51.5 65 A 20 20 0 0 1 83.5 65" stroke="#00E5FF" stroke-width="2" fill="none" stroke-linecap="round"/>
|
||||
<circle cx="67.5" cy="92" r="2" fill="#00E5FF"/>
|
||||
</g>
|
||||
<text x="67.5" y="145" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">SEARCHING...</text>
|
||||
<text x="67.5" 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="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<text x="67.5" y="45" fill="#10B981" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">v RECU</text>
|
||||
|
||||
<!-- 门磁图标 -->
|
||||
<g transform="translate(54.5, 70)">
|
||||
<rect x="0" y="2" width="16" height="28" rx="2" fill="none" stroke="#FFFFFF" stroke-width="1.8"/>
|
||||
<rect x="20" y="6" width="6" height="20" rx="1" fill="none" stroke="#10B981" stroke-width="1.8"/>
|
||||
<circle cx="4" cy="16" r="1.5" fill="#FFFFFF"/>
|
||||
<!-- ⏰ 48x48px Clock Icon -->
|
||||
<g transform="translate(36, 65)">
|
||||
<circle cx="24" cy="24" r="20" stroke="#00E5FF" stroke-width="3" fill="none"/>
|
||||
<path d="M 24 10 L 24 24 L 34 24" stroke="#00E5FF" stroke-width="3" stroke-linecap="round" fill="none"/>
|
||||
<path d="M 8 6 L 16 2 M 40 6 L 32 2" stroke="#00E5FF" stroke-width="3.5" stroke-linecap="round"/>
|
||||
</g>
|
||||
|
||||
<text x="67.5" y="140" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">PORTE</text>
|
||||
|
||||
<!-- 序号选框 [ 01 ] -->
|
||||
<rect x="37.5" y="160" width="60" height="22" rx="4" fill="none" stroke="#00E5FF" stroke-width="1.5"/>
|
||||
<text x="67.5" y="176" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">01</text>
|
||||
|
||||
<text x="67.5" y="215" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">ADDR: 0x37A86</text>
|
||||
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">1. HORLOGE</text>
|
||||
<text x="60" y="210" fill="#64748B" font-family="system-ui, sans-serif" font-size="14" text-anchor="middle">^ v</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
短按 ▲ 自增,▼ 自减序号(01~99);短按 CONFIRM 键或 SOS 键保存退出。
|
||||
按 ▲/▼ 键翻看菜单选项;短按 ■ 确认进入;长按 ■ 3秒返回时钟。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 7. Pair Saved -->
|
||||
<!-- 4. Main Menu - Pairing -->
|
||||
<div class="card">
|
||||
<div class="card-title">7. 对码保存成功</div>
|
||||
<div class="card-desc">高保真圆形对勾绿色成功徽章 (✓)</div>
|
||||
<div class="card-title">4. 主菜单: 2.传感器配对</div>
|
||||
<div class="card-desc">菜单项 2:大雷达对码图标与对码文本</div>
|
||||
<div class="watch-device">
|
||||
<div class="screen-bezel">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<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="#94A3B8" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">- MENU -</text>
|
||||
|
||||
<!-- 📡 48x48px Radar Icon -->
|
||||
<g transform="translate(36, 65)">
|
||||
<path d="M 24 38 A 12 12 0 0 1 36 28 M 24 38 A 18 18 0 0 1 42 22 M 24 38 A 24 24 0 0 1 48 16" stroke="#00E5FF" stroke-width="3" fill="none" stroke-linecap="round"/>
|
||||
<circle cx="24" cy="38" r="4" fill="#00E5FF"/>
|
||||
<line x1="24" y1="38" x2="6" y2="44" stroke="#00E5FF" stroke-width="2.5"/>
|
||||
</g>
|
||||
|
||||
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">2. APPAIR.</text>
|
||||
<text x="60" y="210" fill="#64748B" font-family="system-ui, sans-serif" font-size="14" text-anchor="middle">^ v</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
按 ▲/▼ 键翻看菜单选项;短按 ■ 确认进入对码搜索;长按 ■ 3秒返回时钟。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 5. Main Menu - Arm/Disarm -->
|
||||
<div class="card">
|
||||
<div class="card-title">5. 主菜单: 3.手动布撤防</div>
|
||||
<div class="card-desc">菜单项 3:大盾牌防区图标与大字指示</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="#94A3B8" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">- MENU -</text>
|
||||
|
||||
<!-- 🛡️ Shield / Security Icon (48x48px) representing ALARME menu item -->
|
||||
<g transform="translate(36, 65)">
|
||||
<path d="M 24 4 C 12 4, 6 12, 6 12 C 6 28, 24 44, 24 44 C 24 44, 42 28, 42 12 C 42 12, 36 4, 24 4 Z" stroke="#00E5FF" stroke-width="3.5" fill="none" stroke-linejoin="round"/>
|
||||
<path d="M 24 12 L 24 34" stroke="#00E5FF" stroke-width="3"/>
|
||||
</g>
|
||||
|
||||
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">3. ALARME</text>
|
||||
<text x="60" y="210" fill="#64748B" font-family="system-ui, sans-serif" font-size="14" text-anchor="middle">^ v</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
按 ▲/▼ 键翻看菜单选项;短按 ■ 确认进入手动布撤防页;长按 ■ 3秒返回时钟。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 6. Main Menu - Liaison -->
|
||||
<div class="card">
|
||||
<div class="card-title">6. 主菜单: 4.摄像头绑定</div>
|
||||
<div class="card-desc">菜单项 4:大摄像头图标与绑定文本</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="#94A3B8" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">- MENU -</text>
|
||||
|
||||
<!-- 📷 Camera Icon (48x48px) representing LIAISON menu item -->
|
||||
<g transform="translate(36, 65)">
|
||||
<rect x="4" y="14" width="30" height="24" rx="3" fill="none" stroke="#00E5FF" stroke-width="3"/>
|
||||
<circle cx="19" cy="26" r="6" stroke="#00E5FF" stroke-width="2.5" fill="none"/>
|
||||
<path d="M 34 20 L 44 14 L 44 38 L 34 32 Z" fill="#00E5FF"/>
|
||||
</g>
|
||||
|
||||
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">4. LIAISON</text>
|
||||
<text x="60" y="210" fill="#64748B" font-family="system-ui, sans-serif" font-size="14" text-anchor="middle">^ v</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
按 ▲/▼ 键翻看菜单选项;短按 ■ 确认进入摄像头绑定对码页;长按 ■ 3秒返回时钟。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PART 3 ==================== -->
|
||||
<div class="section-title">第三部分:子设置流程 1 - 时间设定 (STATE_SET_TIME)</div>
|
||||
<div class="grid">
|
||||
<!-- 7. Single Value Time Edit -->
|
||||
<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"/>
|
||||
<text x="60" y="35" fill="#94A3B8" font-family="system-ui, sans-serif" font-size="14" font-weight="bold" text-anchor="middle">REGLER</text>
|
||||
|
||||
<!-- Up Arrow -->
|
||||
<path d="M 60 62 L 52 72 L 68 72 Z" fill="#00E5FF"/>
|
||||
|
||||
<!-- Huge 32x64px hour value -->
|
||||
<text x="60" y="132" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="44" font-weight="bold" text-anchor="middle">10</text>
|
||||
|
||||
<!-- Down Arrow -->
|
||||
<path d="M 60 157 L 52 147 L 68 147 Z" fill="#00E5FF"/>
|
||||
|
||||
<text x="60" y="200" fill="#64748B" font-family="system-ui, sans-serif" font-size="14" font-weight="bold" text-anchor="middle">VALIDER</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
按 ▲ 增加数值,▼ 减少数值;短按 ■ 确认保存并切入分秒年等微调;长按 ■ 3s 放弃退出。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PART 4 ==================== -->
|
||||
<div class="section-title">第四部分:子设置流程 2 - 传感器配对 (STATE_PAIR)</div>
|
||||
<div class="grid">
|
||||
<!-- 8. Pairing Search -->
|
||||
<div class="card">
|
||||
<div class="card-title">8. 雷达对码搜索</div>
|
||||
<div class="card-desc">64x64px 超大雷达闪烁动画,等待对码信号</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="#94A3B8" font-family="system-ui, sans-serif" font-size="14" font-weight="bold" text-anchor="middle">APPAIRAGE</text>
|
||||
|
||||
<!-- 64x64px Big Radar -->
|
||||
<g transform="translate(28, 65)">
|
||||
<path d="M 32 50 C 32 30, 48 10, 60 10 M 32 50 C 32 35, 42 20, 52 20 M 32 50 C 32 40, 36 30, 44 30" stroke="#00E5FF" stroke-width="3" fill="none" stroke-linecap="round"/>
|
||||
<circle cx="32" cy="50" r="5" fill="#00E5FF"/>
|
||||
<line x1="32" y1="50" x2="8" y2="58" stroke="#00E5FF" stroke-width="3"/>
|
||||
</g>
|
||||
|
||||
<text x="60" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="14" font-weight="bold" text-anchor="middle">RECHERCHE</text>
|
||||
<text x="60" y="200" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="13" font-weight="bold" text-anchor="middle">ACTIVER DET.</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
触发物理传感器。捕获数据后手环将<b>自动以数据码识别类型并跳转确认页</b>。长按 ▼ 2 秒退出。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 9. Pairing Confirm -->
|
||||
<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"/>
|
||||
<text x="60" y="32" fill="#10B981" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">✓ RECU</text>
|
||||
|
||||
<!-- 48x48px Big Door Icon -->
|
||||
<g transform="translate(36, 45)">
|
||||
<rect x="2" y="2" width="24" height="42" rx="3" fill="none" stroke="#FFFFFF" stroke-width="2.5"/>
|
||||
<rect x="30" y="8" width="10" height="30" rx="1.5" fill="none" stroke="#10B981" stroke-width="2.5"/>
|
||||
<circle cx="8" cy="24" r="2.5" fill="#FFFFFF"/>
|
||||
</g>
|
||||
|
||||
<!-- Only-read sensor type name (16x32px equivalent) -->
|
||||
<text x="60" y="130" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">PORTE</text>
|
||||
|
||||
<!-- 32x64px Suffix Edit Box [ 01 ] -->
|
||||
<rect x="15" y="152" width="90" height="44" rx="6" fill="none" stroke="#00E5FF" stroke-width="2"/>
|
||||
<text x="60" y="186" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="34" font-weight="bold" text-anchor="middle">01</text>
|
||||
|
||||
<text x="60" y="225" fill="#64748B" font-family="system-ui, sans-serif" font-size="13" font-weight="bold" text-anchor="middle">CONFIRMER</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
按 ▲ 键自增,▼ 键自减微调序号(01~99);短按 ■ 确认键保存;长按 ■ 3秒放弃。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 10. Pair Success -->
|
||||
<div class="card">
|
||||
<div class="card-title">10. 对码保存成功</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="67.5" cy="90" r="24" stroke="#10B981" stroke-width="2.5" fill="none"/>
|
||||
<path d="M 55.5 90 L 63.5 98 L 79.5 82" stroke="#10B981" stroke-width="3.5" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<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="67.5" y="145" fill="#10B981" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">PAIR SUCCESS</text>
|
||||
<text x="67.5" y="175" fill="#64748B" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">ADDR: 0x37A86</text>
|
||||
<text x="60" y="150" fill="#10B981" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">REUSSITE</text>
|
||||
<text x="60" y="185" fill="#94A3B8" font-family="system-ui, sans-serif" font-size="13" font-weight="bold" text-anchor="middle">ENREGISTRE</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
纯状态提示,自动显示 2 秒后回退到待机,无需任何按键操作。
|
||||
显示 2 秒后自动退回到主时钟待机状态,无须任何按键。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 8. Pair Fail -->
|
||||
<!-- 11. Pair Failed -->
|
||||
<div class="card">
|
||||
<div class="card-title">8. 对码匹配失败</div>
|
||||
<div class="card-desc">高保真圆形红叉失败徽章 (❌)</div>
|
||||
<div class="card-title">11. 对码绑定失败</div>
|
||||
<div class="card-desc">无障碍大字版:红叉圈,提示重新激活对码</div>
|
||||
<div class="watch-device">
|
||||
<div class="screen-bezel">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<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="67.5" cy="90" r="24" stroke="#EF4444" stroke-width="2.5" fill="none"/>
|
||||
<path d="M 57.5 80 L 77.5 100 M 77.5 80 L 57.5 100" stroke="#EF4444" stroke-width="3.5" fill="none" stroke-linecap="round"/>
|
||||
<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="67.5" y="155" fill="#EF4444" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">PAIR FAILED</text>
|
||||
<text x="67.5" y="180" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">TYPE MISMATCH</text>
|
||||
<text x="60" y="150" fill="#EF4444" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">ECHEC</text>
|
||||
<text x="60" y="185" fill="#94A3B8" font-family="system-ui, sans-serif" font-size="12" font-weight="bold" text-anchor="middle">DEJA ASSOC.</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
自动显示 5 秒后回退到配对菜单,或短按任意键立即回退到配对菜单。
|
||||
自动显示 5 秒后回退到配对菜单,或短按任意键立即回退。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PART 5 ==================== -->
|
||||
<div class="section-title">第五部分:子设置流程 3 - 手动布撤防 (STATE_ARM_DISARM_SELECT)</div>
|
||||
<div class="grid">
|
||||
<!-- 12. Arm/Disarm Setting Select -->
|
||||
<div class="card">
|
||||
<div class="card-title">12. 手动布撤防设定</div>
|
||||
<div class="card-desc">48x48px 锁/防区图标,无障碍大字状态指示</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="#94A3B8" font-family="system-ui, sans-serif" font-size="14" font-weight="bold" text-anchor="middle">REG. ALARME</text>
|
||||
|
||||
<!-- 48x48px Big Lock Icon representing ARME selection -->
|
||||
<g transform="translate(36, 65)">
|
||||
<rect x="6" y="16" width="36" height="26" rx="4" fill="none" stroke="#EF4444" stroke-width="3"/>
|
||||
<path d="M 12 16 L 12 10 C 12 5, 36 5, 36 10 L 36 16" fill="none" stroke="#EF4444" stroke-width="3" stroke-linecap="round"/>
|
||||
<circle cx="24" cy="28" r="3.5" fill="#EF4444"/>
|
||||
</g>
|
||||
|
||||
<!-- Large active state option in brackets -->
|
||||
<text x="60" y="165" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">[ ARME ]</text>
|
||||
<text x="60" y="210" fill="#64748B" font-family="system-ui, sans-serif" font-size="14" text-anchor="middle">^ v</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
按 ▲/▼ 键来回切换 `[ ARME ]` 和 `[ DESARME ]`;短按 ■ 确认保存退出;长按 ■ 3s 放弃退出。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PART 6 ==================== -->
|
||||
<div class="section-title">第六部分:子设置流程 4 - IPC摄像头绑定 (STATE_IPC_BIND)</div>
|
||||
<div class="grid">
|
||||
<!-- 13. IPC Binding -->
|
||||
<div class="card">
|
||||
<div class="card-title">13. IPC 绑定发送</div>
|
||||
<div class="card-desc">48x48px 摄像头图标,大字发送与 ID 指示</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"/>
|
||||
|
||||
<!-- 48x48px Camera Icon -->
|
||||
<g transform="translate(36, 40)">
|
||||
<rect x="2" y="10" width="32" height="26" rx="4" fill="none" stroke="#00E5FF" stroke-width="3"/>
|
||||
<circle cx="18" cy="23" r="6" stroke="#00E5FF" stroke-width="2.5" fill="none"/>
|
||||
<path d="M 34 16 L 44 10 L 44 36 L 34 30 Z" fill="#00E5FF"/>
|
||||
</g>
|
||||
|
||||
<text x="60" y="130" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">LIAISON</text>
|
||||
<text x="60" y="165" fill="#00E5FF" font-family="system-ui, sans-serif" font-size="15" font-weight="bold" text-anchor="middle">EN COURS</text>
|
||||
|
||||
<text x="60" y="215" fill="#64748B" font-family="system-ui, sans-serif" font-size="9" text-anchor="middle">ID: 0x3F882</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
连发对码信号。长按 ■ 键 3 秒 或 长按 ▼ 键 2 秒可立刻退出返回时钟。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PART 7 ==================== -->
|
||||
<div class="section-title">第七部分:紧急警报触发状态 (STATE_ALARMING / STATE_SOS_EMITTED)</div>
|
||||
<div class="grid">
|
||||
<!-- 14. Alarm Received -->
|
||||
<div class="card">
|
||||
<div class="card-title">14. 收到防区报警 (PORTE)</div>
|
||||
<div class="card-desc">全屏闪烁粗红警告框 + 64x64px 报警传感器大图标</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"/>
|
||||
<!-- 4px Flashing Red Border -->
|
||||
<rect x="4" y="4" width="112" height="232" rx="20" stroke="#EF4444" stroke-width="4.5" fill="none"/>
|
||||
|
||||
<!-- 64x64px Huge Door Icon -->
|
||||
<g transform="translate(28, 40)">
|
||||
<rect x="2" y="2" width="32" height="58" rx="4" fill="none" stroke="#EF4444" stroke-width="3.5"/>
|
||||
<rect x="42" y="12" width="14" height="42" rx="2" fill="none" stroke="#EF4444" stroke-width="3"/>
|
||||
<circle cx="10" cy="32" r="3.5" fill="#EF4444"/>
|
||||
</g>
|
||||
|
||||
<!-- 16x32px text warnings -->
|
||||
<text x="60" y="145" fill="#EF4444" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">PORTE 01</text>
|
||||
<text x="60" y="185" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">INTRUSION!</text>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-ops">
|
||||
<b>按键操作:</b>
|
||||
高分贝马达与声光报警启动。短按手环侧边或上部任意键均可瞬间解除报警复位。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 9. Alarm Received -->
|
||||
<!-- 15. Emitted SOS -->
|
||||
<div class="card">
|
||||
<div class="card-title">9. 收到传感器警报</div>
|
||||
<div class="card-desc">门磁/烟感等传感器触发的警报画面</div>
|
||||
<div class="card-title">15. 本机主动求救 SOS</div>
|
||||
<div class="card-desc">巨大警灯,通过换行与字号分配,完全防止溢出</div>
|
||||
<div class="watch-device">
|
||||
<div class="screen-bezel">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<rect x="4" y="4" width="127" height="232" rx="20" stroke="#EF4444" stroke-width="2.5" fill="none" stroke-dasharray="6 4"/>
|
||||
<g transform="translate(0, 10)">
|
||||
<rect x="59.5" y="55" width="16" height="30" rx="1" fill="none" stroke="#EF4444" stroke-width="2.5"/>
|
||||
<circle cx="71.5" cy="70" r="1.5" fill="#EF4444"/>
|
||||
<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="4.5" fill="none"/>
|
||||
|
||||
<!-- Huge 64x64px Rotating Siren Icon -->
|
||||
<g transform="translate(28, 25)">
|
||||
<!-- Rays -->
|
||||
<path d="M 32 10 L 32 18 M 14 16 L 22 22 M 50 16 L 42 22 M 6 32 L 15 34 M 58 32 L 49 34" stroke="#EF4444" stroke-width="3" stroke-linecap="round"/>
|
||||
<!-- Dome -->
|
||||
<path d="M 12 52 C 12 28, 52 28, 52 52 Z" fill="#EF4444" stroke="#EF4444" stroke-width="2"/>
|
||||
<circle cx="32" cy="45" r="7" fill="#FFFFFF"/>
|
||||
<!-- Base -->
|
||||
<rect x="6" y="52" width="52" height="8" rx="2" fill="#64748B"/>
|
||||
</g>
|
||||
<text x="67.5" y="130" fill="#EF4444" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">FRONT DOOR</text>
|
||||
<text x="67.5" y="165" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="10" text-anchor="middle">ZONE 0 | ALARM</text>
|
||||
|
||||
<!-- Split into 2 rows to fit within 120px screen width nicely -->
|
||||
<text x="60" y="125" fill="#EF4444" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">SOS</text>
|
||||
<text x="60" y="152" fill="#EF4444" font-family="system-ui, sans-serif" font-size="16" font-weight="bold" text-anchor="middle">EMIS</text>
|
||||
|
||||
<text x="60" y="195" fill="#FFFFFF" font-family="system-ui, sans-serif" font-size="14" font-weight="bold" text-anchor="middle">APPEL...</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="135" height="240" viewBox="0 0 135 240">
|
||||
<rect width="135" height="240" fill="#000000"/>
|
||||
<rect x="4" y="4" width="127" height="232" rx="20" stroke="#EF4444" stroke-width="2.5" fill="none"/>
|
||||
<rect x="8" y="8" width="119" 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 67.5 48 L 67.5 54 M 52.5 52 L 57.5 57 M 82.5 52 L 77.5 57 M 47.5 65 L 53.5 67 M 87.5 65 L 81.5 67" stroke="#EF4444" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Siren Glass Dome -->
|
||||
<path d="M 53.5 82 C 53.5 64, 81.5 64, 81.5 82 Z" fill="#EF4444" stroke="#EF4444" stroke-width="1.5"/>
|
||||
<!-- Bulb inside -->
|
||||
<circle cx="67.5" cy="77" r="4.5" fill="#FFFFFF"/>
|
||||
<!-- Metallic Base -->
|
||||
<rect x="49.5" y="82" width="36" height="6" rx="1.5" fill="#64748B"/>
|
||||
</g>
|
||||
|
||||
<!-- Centered SOS Alarm Texts safely inside circular active area -->
|
||||
<text x="67.5" y="138" fill="#EF4444" font-family="system-ui, sans-serif" font-size="11" font-weight="bold" text-anchor="middle">🆘 EMIT SOS</text>
|
||||
<text x="67.5" 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 秒解除报警;或接收到主机的远程撤防指令自动解除。
|
||||
连发 SOS 呼救信号。短按或长按任意按键均可停止发射并消除紧急求救。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,47 +1,49 @@
|
||||
# 模块拆分 - 按键扫描与事件判定 (Docs/50_module-breakdown/mod-key.md)
|
||||
# 模块拆分 - 按键输入消抖与判定 (Docs/50_module-breakdown/mod-key.md)
|
||||
|
||||
本模块描述按键状态消抖、长按计时判定以及组合按键识别。支持 5 个物理按键到手环事件的映射。
|
||||
本模块描述物理按键输入的检测、电平消抖、长按计时以及多事件防丢处理。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. 在 1ms 定时器中断中建立 10ms 扫描计时周期。
|
||||
2. 对 5 个物理按键进行引脚电平扫描:
|
||||
* 侧边:`KEY_UP` SW1 (▲), `KEY_DOWN` SW2 (▼), `KEY_CONFIRM` (■)
|
||||
* 上部:`KEY_SOS1` (SOS 1), `KEY_SOS2` (SOS 2)
|
||||
3. 实现消抖检测(连续 20ms 检测到电平稳定才认定按键动作)。
|
||||
4. 对上部双 SOS 按键进行逻辑并联处理,保证按下任意一个均能触发求救。
|
||||
5. 对按住不放的行为进行计时累加,判定长按(如长按 SOS 达 5 秒触发对码;长按 ▲+▼ 达 3 秒触发配对模式)。
|
||||
6. 将按键判定结果转换为 `KeyEvent` 并注入按键事件缓冲区 `key_event_buf`。
|
||||
1. 在系统上电时,将按键引脚 `P0.1~P0.5` 配置为**高阻输入且开启内部上拉电阻**(STC32G P0M0/P0M1/P0PU 寄存器配置)。
|
||||
2. 实现每 10ms 一次的硬件消抖滤波(采用 3 次扫描连续一致判定法,滤波时间约 20-30ms)。
|
||||
3. 支持侧边 ▲/▼ 键、确认键 ■,以及上部双并联 SOS 键的独立状态判定。
|
||||
4. 对上部双 SOS 按键进行逻辑并联处理:只要任意一个按键拉低,即视为 SOS 触发。
|
||||
5. **长按计时判定**:
|
||||
* 长按 **确认键 (■)** 达 3 秒(300 个时基单位)触发主菜单切换或子页面放弃退出。
|
||||
* 长按 **▼ 键** 达 2 秒(200 个时基单位)触发报警清除或 IPC 绑定退出。
|
||||
6. **防丢事件缓冲队列 (Ring Buffer)**:
|
||||
* 为了防止高频按键或同时按下时发生丢键,本模块维护一个深度为 4 级的环形事件队列。按键扫描判定出的 `KeyEvent` 压入队列,主循环通过出队机制依次消费。
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据结构定义
|
||||
|
||||
### 按键事件枚举 (KeyEvent)
|
||||
### 2.1 按键事件枚举 (KeyEvent)
|
||||
```c
|
||||
typedef enum {
|
||||
KEY_EVENT_NONE,
|
||||
KEY_UP_SHORT,
|
||||
KEY_UP_LONG,
|
||||
KEY_DOWN_SHORT,
|
||||
KEY_DOWN_LONG,
|
||||
KEY_CONFIRM_CLICK, // ■ 确认键短按
|
||||
KEY_SOS_SHORT, // SOS键短按 (SOS1 或 SOS2)
|
||||
KEY_SOS_LONG, // SOS键长按(5秒) (SOS1 或 SOS2)
|
||||
KEY_COMB_LONG // ▲ + ▼ 组合长按事件
|
||||
KEY_UP_SHORT, // ▲ 键短按
|
||||
KEY_DOWN_SHORT, // ▼ 键短按
|
||||
KEY_DOWN_LONG, // ▼ 键长按 2 秒 (清除报警/退出)
|
||||
KEY_CONFIRM_CLICK, // ■ 确认键短按
|
||||
KEY_CONFIRM_LONG, // ■ 确认键长按 3 秒 (菜单切换)
|
||||
KEY_SOS_ACTIVE // SOS 键触发 (不分长短按,秒级响应)
|
||||
} KeyEvent;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口与函数说明
|
||||
|
||||
* `void Key_Init(void)`:配置 `P0.1~P0.5` 的 `P0M1=0x00`, `P0M0=0x00`(高阻模式),并设置 `P0PU = 0x3E` 使能上拉电阻。
|
||||
* `void Key_Scan_Process(void)`:
|
||||
在 Timer 1 ISR 中每 10ms 调度一次。
|
||||
* 读取 `KEY_UP`, `KEY_DOWN`, `KEY_CONFIRM`, `KEY_SOS1`, `KEY_SOS2` 的 GPIO 逻辑电平。
|
||||
* 计算并联 SOS 状态:`is_sos_pressed = (KEY_SOS1 == 0) || (KEY_SOS2 == 0)`。
|
||||
* 如果发现按键电平状态改变,进行计数消抖。
|
||||
* 如果按住不放,累加计时计数器(`key_up_hold`, `key_down_hold`, `key_confirm_hold`, `key_sos_hold`)。
|
||||
* 检测到 `key_up_hold >= 300` 且 `key_down_hold >= 300` 达 3 秒时,注入 `KEY_COMB_LONG` 事件。
|
||||
* 检测到 `key_sos_hold >= 500` 达 5 秒时,注入 `KEY_SOS_LONG` 事件;若释放时未达 5 秒但大于 20ms,注入 `KEY_SOS_SHORT`。
|
||||
* 检测到确认键释放,注入 `KEY_CONFIRM_CLICK`。
|
||||
* 事件解析完毕后存入 `key_event_buf`。
|
||||
在 Timer 1 10ms 中断分频中调用。
|
||||
* 读取引脚逻辑状态,并利用移位寄存器滤波判定。
|
||||
* 并联 SOS 状态:`sos_pressed = (KEY_SOS1 == 0) || (KEY_SOS2 == 0)`。
|
||||
* 累加各按键的计数器:`key_up_hold`, `key_down_hold`, `key_confirm_hold`, `key_sos_hold`。
|
||||
* 达到长按阈值时将对应事件写入环形队列。
|
||||
* `bit Key_Push_Event(KeyEvent evt)`:将事件压入环形事件队列。若满则丢弃,返回 0。
|
||||
* `KeyEvent Key_Pop_Event(void)`:主循环调用,从事件队列中读取未消费的事件。若空返回 `KEY_EVENT_NONE`。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,36 +1,33 @@
|
||||
# 模块拆分 - LCD 显示与字模驱动 (Docs/50_module-breakdown/mod-lcd.md)
|
||||
# 模块拆分 - AMOLED 显示与无障碍渲染 (Docs/50_module-breakdown/mod-lcd.md)
|
||||
|
||||
本模块管理 1.14寸 TFT LCD 屏幕引脚、电平控制、SPI 传输和界面图文渲染(分辨率为 135x240 像素)。
|
||||
本模块管理 Truly 0.95寸 AMOLED 屏的底层 SPI 通信、窗口控制、以及无障碍(A11y)超大字体和图标的渲染。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. 提供底层的 SPI 单向命令/数据通道。
|
||||
2. 控制 LCD_PWR_CTRL 供电管脚。
|
||||
3. 支持屏幕窗口配置,实现底层清屏与局部像素写入。
|
||||
4. 读取 `lcd_font.h` 库,在指定坐标绘制 8x16 字符与自定义大小位图。
|
||||
5. 实现各业务状态屏幕(135x240 分辨率)画面绘制与文字对齐。
|
||||
1. 管理 RM69310 控制器通信,提供单向 SPI 指令/数据写操作。
|
||||
2. 提供 `SGM_CTRL`(引脚 `P3.4`)控制,配合低功耗模块实现屏幕 PMIC 的上电与彻底断电。
|
||||
3. **物理窗口偏置处理**:Truly 120x240 AMOLED 屏的 GRAM X 轴起始位置有 **+4 像素的偏置**,设置显示窗口时必须进行偏移修正:`LCD_SetWindow(x1 + 4, x2 + 4, y1, y2)`。
|
||||
4. **无障碍大字排版(A11y)渲染**:
|
||||
* 取消任何小于 16x32px 的微缩文本。
|
||||
* 时间显示使用 **32x64px** 超大点阵。
|
||||
* 防区图标使用 **48x48px** 或 **64x64px** 超大单色位图。
|
||||
* 在 120 像素宽的屏幕内,应用水平居中公式:`X_start = (120 - len * char_width) / 2`。
|
||||
5. **单页集中展示逻辑**:控制各菜单页面和子修改页面在屏幕中只显示单焦点,避免多行小字杂乱堆叠。
|
||||
|
||||
## 2. 底层显示接口
|
||||
---
|
||||
|
||||
* `void LCD_Init(void)`:初始化 LCD 引脚,置 `LCD_PWR_CTRL = 1` 使能背光与供电,并发送 **ST7789V** 屏幕控制器的初始化寄存器配置序列。
|
||||
* `void LCD_WriteCmd(u8 cmd)`:拉低 `LCD_RS` 发送 SPI 命令。
|
||||
* `void LCD_WriteData(u8 dat)`:拉高 `LCD_RS` 发送 SPI 数据。
|
||||
* `void LCD_SetWindow(u16 x1, u16 y1, u16 x2, u16 y2)`:设置局部像素绘制范围,以适配 135x240 竖屏在 240x320 GRAM 上的对齐(强制处理 **X 轴偏移量 +52,Y 轴偏移量 +40**)。
|
||||
* `void LCD_Clear(u16 color)`:将整块屏幕刷写为特定背景色。
|
||||
## 2. 接口与函数说明
|
||||
|
||||
## 3. 图文绘制与 UI 渲染
|
||||
|
||||
* `void LCD_ShowChar(u16 x, u16 y, char c, u16 fc, u16 bc)`:在 (x, y) 坐标处绘制 ASCII 字符 `c`。
|
||||
* `void LCD_ShowString(u16 x, u16 y, char *s, u16 fc, u16 bc)`:循环打印字符串。
|
||||
* `void LCD_ShowStringCentered(u16 y, char *str, u16 fc, u16 bc)`:在 135 像素宽屏幕上水平居中绘制 8 像素宽的字符串,水平起始坐标算法为 `(135 - len * 8) / 2`。
|
||||
* `void LCD_ShowString16x32Centered(u16 y, char *str, u16 fc, u16 bc)`:在 135 像素宽屏幕上水平居中绘制双倍大小 (16x32px) 的字符串,水平起始坐标算法为 `(135 - len * 16) / 2`。
|
||||
* `void LCD_ShowImage(u16 x, u16 y, u16 w, u16 h, const u8 *img, u16 fc, u16 bc)`:在指定区域绘制单色位图。
|
||||
* `void UI_ShowClockPage(SystemState state, u8 hour, u8 min)`:渲染时钟待机页面(135 宽布局),并根据布撤防状态在状态栏绘制相应锁状态图标。
|
||||
* `void UI_ShowAlarmPage(char *sensor_name, u8 zone)`:渲染防区告警页面,显示对应的传感器位图和法语名称。
|
||||
* `void UI_ShowPairMenuPage(u8 selected_index)`:渲染对码选择菜单。
|
||||
* `void UI_ShowPairConfirmPage(u8 type, u8 selected_suffix)`:渲染对码确认页,显示捕获的类型图标、名字前缀及带选框的 `[ selected_suffix ]` 数字序号(支持按键调整)。
|
||||
* `void UI_ShowBindingPage(void)`:渲染与 IPC 绑定对码界面,并在屏幕底部居中显示手环自身的唯一 `Factory ID`。
|
||||
|
||||
<!-- Checked and verified with always-on screen and sleep removal changes -->
|
||||
* `void LCD_Init(void)`:配置 `P1.1~P1.6` 控制线为推挽输出模式,并在拉高 `SGM_CTRL` 稳定后,发送 RM69310 初始化寄存器指令序列。
|
||||
* `void LCD_WriteCmd(u8 cmd)`:拉低 `LCD_RS` 选择命令寄存器,通过 SPI 发送字节。
|
||||
* `void LCD_WriteData(u8 dat)`:拉高 `LCD_RS` 选择数据寄存器,通过 SPI 发送字节。
|
||||
* `void LCD_SetWindow(u16 x1, u16 y1, u16 x2, u16 y2)`:设置局部像素刷写范围,物理 X 坐标必须强制加 4 像素。
|
||||
* `void LCD_Clear(u16 color)`:清屏为指定底色(常态使用全黑以节省功耗)。
|
||||
* `void LCD_ShowChar16x32(u16 x, u16 y, char c, u16 fc, u16 bc)`:在指定坐标绘制标准无障碍大字符(16x32点阵)。
|
||||
* `void LCD_ShowChar32x64(u16 x, u16 y, char c, u16 fc, u16 bc)`:在指定坐标绘制超大数字字符(32x64点阵)。
|
||||
* `void LCD_ShowImage(u16 x, u16 y, u16 w, u16 h, const u8 *img, u16 fc, u16 bc)`:渲染指定单色位图(支持 32x32/48x48/64x64/80x80 图标规格)。
|
||||
* `void LCD_ShowStringCentered(u16 y, char *str, u16 fc, u16 bc)`:16x32 规格字符串居中渲染,单行限制最多 7 个字符。
|
||||
* `void LCD_ShowString32x64Centered(u16 y, char *str, u16 fc, u16 bc)`:32x64 规格超大字符串居中渲染(如时钟显示)。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
# 模块拆分 - WS2812B 可编程 RGB 灯效 (Docs/50_module-breakdown/mod-led.md)
|
||||
|
||||
本模块描述可编程幻彩 RGB 灯珠(WS2812B/FCOB-2.7)的单线级联数据流驱动与报警色彩反馈。
|
||||
本模块管理双级联幻彩 RGB 灯珠(WS2812B/FCOB-2.7)的硬件 SPI 通道、防抖抗噪切换以及指示闪烁逻辑。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. 在系统启动时,配置 WS2812 的物理输出引脚 `P2.3` (MOSI)。
|
||||
2. 支持一上一下级联(Daisy-chained)的双 WS2812B/FCOB-2.7 灯珠驱动。上灯的 DOUT 串行连接至下灯的 DIN。
|
||||
3. 提供高速的硬件 SPI 发送驱动,配合 LUT 查表展宽算法,连续发送 48-bit (24-bit × 2) 的 GRB 级联数据流,输出满足单线纳秒级精度的 WS2812 时序波形,使两个灯珠同步亮起相同的颜色。
|
||||
4. 在硬件 SPI 传输 48位灯效数据时,采取临时关闭中断并把复用的 `P2.5` 配置为高阻输入的隔离防噪处理。
|
||||
5. 维护软件定时闪烁状态机,提供报警状态下的指示灯颜色与特定频率闪烁效果。
|
||||
1. 管理物理引脚 `P2.3`(复用硬件 SPI 的 MOSI)作为单线纳秒级高速数据流输出。
|
||||
2. 实现对级联的两个 RGB 灯珠(上灯 DOUT 串接下灯 DIN)输出相同的 24-bit × 2 色彩数据。
|
||||
3. **硬件 SPI 复用防噪隔离处理**:
|
||||
由于单片机引脚紧缺,SPI 引脚与马达控制可能存在轻微高频串扰。在每次发送 48-bit (GRB) 灯光控制字之前,**必须临时关闭全局中断 (EA=0)**,并将马达引脚配置为高阻输入以彻底隔离噪声。发送完成后立即恢复引脚模式并使能全局中断 (EA=1)。
|
||||
4. **软件异步闪烁控制**:
|
||||
在 1ms 中断中自增计时器,控制报警状态下不同防区灯光的异步闪烁(500ms 亮、500ms 灭,或本地 SOS 下的 50ms 红光快速交替爆闪)。
|
||||
|
||||
---
|
||||
|
||||
## 2. LED 报警色彩矩阵
|
||||
|
||||
根据 7 种不同的外部传感器类型及本地主动求救,亮起对应的 LED 灯:
|
||||
根据防区传感器类型及报警动作亮起指示灯:
|
||||
* **门磁/窗磁 (PORTE)**:红色闪烁。
|
||||
* **PIR 人体红外 (PIR)**:橙色闪烁。
|
||||
* **烟雾传感器 (FUMEE)**:绿色闪烁。
|
||||
@@ -21,14 +24,20 @@
|
||||
* **气体泄漏 (GAZ)**:紫色闪烁。
|
||||
* **水浸传感器 (INOND.)**:黄色闪烁。
|
||||
* **振动传感器 (VIBRA.)**:青色闪烁。
|
||||
* **本地主动 SOS**:红色快速交替闪烁。
|
||||
* **本地主动 SOS**:双红灯以 50ms 周期高速交替闪烁。
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口与函数说明
|
||||
|
||||
* `void WS2812_Init(void)`:配置 `P2.3` 引脚为推挽输出模式。
|
||||
* `void WS2812_Write24Bit(u8 g, u8 r, u8 b)`:使用硬件 SPI 方式串行发送 24-bit 颜色数据给级联灯珠。发送前后进行 `P2.5` 引脚高阻/推挽切换屏蔽马达时钟抖动。
|
||||
* `void WS2812_Reset(void)`:发送大于 80us 的低电平复位脉冲使颜色锁存生效。
|
||||
* `void LED_Set_Color(u8 g, u8 r, u8 b)`:立即设置 RGB 灯亮起特定颜色。
|
||||
* `void LED_Flash_Process(void)`:在 1ms 定时器中断中累加,控制报警状态下指示灯的交替闪烁(如 500ms 亮、500ms 灭)。
|
||||
* `void WS2812_Init(void)`:初始化物理引脚 `P2.3` 状态,复用硬件 SPI 通道,配置时钟展宽 LUT 码表。
|
||||
* `void WS2812_WriteRGB(u8 led1_g, u8 led1_r, u8 led1_b, u8 led2_g, u8 led2_r, u8 led2_b)`:
|
||||
1. 临时保存并拉低 `EA = 0`。
|
||||
2. 切换 `P2.5` (MOTOR) 引脚为高阻输入以防共地噪声。
|
||||
3. 通过 SPI 控制寄存器高速连发 48 字节的时序宽展码,驱动两个灯珠亮起对应颜色。
|
||||
4. 发送完毕后发送 >80us 的低电平复位脉冲。
|
||||
5. 恢复马达引脚为推挽输出,并还原 `EA`。
|
||||
* `void LED_Set_Color(u8 g, u8 r, u8 b)`:同步设置双级联灯亮起特定颜色。
|
||||
* `void LED_Flash_Process(void)`:在 1ms 中断中调用,控制指示灯处于交替爆闪或间歇闪烁的状态机更新。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
# 模块拆分 - 振动马达驱动与反馈 (Docs/50_module-breakdown/mod-motor.md)
|
||||
# 模块拆分 - 振动马达异步驱动与反馈 (Docs/50_module-breakdown/mod-motor.md)
|
||||
|
||||
本模块描述手环告警与按键反馈的振动马达驱动逻辑。手环通过控制特定的振动时长与周期,向用户提供直观的物理触觉告警反馈。
|
||||
本模块描述振动马达引脚的开关控制、异步时间片脉冲时序生成以及针对不同防区的特定振动波形。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. 系统初始化时,将马达控制管脚 `P2.5` 配置为推挽输出模式。
|
||||
2. 提供底层的开关控制,使能或禁止马达供电(高电平振动,低电平静止)。
|
||||
3. 在 1ms 中断(Timer 1)中执行异步振动控制时序(Pulse Process),实现不阻塞 CPU 的各种复杂振动波形(如短振、长振、连续多次振动)。
|
||||
4. 根据接收到的 7 类传感器报警类型或本地主动 SOS 呼救状态,自动触发对应的振动模式。
|
||||
1. 系统初始化时配置马达引脚 `P2.5` 为推挽输出模式,默认输出低电平(马达静止)。
|
||||
2. **非阻塞异步脉冲处理**:
|
||||
为防止马达振动时间(几百毫秒)阻塞 CPU 的业务循环与射频解码,本模块将马达动作拆分为多个电平交替状态段。利用 Timer 1 (1ms 中断) 异步扣减阶段计数器,实现不占用 CPU 资源的精细振动波形。
|
||||
3. 配合系统状态机,在按键点击时输出 50ms 极短触觉反馈,在防区入侵报警时根据类型输出对应的振动指征,在本地主动 SOS 状态下输出连续不断的重度警示振动。
|
||||
|
||||
---
|
||||
|
||||
## 2. 振动模式设计 (周期 5 秒)
|
||||
|
||||
* **按键操作反馈**:1 次极短振动 50ms。
|
||||
* **门磁/窗磁 (PORTE)**:1 次短振 300ms。
|
||||
* **PIR 红外 (PIR)**:2 次短振 300ms (间隔 200ms)。
|
||||
* **烟雾传感器 (FUMEE)**:3 次短振 200ms (间隔 150ms)。
|
||||
* **紧急按钮 (URGENCE)**:1 次长振 800ms。
|
||||
* **气体泄漏 (GAZ)**:4 次短振 200ms (间隔 100ms)。
|
||||
* **水浸传感器 (INOND.)**:2 次长振 600ms (间隔 300ms)。
|
||||
* **振动传感器 (VIBRA.)**:连续 3 次短振 150ms (间隔 100ms)。
|
||||
* **本地主动 SOS**:持续性间歇长振(振 1000ms,停 200ms 循环)。
|
||||
* **振动传感器 (VIBRA.)**:连续 3 次极短振动 150ms (间隔 100ms)。
|
||||
* **本地主动 SOS**:持续间歇重度长振(振 1000ms,停 200ms 循环)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口与函数说明
|
||||
|
||||
* `void Motor_Init(void)`:初始化配置引脚 `P2.5` 为推挽输出,默认输出低电平(马达静止)。
|
||||
* `void Motor_Set_State(bit state)`:立即开关马达(直接写入 `P2.5` 引脚)。
|
||||
* `void Motor_Start_Alarm_Pattern(u8 pattern_type)`:传入传感器类型,装载对应的振动计数器和阶段标志,启动异步振动模式。
|
||||
* `void Motor_Pulse_Process(void)`:在 1ms 中断中调用(通常每 10ms 调度一次),更新振动时间计数器,切换各阶段电平以输出指定波形。
|
||||
* `void Motor_Stop(void)`:清空所有计数器并立即关闭马达,用以清除告警。
|
||||
* `void Motor_Init(void)`:配置引脚 `P2.5` 的 `P2M1=0x00`, `P2M0=0x20`(推挽输出),默认输出 `MOTOR = 0`。
|
||||
* `void Motor_Set_State(bit state)`:硬开关控制引脚 `P2.5` 的电平。
|
||||
* `void Motor_Start_Pattern(u8 pattern_type)`:装载对应类型的马达振动计数器,开启异步振动状态机。
|
||||
* `void Motor_Pulse_Process(void)`:
|
||||
在 Timer 1 的 10ms 中断分频中被调用:
|
||||
* 根据装载的波形,扣减当前阶段维持的毫秒数。
|
||||
* 当计数器归零时,切换 `MOTOR` 引脚电平并转入下一个电平维持段。
|
||||
* `void Motor_Stop(void)`:清空所有计数器,拉低 `MOTOR = 0`,强行中止当前振动。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,19 +1,34 @@
|
||||
# 模块拆分 - 电源与供电管理 (Docs/50_module-breakdown/mod-power.md)
|
||||
# 模块拆分 - 极低功耗与电源管理 (Docs/50_module-breakdown/mod-power.md)
|
||||
|
||||
本模块描述手环的电源供电状态。根据系统设计,手环不启用任何关屏低功耗或停机(Power-Down)模式,以保证屏幕时钟常显与全时无线监听。
|
||||
本模块描述手环的低功耗管理、AMOLED 供电 PMIC 控制以及中断睡眠/唤醒时序。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. 系统初始化时使能 LCD 屏幕与背光电源。
|
||||
2. 维持 `LCD_PWR_CTRL` 引脚输出高电平(1),确保屏幕不进入断电休眠。
|
||||
3. 不进行时钟挂起操作,使 CPU 保持在 active 状态以进行实时的 433MHz 射频信号捕获。
|
||||
1. 在系统上电时使能 SGM3833 升压芯片,为 OLED 屏提供稳定的显示电源。
|
||||
2. **低功耗决策判定**:
|
||||
当主系统处于非警报状态,且连续 10 秒(`inactivity_timer >= 1000`)无任何按键或无线包事件时,判定系统进入 `STATE_SLEEP` 极低功耗睡眠。
|
||||
3. **彻底切断 PMIC**:
|
||||
为消除 OLED 的静态负压漏电流,休眠前拉低 `SGM_CTRL = 0`,使 SGM3833 彻底断电。
|
||||
4. **睡眠挂起配置**:
|
||||
使能 `INT2`(外部中断 2,接射频接收引脚)以及 P0 口引脚电平变化中断,然后将 STC32G 写入 `PCON |= 0x02` 进入停机(Power-Down)挂起状态,关闭主高频振荡时钟,全板功耗降至微安级。
|
||||
5. **安全唤醒重初始化时序**:
|
||||
发生按键或无线信号中断时,CPU 瞬间被唤醒。由于升压 PMIC 的输入电容充电及负压稳压需要时间,唤醒后**严禁立即写屏**。必须首先拉高 `SGM_CTRL = 1`,接着**软件强行阻塞延时 50ms**,等电网稳定后,再次完整初始化 RM69310 的寄存器参数,最后恢复待机屏幕重绘。
|
||||
|
||||
## 2. 接口与函数设计
|
||||
---
|
||||
|
||||
* `void Power_Init(void)`:
|
||||
1. 配置 `LCD_PWR_CTRL` 引脚为推挽输出模式。
|
||||
2. 设置 `LCD_PWR_CTRL = 1`(物理引脚 `P3.4`)开启 LCD 屏幕与背光供电。
|
||||
* `void Enter_Deep_Sleep(void)`:已作废。手环永不进入此函数,保持主循环及射频实时解调。
|
||||
## 2. 接口与函数说明
|
||||
|
||||
<!-- Checked and verified with always-on screen and sleep removal changes -->
|
||||
* `void Power_Init(void)`:配置 `P3.4` (SGM_CTRL) 为推挽输出,默认输出高电平 `SGM_CTRL = 1`。
|
||||
* `void Enter_Low_Power_Sleep(void)`:
|
||||
1. 向 RM69310 屏幕控制器发送关闭显示命令(寄存器 0x28)。
|
||||
2. 拉低 `SGM_CTRL = 0` 彻底切断 PMIC。
|
||||
3. 配置并使能按键端口中断与 RF 中断。
|
||||
4. 执行 `PCON |= 0x02` 挂起 CPU。
|
||||
* `void Wakeup_Restore(void)`:
|
||||
1. 拉高 `SGM_CTRL = 1` 开启 SGM3833 供电。
|
||||
2. 执行 `delay_ms(50)` 阻塞式等待电平平稳,过滤冲击电流。
|
||||
3. 调用 `LCD_Init()` 重新对 RM69310 进行整套初始化配置,恢复写屏 GRAM 通道。
|
||||
4. 状态机切回 `STATE_CLOCK` 并置 `Redraw = 1`。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
# 模块拆分 - 自适应 RF 解码与发射 (Docs/50_module-breakdown/mod-rf.md)
|
||||
|
||||
本模块管理射频芯片 GPIO 初始化、433MHz EV1527 解调接收(宽限时序比值算法)与射频打包主动发射。已确认此模块与新的 1.14寸屏幕/5按键物理变更兼容。
|
||||
本模块描述 LR690L 433MHz 射频物理收发的控制、自适应宽限时间比值解码机制以及对码/呼救编码包的发射。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. 初始化射频接收和发射控制引脚。
|
||||
2. 对射频输入引脚进行高低电平时序轮询解码,计算其高低电平比值,实现自适应 EV1527 24位数据解码。
|
||||
3. 在特定系统请求下(例如发送 SOS 呼救或与 IPC 对码绑定),主动通过发射引脚发出 EV1527 编码帧。
|
||||
* **自适应比值解调机制**:
|
||||
不依赖死宽度的微秒延迟。检测同步头低电平(时间在 1500~60000us 之间)与高电平时间(时间在 50~2500us 之间),算出两者的时序比例。
|
||||
* 以 `31` 作为低电平对高电平的时钟倍率基准(高低比值支持在 `15` 到 `48` 倍范围)。
|
||||
* 计算出每 bit 的标准时钟周期 `T = low_time / 31`,根据此动态 `T` 进行后续 24 个数据位(高/低电平宽度)的比值反解。
|
||||
1. 配置射频芯片接收 GPIO 与发射 GPIO 的电平方向。
|
||||
2. **自适应比值解调算法**:
|
||||
EV1527 协议数据速率变化范围较宽。本模块采用自适应宽度比值解调机制:
|
||||
* 捕获到一个低电平维持时间介于 1500us~60000us 之间的脉冲,判定为同步前导头。
|
||||
* 抓取该帧的标准时钟周期基准 `T = low_time / 31`(前导低电平占 31 个时钟周期 T,允许 T 的宽度随环境在宽限范围内自适应计算)。
|
||||
* 连续捕获 24 位宽数据:每个 bit 的电平变化依据其高低电平的宽幅比例(1:3 对应 0,3:1 对应 1)反解出对应的数据位。
|
||||
3. 解析出 24 位载波包:前 20 位为无线探测器的出厂唯一地址码(Address Code),后 4 位为状态数据码(Data Code)。
|
||||
4. **数据包主动发送**:
|
||||
将手环 Factory ID 编码为一帧 EV1527 数据,通过物理发射引脚输出同步头及 24 位调制波形,连发多遍以确保 IPC 接收质量。
|
||||
|
||||
## 2. 接口与函数说明
|
||||
---
|
||||
|
||||
* `void RF_Init(void)`:配置射频芯片引脚方向,初始化控制端口电平。
|
||||
## 2. 业务状态射频数据编码定义
|
||||
|
||||
* **对码绑定发送 (LIAISON IPC)**:
|
||||
* 数据码固定为 **`0x01`** (0001),源地址为手环 20-bit 出厂 Factory ID,周期性连续发射。
|
||||
* **本地主动 SOS 呼救 (SOS EMIS)**:
|
||||
* 数据码固定为 **`0x08`** (1000),源地址为手环 20-bit 出厂 Factory ID,以 2 秒为周期循环向外发射。
|
||||
* **传感器自动识别对码**:
|
||||
* 手环被动接收 433MHz 对码信号。若捕获成功,状态机直接**依据后 4 位数据码的数据值自动判断识别传感器的设备类型**(如门磁为 `0x01`,红外为 `0x02`),直接跳转到对码微调序号页,类型与大图标只读高亮。
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口与函数说明
|
||||
|
||||
* `void RF_Init(void)`:初始化射频物理端口,使能 INT2 (接收脚的沿中断)。
|
||||
* `bit EV1527_Decode(u32 *out_addr, u8 *out_type)`:
|
||||
进行射频接收包解码尝试。
|
||||
* 首先通过计数检测大于 `1500us` 的同步低电平前导信号。
|
||||
* 自适应计算时钟基准 `T`。
|
||||
* 连续接收 24 位宽数据:如果某个数据位的高电平比低电平长,则认为该位为 `1`;反之为 `0`。
|
||||
* 解码成功将 20 位地址存入 `out_addr`,后 4 位数据存入 `out_type` 并返回 `1`;否则返回 `0`。
|
||||
主循环轮询调用。如果捕获到合法同步头且成功解调出 24 位数据流,则输出 `out_addr` 和 `out_type` 并返回 1,否则返回 0。
|
||||
* `void EV1527_Transmit(u32 addr, u8 data_code)`:
|
||||
主动发射一帧数据。生成同步头,并按 `1` 码(高电平 3T, 低电平 1T)或 `0` 码(高电平 1T, 低电平 3T)依次驱动发射引脚电平,持续多帧以确保接收方捕获。
|
||||
* 该函数被手环用作向 IPC 摄像头主动对码绑定(`data_code = 0x01`)。
|
||||
* 该函数也用于手环主动发射 SOS 紧急呼救包(`data_code = 0x08`),此时传入手环自身的出厂固定 ID `bracelet_factory_id`。
|
||||
主动发射数据。连发至少 5 遍,每遍间歇 20ms,产生满足 T 基准的同步码头、`1` 码时序(高 3T 低 1T)和 `0` 码时序(高 1T 低 3T)。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,67 +1,60 @@
|
||||
# 模块拆分 - 系统核心控制与存储 (Docs/50_module-breakdown/mod-sys.md)
|
||||
# 模块拆分 - 系统状态机与 IAP 数据库 (Docs/50_module-breakdown/mod-sys.md)
|
||||
|
||||
本模块定义手环系统的生命周期、时间计数器、定时中断调度器以及断电保存数据库模块。只涉及手环本地代码实现。
|
||||
本模块描述手环的核心生命周期调度器、业务状态机、软件 RTC 时钟,以及持久化防区配置 Flash 扇区读写。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. 驱动系统主状态机运转(`current_state`)。
|
||||
2. 提供 RTC 软时钟维护(`current_hour`, `current_min`, `current_sec`)。
|
||||
3. 利用 Timer 1 产生 1ms 定时器中断,维护毫秒滴答计数器并作为其他外设时效的基础。
|
||||
4. 实现 IAP 读写底层函数,对防区数据库进行存取与读取。
|
||||
5. 读取并管理手环出厂固定唯一的 `bracelet_factory_id`,作为主动射频发送的数据源地址。
|
||||
1. 驱动核心 SystemState 状态迁移,为其他所有外设(显示、指示灯、振动、无线)提供全局状态指示。
|
||||
2. 提供基于软件计数分频的高可靠 RTC 时钟(维护日历:时、分、秒、年、月、日)。
|
||||
3. 利用 Timer 1 产生主 1ms 系统滴答,自增休眠超时计时器 `inactivity_timer`。
|
||||
4. **持久化 IAP 配置数据库管理**:
|
||||
利用 STC32G 内部 Flash 闪存的第 254 扇区(地址:`0xFE0000`)实现数据库的掉电不丢失存储。最大支持 16 个传感器槽位,提供写入、删除、检索和配置防区类别的全套数据库处理接口。
|
||||
5. 管理出厂固定唯一的 `bracelet_factory_id`(通过读取芯片全球唯一硬 UID 进行哈希映射生成,20位有效)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 数据结构定义
|
||||
|
||||
### 2.1 传感器插槽结构体 (Sensor_Slot)
|
||||
### 2.1 传感器槽位信息结构体 (Sensor_Slot)
|
||||
```c
|
||||
typedef struct {
|
||||
u8 is_used; // 0x01:已使用,其它:空闲
|
||||
u8 addr[3]; // 24位 EV1527 对码物理地址
|
||||
u8 type; // 传感器类型 (0~6)
|
||||
u8 zone; // 防区类别 (0: 永久防区, 1: 可撤布防区)
|
||||
char name_gbk[16]; // 法语自定义名字(前缀+两位数序号,如 PORTE 02)
|
||||
u8 is_used; // 0x01: 有效配置槽位,其它: 空闲槽位
|
||||
u8 addr[3]; // 24位对码 EV1527 传感器无线物理地址
|
||||
u8 type; // 传感器类型:0(门磁), 1(红外), 2(烟感), 3(紧急), 4(气体), 5(水浸), 6(振动)
|
||||
u8 zone; // 防区类别:0(永久防区 - 24h), 1(普通可撤布防区)
|
||||
char name_gbk[16]; // 法语防区名称,拼装格式为 "[预设前缀] [微调序号]" (如 PORTE 02)
|
||||
} Sensor_Slot;
|
||||
```
|
||||
|
||||
### 2.2 系统状态枚举 (SystemState)
|
||||
### 2.2 系统核心状态枚举 (SystemState)
|
||||
```c
|
||||
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
|
||||
STATE_CLOCK, // 时钟常态待机(大字走时与电量大图标)
|
||||
STATE_SLEEP, // 彻底关屏断电深度睡眠(主时钟暂停,挂起 CPU)
|
||||
STATE_MENU, // 主选择菜单(单大条目卡片式循环切换)
|
||||
STATE_SET_TIME, // 时间日期微调修改(单大参数显示)
|
||||
STATE_PAIR_SEARCH, // 对码雷达搜寻等待
|
||||
STATE_PAIR_CONFIRM, // 序号微调与保存确认
|
||||
STATE_ARM_DISARM_SELECT, // 系统手动布撤防更改
|
||||
STATE_IPC_BIND, // 对码绑定发射
|
||||
STATE_ALARMING, // 收到传感器警报响应(高频爆闪与间歇振动)
|
||||
STATE_SOS_EMITTED // 本地主动发射 SOS 求救
|
||||
} SystemState;
|
||||
```
|
||||
|
||||
## 3. 模块接口说明
|
||||
---
|
||||
|
||||
### 3.1 定时与时钟函数
|
||||
* `void Timer1_Init(void)`:配置 Timer 1 作为 1ms 中断源,并使能全局中断。
|
||||
* `void Timer1_Isr(void) interrupt 3`:ISR 中断处理,自增时间滴答、维护 LED 闪烁周期、马达振动波形定时,以及维护软件 RTC(自增 `current_sec` 并在满 60 秒时触发主界面分钟刷新)。
|
||||
## 3. 接口与函数说明
|
||||
|
||||
### 3.2 IAP 数据库存储接口
|
||||
* `void Load_Database(void)`:从 Flash 扇区 `0xFE0000` 读取 16 组传感器配置载入内存的 `sensor_list`。
|
||||
* `void Save_Database(void)`:擦除 Flash 扇区并将内存中的 `sensor_list` 写入 Flash。
|
||||
* `void Add_Sensor(u32 addr, u8 type, u8 suffix_idx)`:向 `sensor_list` 添加传感器信息,将其名字拼装为 `[前缀] [suffix_idx]`,并自动调用 `Save_Database()`。
|
||||
* `bit Check_Sensor_ID(u32 addr, u8 *out_slot_index)`:在数据库中检索该地址码,若存在则返回它的槽位索引。
|
||||
|
||||
### 3.3 系统初始化与全局 ID 获取
|
||||
* `void System_Init(void)`:
|
||||
1. 初始化单片机系统寄存器(WTST, EAXFR 等)。
|
||||
2. 读取 STC32G 硬件全球唯一 ID (UID)。
|
||||
3. 提取 UID 中的后 3 字节,并通过 `& 0x0FFFFF` 裁剪为 20 位 EV1527 源地址,赋值给全局变量 `bracelet_factory_id`。如果读取失败,则默认赋予 `0x37A86UL`。
|
||||
4. 载入数据库并配置 Timer1 和外设 GPIO 状态。
|
||||
配置单片机寄存器(使能 FCON,开启扩展 SFR,调整外部 RAM 模式)。读取内置全球唯一 UID 拼装 Factory ID。初始化 Timer 1 开启 1ms 时基,载入 Flash 数据库。
|
||||
* `void Timer1_Init(void)`:配置 Timer 1 中断,提供 1ms 精度的时基回调。
|
||||
* `void Timer1_Isr(void) interrupt 3`:
|
||||
中断服务函数。累加 `inactivity_timer`;更新 RTC(秒/分/时/日/月/年)数值;分频驱动马达状态机和 RGB 闪烁标志。
|
||||
* `void Load_Database(void)`:读取 `0xFE0000` Flash 扇区数据至内存缓冲槽。
|
||||
* `void Save_Database(void)`:通过 STC IAP 命令擦除 `0xFE0000` 扇区,并将缓冲槽内的 16 组数据完整写回。
|
||||
* `void Add_Sensor(u32 addr, u8 type, u8 suffix_idx)`:向空闲槽位添加新传感器。根据 `type` 索引获取设备名称前缀(如 `PORTE` 或 `PIR`),拼装为 `[前缀] [suffix_idx]`,存入槽位并执行 `Save_Database()` 持久化。
|
||||
* `bit Check_Sensor_ID(u32 addr, u8 *out_slot_index)`:在数据库中查寻地址码,若匹配则返回槽位索引,作为警报时的名称提取依据。
|
||||
|
||||
### 3.4 电池与充电检测接口
|
||||
* `u16 Get_ADC_Result(u8 channel)`:底层 ADC 数据采集函数,完成单次指定通道的模拟量到 12-bit 数字量的转换并返回读数。
|
||||
* `u8 Read_Battery_Percent(void)`:读取通道 8 (`P0.0`),将电压采样转换数据做线性比例转换(`1279~1628` 映射到 `0~100`),计算并返回电量百分比。
|
||||
* `bit Is_Charging(void)`:读取 `P2.7`(充电检测管脚)的 GPIO 数字输入电平。当电平为高(1)时代表 USB 已接入,返回 `1`;否则返回 `0`。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# 编码实现 - 按键扫描与事件判定 (Docs/60_coding/mod-key.md)
|
||||
|
||||
本文件对应按键状态消抖、长按计时判定以及组合按键识别的具体编码实现细节。
|
||||
本文件对应按键状态消抖、确认键长按 3 秒判定以及主键事件注入的具体编码实现细节。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定时中断内的按键扫描、按键状态累加、主循环事件处理)
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定时中断内的按键扫描、按键状态高阻读取、长短按电平扫描)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
@@ -26,67 +26,111 @@ void Key_Scan_Process(void) {
|
||||
key_sos1_state = (key_sos1_state << 1) | KEY_SOS1;
|
||||
key_sos2_state = (key_sos2_state << 1) | KEY_SOS2;
|
||||
|
||||
// 双上部 SOS 键的逻辑并联(低电平有效,按位与运算相当于逻辑或)
|
||||
// 双上部 SOS 键的逻辑并联
|
||||
key_sos_state = key_sos1_state & key_sos2_state;
|
||||
|
||||
// 2. 长按与组合按键计时器累加
|
||||
if ((key_up_state & 0x07) == 0 && (key_down_state & 0x07) == 0) {
|
||||
// ▲ + ▼ 组合键按住
|
||||
comb_hold++;
|
||||
if (comb_hold == 300) { // 3秒
|
||||
key_event_buf = KEY_COMB_LONG;
|
||||
// 2. 按键长按与短按状态机扫描
|
||||
|
||||
// ▲ 键 (UP) 处理
|
||||
if ((key_up_state & 0x07) == 0) {
|
||||
key_up_hold++;
|
||||
} else {
|
||||
if (key_up_hold > 2) {
|
||||
key_event_buf = KEY_UP_SHORT;
|
||||
}
|
||||
key_up_hold = 0;
|
||||
}
|
||||
|
||||
// ▼ 键 (DOWN) 处理 (支持长按 2 秒清除报警/退出)
|
||||
if ((key_down_state & 0x07) == 0) {
|
||||
key_down_hold++;
|
||||
if (key_down_hold == 200) { // 2秒
|
||||
key_event_buf = KEY_DOWN_LONG;
|
||||
}
|
||||
} else {
|
||||
comb_hold = 0;
|
||||
|
||||
// 单个按键:▲ 键 (UP)
|
||||
if ((key_up_state & 0x07) == 0) {
|
||||
key_up_hold++;
|
||||
} else {
|
||||
if (key_up_hold > 2 && key_up_hold < 200) {
|
||||
key_event_buf = KEY_UP_SHORT;
|
||||
}
|
||||
key_up_hold = 0;
|
||||
if (key_down_hold > 2 && key_down_hold < 200) {
|
||||
key_event_buf = KEY_DOWN_SHORT;
|
||||
}
|
||||
key_down_hold = 0;
|
||||
}
|
||||
|
||||
// 单个按键:■ 确认键 (CONFIRM)
|
||||
if ((key_confirm_state & 0x07) == 0) {
|
||||
key_confirm_hold++;
|
||||
} else {
|
||||
if (key_confirm_hold > 2 && key_confirm_hold < 200) {
|
||||
key_event_buf = KEY_CONFIRM_CLICK;
|
||||
}
|
||||
key_confirm_hold = 0;
|
||||
// ■ 确认键 (CONFIRM) 处理 (支持长按 3 秒进入/退出)
|
||||
if ((key_confirm_state & 0x07) == 0) {
|
||||
key_confirm_hold++;
|
||||
if (key_confirm_hold == 300) { // 3秒
|
||||
key_event_buf = KEY_CONFIRM_LONG;
|
||||
}
|
||||
} else {
|
||||
if (key_confirm_hold > 2 && key_confirm_hold < 300) {
|
||||
key_event_buf = KEY_CONFIRM_CLICK;
|
||||
}
|
||||
key_confirm_hold = 0;
|
||||
}
|
||||
|
||||
// 单个按键:并联 SOS 键
|
||||
if ((key_sos_state & 0x07) == 0) {
|
||||
key_sos_hold++;
|
||||
if (key_sos_hold == 500) { // 5秒
|
||||
key_event_buf = KEY_SOS_LONG;
|
||||
}
|
||||
} else {
|
||||
if (key_sos_hold > 2 && key_sos_hold < 500) {
|
||||
key_event_buf = KEY_SOS_SHORT;
|
||||
}
|
||||
key_sos_hold = 0;
|
||||
// 并联 SOS 键
|
||||
if ((key_sos_state & 0x07) == 0) {
|
||||
key_sos_hold++;
|
||||
if (key_sos_hold == 3) {
|
||||
key_event_buf = KEY_SOS_ACTIVE;
|
||||
}
|
||||
// ▼ 键 (DOWN) 处理同上...
|
||||
} else {
|
||||
key_sos_hold = 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
|
||||
### 2.2 事件异步读取与清除
|
||||
主循环在其周期内轮询 `key_event_buf`。一旦发现其非 `KEY_EVENT_NONE`,拷贝并立即重置该缓冲区为 `KEY_EVENT_NONE` 以防止重复触发:
|
||||
### 2.2 事件解调与微调分配分发 (Process_System_Event 示例)
|
||||
在主循环事件分发中,对各个状态下的事件进行处理:
|
||||
```c
|
||||
if (key_event_buf != KEY_EVENT_NONE) {
|
||||
KeyEvent evt = key_event_buf;
|
||||
key_event_buf = KEY_EVENT_NONE; // 清空事件缓冲区
|
||||
void Process_System_Event(KeyEvent evt) {
|
||||
switch (current_state) {
|
||||
case STATE_MENU:
|
||||
if (evt == KEY_UP_SHORT) {
|
||||
if (menu_index > 0) menu_index--;
|
||||
Redraw = 1;
|
||||
} else if (evt == KEY_DOWN_SHORT) {
|
||||
if (menu_index < 3) menu_index++;
|
||||
Redraw = 1;
|
||||
} else if (evt == KEY_CONFIRM_CLICK) {
|
||||
Enter_Menu_Branch(menu_index);
|
||||
} else if (evt == KEY_CONFIRM_LONG) {
|
||||
current_state = STATE_CLOCK;
|
||||
Redraw = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// 执行具体事件动作,如在常态下短按 SOS 进入 SOS 警报发射状态等
|
||||
// ...
|
||||
case STATE_PAIR_CONFIRM:
|
||||
// 直接进行后缀序号微调 (传感器类型已由射频数据码自动识别并锁定)
|
||||
if (evt == KEY_UP_SHORT) {
|
||||
if (selected_suffix < 99) selected_suffix++;
|
||||
Redraw = 1;
|
||||
} else if (evt == KEY_DOWN_SHORT) {
|
||||
if (selected_suffix > 1) selected_suffix--;
|
||||
Redraw = 1;
|
||||
} else if (evt == KEY_CONFIRM_CLICK) {
|
||||
// 点击 CONFIRM,直接将自动解析的类型和调整好的序号写入数据库
|
||||
Add_Sensor(captured_addr, auto_detected_type, selected_suffix);
|
||||
current_state = STATE_CLOCK;
|
||||
Redraw = 1;
|
||||
} else if (evt == KEY_CONFIRM_LONG) {
|
||||
// 长按 3 秒放弃保存返回时钟
|
||||
current_state = STATE_CLOCK;
|
||||
Redraw = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_IPC_BIND:
|
||||
if (evt == KEY_CONFIRM_LONG || evt == KEY_DOWN_LONG) {
|
||||
current_state = STATE_CLOCK;
|
||||
Redraw = 1;
|
||||
} else if (evt == KEY_CONFIRM_CLICK) {
|
||||
EV1527_Transmit(bracelet_factory_id, 0x01);
|
||||
}
|
||||
break;
|
||||
|
||||
// 其它状态处理...
|
||||
}
|
||||
}
|
||||
```
|
||||
通过该缓冲区实现了按键中断采集与主循环处理的解耦。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
# 编码实现 - LCD 显示与字模驱动 (Docs/60_coding/mod-lcd.md)
|
||||
# 编码实现 - AMOLED 显示与字模驱动 (Docs/60_coding/mod-lcd.md)
|
||||
|
||||
本文件对应 LCD 驱动与字模渲染的具体编码实现细节。
|
||||
本文件对应 Truly AMOLED 驱动与无障碍大图文渲染的具体编码实现细节。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [Drivers/lcd.c](file:///c:/workfile/105/stc32g12k128/Drivers/lcd.c) (LCD 初始化、SPI 数据写、画图画字函数)
|
||||
* [Drivers/lcd.h](file:///c:/workfile/105/stc32g12k128/Drivers/lcd.h) (管脚接口与画图画字声明)
|
||||
* [Drivers/lcd_font.h](file:///c:/workfile/105/stc32g12k128/Drivers/lcd_font.h) (ASCII 8x16 点阵字模与图标数据)
|
||||
* [Drivers/lcd_font.h](file:///c:/workfile/105/stc32g12k128/Drivers/lcd_font.h) (包含 16x32 字符点阵、32x64 超大字模、48x48 & 64x64 大图标点阵)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 局部窗口设置 (X/Y轴偏移量修正)
|
||||
在 `lcd.c` 中配置窗口时,需要将坐标对齐到 ST7789V 在 135x240 面板下的实际 GRAM 范围,加入 X 轴 52 像素、Y 轴 40 像素的偏差:
|
||||
### 2.1 局部窗口设置 (X 轴偏移量修正)
|
||||
在 `lcd.c` 中配置窗口时,需要将坐标对齐到 Truly AMOLED (RM69310) 在 120x240 面板下的实际 GRAM 范围,加入 X 轴 4 像素的偏移,Y 轴无偏移:
|
||||
```c
|
||||
void LCD_SetWindow(u16 x1, u16 y1, u16 x2, u16 y2) {
|
||||
x1 += 52;
|
||||
x2 += 52;
|
||||
y1 += 40;
|
||||
y2 += 40;
|
||||
x1 += 4;
|
||||
x2 += 4;
|
||||
|
||||
LCD_WriteCmd(0x2A); // Column Address Set
|
||||
LCD_WriteData(x1 >> 8);
|
||||
@@ -33,106 +31,80 @@ void LCD_SetWindow(u16 x1, u16 y1, u16 x2, u16 y2) {
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 电池图标与动态百分比 (包含充电 + 后缀) 渲染
|
||||
在 `main.c` 的时钟页面刷新中,获取当前百分比及充电状态,动态绘制到状态栏:
|
||||
### 2.2 待机大字时钟与大电量图标渲染
|
||||
在 `main.c` 中渲染时钟,时钟字符使用 `32x64px`,电量文字使用 `16x32px`,状态锁使用 `32x32px` 图标:
|
||||
```c
|
||||
void UI_ShowClockPage(SystemState state, u8 hour, u8 min) {
|
||||
char time_str[6];
|
||||
char bat_str[10];
|
||||
u8 bat_val = Read_Battery_Percent();
|
||||
bit charging = Is_Charging();
|
||||
|
||||
LCD_Clear(COLOR_BLACK);
|
||||
|
||||
// 充电状态判定与百分比字符串格式化
|
||||
if (charging) {
|
||||
// 充电时显示 + 号后缀,如 "85%+"
|
||||
if (bat_val >= 100) {
|
||||
bat_str[0] = '1'; bat_str[1] = '0'; bat_str[2] = '0'; bat_str[3] = '%'; bat_str[4] = '+'; bat_str[5] = '\0';
|
||||
} else {
|
||||
bat_str[0] = '0' + (bat_val / 10);
|
||||
bat_str[1] = '0' + (bat_val % 10);
|
||||
bat_str[2] = '%';
|
||||
bat_str[3] = '+';
|
||||
bat_str[4] = '\0';
|
||||
}
|
||||
// X 坐标向左平移 8 像素 (X=69) 以确保和电池图标 (X=107) 之间有 6px 以上的安全间距
|
||||
LCD_ShowString(69, 24, bat_str, COLOR_GRAY, COLOR_BLACK);
|
||||
// 1. 渲染状态栏 (大锁图标 + 16x32大电量)
|
||||
if (state == STATE_ARMED) {
|
||||
LCD_ShowImage(10, 20, 32, 32, bmp_lock_32x32, COLOR_RED, COLOR_BLACK);
|
||||
} else {
|
||||
// 未充电正常显示百分比,如 "85%"
|
||||
if (bat_val >= 100) {
|
||||
bat_str[0] = '1'; bat_str[1] = '0'; bat_str[2] = '0'; bat_str[3] = '%'; bat_str[4] = '\0';
|
||||
} else {
|
||||
bat_str[0] = '0' + (bat_val / 10);
|
||||
bat_str[1] = '0' + (bat_val % 10);
|
||||
bat_str[2] = '%';
|
||||
bat_str[3] = '\0';
|
||||
}
|
||||
LCD_ShowString(77, 24, bat_str, COLOR_GRAY, COLOR_BLACK);
|
||||
LCD_ShowImage(10, 20, 32, 32, bmp_unlock_32x32, COLOR_GREEN, COLOR_BLACK);
|
||||
}
|
||||
|
||||
// 绘制电池位图图标
|
||||
LCD_ShowImage(107, 27, 20, 10, bmp_battery_20x10, COLOR_GRAY, COLOR_BLACK);
|
||||
// ...
|
||||
if (charging) {
|
||||
sprintf(bat_str, "%d%%+", (int)bat_val);
|
||||
LCD_ShowString(60, 20, bat_str, COLOR_GRAY, COLOR_BLACK); // 16x32px字模
|
||||
} else {
|
||||
sprintf(bat_str, "%d%%", (int)bat_val);
|
||||
LCD_ShowString(70, 20, bat_str, COLOR_GRAY, COLOR_BLACK);
|
||||
}
|
||||
LCD_ShowImage(100, 25, 16, 16, bmp_battery_icon_16x16, COLOR_GRAY, COLOR_BLACK);
|
||||
|
||||
// 2. 渲染中央超大时钟 (32x64px 字模)
|
||||
sprintf(time_str, "%02d:%02d", (int)hour, (int)min);
|
||||
LCD_ShowString32x64Centered(80, time_str, COLOR_WHITE, COLOR_BLACK);
|
||||
|
||||
// 3. 渲染底部大日期 (16x32px 字模)
|
||||
LCD_ShowStringCentered(180, "VEN. 07-10", COLOR_GRAY, COLOR_BLACK);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 字模百分号偏置
|
||||
在 `lcd_font.h` 的 ASCII 字符数组中,百分号 `%`(十进制 37,十六进制 0x25)的字模通过在字模绘制时向上平移 2 像素对齐普通数字的下基准线。
|
||||
|
||||
### 2.4 水平居中渲染实现
|
||||
在 `lcd.c` 中,字符串居中函数需修改宽度限制参数为 `135` 像素:
|
||||
### 2.3 单屏单条目无障碍主菜单渲染
|
||||
主菜单每次只在中央渲染选中条目的 48x48px 图标,下方用大字标出:
|
||||
```c
|
||||
void LCD_ShowStringCentered(u16 y, char *str, u16 color, u16 bg_color) {
|
||||
u16 len = 0;
|
||||
char *p = str;
|
||||
while(*p++) len++;
|
||||
if(len * 8 >= 135)
|
||||
LCD_ShowString(0, y, str, color, bg_color);
|
||||
else
|
||||
LCD_ShowString((135 - len * 8) / 2, y, str, color, bg_color);
|
||||
void UI_ShowMenuPage(u8 selected_item) {
|
||||
LCD_Clear(COLOR_BLACK);
|
||||
LCD_ShowStringCentered(20, "- MENU -", COLOR_GRAY, COLOR_BLACK); // 16x32px
|
||||
|
||||
// 渲染选中项的 48x48px 图标
|
||||
LCD_ShowImage(36, 70, 48, 48, menu_icons_48x48[selected_item], COLOR_CYAN, COLOR_BLACK);
|
||||
|
||||
// 渲染选中项的 16x32px 功能名称
|
||||
LCD_ShowStringCentered(150, menu_names[selected_item], COLOR_WHITE, COLOR_BLACK);
|
||||
|
||||
// 渲染底部上下页提示符 (▲ / ▼)
|
||||
LCD_ShowStringCentered(205, "^ v", COLOR_GRAY, COLOR_BLACK);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.5 绑定界面 ID 渲染实现
|
||||
在 `main.c` 中通过 `FormatHex` 接口将 `bracelet_factory_id` 转换为十六进制字符串,并显示在绑定界面的底部:
|
||||
```c
|
||||
void UI_ShowBindingPage(void) {
|
||||
char id_str[15];
|
||||
// 渲染背景与图标
|
||||
// ...
|
||||
// 绘制手环自身的出厂 ID
|
||||
FormatHex(bracelet_factory_id, id_str);
|
||||
LCD_ShowStringCentered(180, id_str, COLOR_GRAY, COLOR_BLACK);
|
||||
}
|
||||
|
||||
### 2.6 对码确认与序号微调页渲染
|
||||
在 `main.c` 中通过以下方式渲染可供按键微调的数字后缀界面:
|
||||
### 2.4 对码确认超大序号微调界面渲染
|
||||
只读传感器类型名称使用 `16x32px`,大图标使用 `48x48px`,微调序号使用 `32x64px` 超大字符渲染:
|
||||
```c
|
||||
void UI_ShowPairConfirmPage(u8 type, u8 selected_suffix) {
|
||||
char num_buf[10];
|
||||
|
||||
LCD_Clear(COLOR_BLACK);
|
||||
LCD_ShowStringCentered(40, "v RECU", COLOR_GREEN, COLOR_BLACK);
|
||||
|
||||
// 根据类型渲染 32x32 图标
|
||||
// ...
|
||||
// 提示 "RECU" (16x32px)
|
||||
LCD_ShowStringCentered(20, "RECU", COLOR_GREEN, COLOR_BLACK);
|
||||
|
||||
// 居中显示预设名称前缀
|
||||
LCD_ShowStringCentered(135, sensor_prefixes[type], COLOR_WHITE, COLOR_BLACK);
|
||||
// 渲染传感器 48x48px 大图标
|
||||
LCD_ShowImage(36, 60, 48, 48, sensor_icons_48x48[type], COLOR_WHITE, COLOR_BLACK);
|
||||
|
||||
// 拼接成带选框的 "[ 02 ]" 格式字符串并高亮居中渲染
|
||||
num_buf[0] = '[';
|
||||
num_buf[1] = ' ';
|
||||
num_buf[2] = ' ';
|
||||
num_buf[3] = '0' + (selected_suffix / 10);
|
||||
num_buf[4] = '0' + (selected_suffix % 10);
|
||||
num_buf[5] = ' ';
|
||||
num_buf[6] = ' ';
|
||||
num_buf[7] = ']';
|
||||
num_buf[8] = '\0';
|
||||
LCD_ShowStringCentered(165, num_buf, COLOR_CYAN, COLOR_BLACK);
|
||||
// 只读渲染传感器名称 (16x32px)
|
||||
LCD_ShowStringCentered(120, sensor_prefixes[type], COLOR_WHITE, COLOR_BLACK);
|
||||
|
||||
// 渲染超大微调序号选框 (32x64px)
|
||||
sprintf(num_buf, "[%02d]", (int)selected_suffix);
|
||||
LCD_ShowString32x64Centered(170, num_buf, COLOR_CYAN, COLOR_BLACK);
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
```
|
||||
```
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,30 +1,78 @@
|
||||
# 编码实现 - 电源管理与常亮控制 (Docs/60_coding/mod-power.md)
|
||||
# 编码实现 - 电源管理与休眠唤醒 (Docs/60_coding/mod-power.md)
|
||||
|
||||
本文件对应取消低功耗休眠、保持屏幕常亮及系统全时监测的具体编码实现。
|
||||
本文件对应低功耗休眠、关屏切断 PMIC 以及外部中断唤醒的具体编码实现。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (初始化供电配置)
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定义电源控制引脚使能、超时判断及进入 Power-Down 和中断唤醒的实现)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 供电引脚常使能
|
||||
在系统初始化阶段,配置 `LCD_PWR_CTRL`(控制屏和背光供电的引脚)为推挽输出模式,并输出高电平:
|
||||
### 2.1 供电引脚初始化
|
||||
系统初始化时,配置 `SGM_CTRL`(控制 SGM3833 供电的引脚 `P3.4`)为推挽输出,并拉高使能:
|
||||
```c
|
||||
sbit SGM_CTRL = P3^4;
|
||||
|
||||
void Power_Init(void) {
|
||||
// P3.4 (LCD_PWR_CTRL) 配置为推挽输出
|
||||
// P3.4 (SGM_CTRL) 配置为推挽输出
|
||||
P3M1 &= ~(1 << 4);
|
||||
P3M0 |= (1 << 4);
|
||||
|
||||
// 拉高引脚,开启 LCD 背光与供电使能
|
||||
LCD_PWR_CTRL = 1;
|
||||
// 拉高引脚,开启 SGM3833 负压供电
|
||||
SGM_CTRL = 1;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 移除睡眠超时与休眠指令
|
||||
在主循环事件分发中,不再轮询待机时间累加器,也不再调用休眠流程:
|
||||
* **移除** `Enter_Deep_Sleep` 函数。
|
||||
* **移除** 端口 P0 的引脚中断设置(`P0INTE` 等)及 `PD` 停机指令。
|
||||
* 手环时刻保持主频运转,Timer 1 中断不断累加,`EV1527_Decode` 全时监听射频,随时处理防区报警 and SOS 求救触发。
|
||||
### 2.2 进入低功耗睡眠 (Enter_Low_Power_Sleep)
|
||||
在 10 秒无按键操作发生后,关闭屏幕显示,断电,配置中断,并进入 Power-Down 挂起状态:
|
||||
```c
|
||||
void Enter_Low_Power_Sleep(void) {
|
||||
// 1. 给 AMOLED 发送 Sleep In 命令
|
||||
LCD_WriteCmd(0x10);
|
||||
|
||||
<!-- Checked and verified with always-on screen and sleep removal changes -->
|
||||
// 2. 切断 SGM3833 电源,停止输出负压
|
||||
SGM_CTRL = 0;
|
||||
|
||||
// 3. 配置引脚中断 (以 P0.4 确认键、P0.2/P0.5 SOS键为例)
|
||||
// 允许 P0 口引脚下降沿中断以供按键唤醒
|
||||
P0IM1 &= ~0x36; // P0.1, P0.2, P0.3, P0.4, P0.5 设为下降沿或电平触发
|
||||
P0IM0 &= ~0x36;
|
||||
P0INTE |= 0x36; // 开启中断使能
|
||||
|
||||
// 4. 配置射频 carrier 接收脚 (如 P3.6) 为外部中断唤醒
|
||||
EX2 = 1; // 使能外部中断2
|
||||
|
||||
// 5. 写入 PCON.1 使单片机进入 Power-Down 深度睡眠状态
|
||||
PCON |= 0x02; // MCU 挂起,主时钟停振,直到外部中断唤醒
|
||||
_nop_();
|
||||
_nop_();
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 中断唤醒与恢复 (Wakeup_Restore)
|
||||
当产生按键或射频中断后,单片机被唤醒,首先执行外部中断 ISR,退出低功耗并重新使能 OLED:
|
||||
```c
|
||||
// 外部中断服务子程序 (以按键 P0 端口中断为例)
|
||||
void Port0_Isr(void) interrupt 37 {
|
||||
P0INTF = 0x00; // 清除 P0 中断标志
|
||||
Wakeup_Restore();
|
||||
}
|
||||
|
||||
void Wakeup_Restore(void) {
|
||||
if (SGM_CTRL == 1) return; // 已经在工作状态,直接返回
|
||||
|
||||
// 1. 拉高 SGM_CTRL 重新使能 SGM3833 供电
|
||||
SGM_CTRL = 1;
|
||||
|
||||
// 2. 延时约 50ms 等待升压/负压输出稳定
|
||||
Delay50ms();
|
||||
|
||||
// 3. 重新对 RM69310 屏幕控制器做初始化序列
|
||||
LCD_Init();
|
||||
|
||||
// 4. 重置无按键操作的超时计时器
|
||||
inactivity_timer = 0;
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 编码实现 - 自适应 RF 解码与发射 (Docs/60_coding/mod-rf.md)
|
||||
|
||||
本文件对应自适应射频解码与主动发射的具体编码实现细节。已验证无变动。
|
||||
本文件对应自适应射频解码与主动发射的具体编码实现细节。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
解码时,软件轮询检测接收管脚状态。
|
||||
1. **抓取同步头**:检测到一个大于 `1500us` 且小于 `60000us` 的低电平。
|
||||
2. **计算基准 T**:`T = low_time / 31`。
|
||||
3. **采集 24 个数据位**:对于每一位,检测它的高电平持续时间 `h_val` 和低电平持续时间 `l_val`:
|
||||
3. **采集 24 个数据位**:对于每一位,检测它的高电平持续时间 `h_val` and 低电平持续时间 `l_val`:
|
||||
```c
|
||||
// 解码一位数据
|
||||
if (h_val > l_val) {
|
||||
@@ -22,7 +22,7 @@
|
||||
res = (res << 1) | 0;
|
||||
}
|
||||
```
|
||||
4. **极速解析与 CPU 效率**:去除了之前在主循环中阻塞多帧解析的详细日志串口打印,仅在解析整帧成功后发送一行 Summary。单帧处理耗时控制在 **2ms** 以内,彻底避免了连续波形导致的丢包现象。
|
||||
4. 正常解码成功将 20 位地址存入 `out_addr`,后 4 位数据存入 `out_type` 并返回 `1`。
|
||||
|
||||
### 2.2 主动广播发射 (EV1527_Transmit)
|
||||
手环通过 LT4455 发送对码广播或主动 SOS 警报,在 `rf.c` 中实现:
|
||||
@@ -37,4 +37,4 @@ void EV1527_Transmit(u32 addr, u8 data_code) {
|
||||
* **绑定对码**:当用户触发对码绑定时,传入 `addr = bracelet_factory_id`,`data_code = 0x01`。
|
||||
* **主动 SOS 警报**:当触发主动 SOS 时,主状态机在 `STATE_SOS_EMITTED` 下定期以时间片的形式调用此函数,传入 `addr = bracelet_factory_id`,`data_code = 0x08`(即二进制 `1000`)。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -1,32 +1,58 @@
|
||||
# 编码实现 - 系统核心控制与存储 (Docs/60_coding/mod-sys.md)
|
||||
|
||||
本文件对应系统控制与存储的具体编码实现细节。只包含手环代码实现。
|
||||
本文件对应系统状态机、超时低功耗休眠判断以及断电数据库的具体编码实现。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (系统主循环、定时器中断、IAP 存取)
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (系统主逻辑、主状态机切换、10s 超时累加判断)
|
||||
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (系统状态及数据结构定义)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 定时器 1 中断服务 (Timer1_Isr)
|
||||
定时器初始化配置为 1ms,在 `main.c` 中第 190~250 行左右实现。
|
||||
在 `Timer1_Isr` 里,我们累加 `ms_tick`。当累加到 1000 时,重置 `ms_tick = 0`,自增 `current_sec`。若秒达 60,则自增 `current_min` 并置位 `clock_updated = 1` 通知主循环在下一个周期重绘时钟画面。
|
||||
|
||||
### 2.2 IAP 读写细节
|
||||
在 `main.c` 中通过 IAP 寄存器控制读写。
|
||||
### 2.1 10秒无操作休眠时序 (Timer1_Isr)
|
||||
定时器初始化配置为 1ms,在 `main.c` 中实现。
|
||||
在 `Timer1_Isr` (每 10ms 调用一次) 中,当系统非处于休眠(`STATE_SLEEP`)且非处于报警(`STATE_ALARMING`/`STATE_SOS_EMITTED`)状态时,累加无按键操作计数器 `inactivity_timer`:
|
||||
```c
|
||||
void IAP_EraseSector(u16 addr) {
|
||||
IAP_CMD = 3; // 扇区擦除
|
||||
IAP_ADDRL = addr & 0xFF;
|
||||
IAP_ADDRH = addr >> 8;
|
||||
IAP_TRIG = 0x5A; // 触发
|
||||
IAP_TRIG = 0xA5;
|
||||
_nop_();
|
||||
u16 inactivity_timer = 0;
|
||||
|
||||
void Timer1_Isr(void) interrupt 3 {
|
||||
// 基础毫秒滴答计数
|
||||
ms_tick++;
|
||||
|
||||
// 10ms 调度周期
|
||||
if (ms_tick % 10 == 0) {
|
||||
// 当不是休眠或报警时,进行超时计时累加
|
||||
if (current_state != STATE_SLEEP && current_state != STATE_ALARMING && current_state != STATE_SOS_EMITTED) {
|
||||
inactivity_timer++;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 主循环低功耗检测与状态转换
|
||||
在主循环 `main()` 中,不断检查 `inactivity_timer` 是否达到 1000(即 1000 * 10ms = 10 秒):
|
||||
```c
|
||||
void main(void) {
|
||||
System_Init();
|
||||
|
||||
while (1) {
|
||||
// 读取按键事件并重置计时器
|
||||
if (key_event_buf != KEY_EVENT_NONE) {
|
||||
inactivity_timer = 0; // 重置无按键操作计时器
|
||||
}
|
||||
|
||||
// 如果达到 10 秒无操作,进入低功耗休眠
|
||||
if (inactivity_timer >= 1000) {
|
||||
inactivity_timer = 0;
|
||||
current_state = STATE_SLEEP;
|
||||
Enter_Low_Power_Sleep(); // 关屏、拉低 SGM_CTRL、单片机停机
|
||||
}
|
||||
|
||||
// 轮询解码及其他主状态机业务处理
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
- 主动擦除与写字节前必须先调用使能,写完后调用 `IAP_Disable()` 避免误写入损坏配置。
|
||||
- 数据库保存在末尾扇区 `0xFE0000`(大小为 512 字节)。
|
||||
|
||||
### 2.3 获取出厂唯一 ID (Get_Bracelet_Factory_ID)
|
||||
从 STC32G 的内置 IDATA RAM 区域 `0xF1~0xF7` 处读取 7 字节唯一硬件 ID,并将其转换为符合 EV1527 的 20 位地址码:
|
||||
@@ -35,7 +61,7 @@ u32 Get_Bracelet_Factory_ID(void) {
|
||||
unsigned char idata *p_uid = (unsigned char idata *)0xF1;
|
||||
u32 uid = 0;
|
||||
|
||||
// 组合后 3 字节并进行 20 位掩码过滤
|
||||
// 组合后 3 字节并进行 20 位限制
|
||||
uid = ((u32)p_uid[4] << 16) | ((u32)p_uid[5] << 8) | p_uid[6];
|
||||
uid &= 0x0FFFFF; // 20-bit address range limit for EV1527
|
||||
|
||||
@@ -46,41 +72,14 @@ u32 Get_Bracelet_Factory_ID(void) {
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 传感器自定义名称拼接与写入 (Add_Sensor)
|
||||
在 `Add_Sensor(u32 addr, u8 type, u8 suffix_idx)` 中,系统预设 7 类传感器名前缀:
|
||||
```c
|
||||
char *code sensor_prefixes[7] = {
|
||||
"PORTE", "PIR", "FUMEE", "URGENCE", "GAZ", "INOND.", "VIBRA."
|
||||
};
|
||||
```
|
||||
在写入时,手动拼接前缀和两位数字 `suffix_idx` 后缀:
|
||||
```c
|
||||
void Add_Sensor(u32 addr, u8 type, u8 suffix_idx) {
|
||||
u8 slot = ...; // 检索空槽或匹配历史ID
|
||||
char *prefix = sensor_prefixes[type];
|
||||
u8 len = 0;
|
||||
|
||||
// 拷贝前缀
|
||||
while (prefix[len] != '\0' && len < 11) {
|
||||
sensor_list[slot].name_gbk[len] = prefix[len];
|
||||
len++;
|
||||
}
|
||||
sensor_list[slot].name_gbk[len++] = ' ';
|
||||
sensor_list[slot].name_gbk[len++] = '0' + (suffix_idx / 10);
|
||||
sensor_list[slot].name_gbk[len++] = '0' + (suffix_idx % 10);
|
||||
sensor_list[slot].name_gbk[len] = '\0';
|
||||
|
||||
Save_Database();
|
||||
}
|
||||
|
||||
### 2.5 电池采样与充电状态读取实现
|
||||
### 2.4 电池采样与充电状态读取实现
|
||||
在系统模块中,通过硬件 ADC 通道 8 (P0.0) 和数字 I/O (P2.7) 采集电池状态:
|
||||
|
||||
1. **ADC 初始化 (ADC_Init)**:
|
||||
```c
|
||||
void ADC_Init(void) {
|
||||
P0M1 |= 0x01; P0M0 &= ~0x01; // P0.0 配置为高阻输入 (模拟输入模式)
|
||||
ADCCFG = 0x2F; // RESFMT = 1 (右对齐), ADC 时钟配置为 SYSCLK / 2 / 16
|
||||
ADCCFG = 0x2F; // RESFMT = 1 (右对齐)
|
||||
ADC_CONTR |= 0x80; // 打开 ADC 电源 (ADC_POWER = 1)
|
||||
}
|
||||
```
|
||||
@@ -118,5 +117,4 @@ bit Is_Charging(void) {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes -->
|
||||
```
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -8,25 +8,24 @@
|
||||
|
||||
| 串口发送字符 | 对应仿真的物理事件与说明 | 预期系统响应 |
|
||||
| :--- | :--- | :--- |
|
||||
| **`u` / `U`** | 仿真短按 / 长按 **侧边 ▲ 键** | 时钟微调 / 菜单滚动 / **对码确认页:自增序号 (01->99)** |
|
||||
| **`d` / `D`** | 仿真短按 / 长按 **侧边 ▼ 键** | 时钟微调 / 菜单滚动 / 长按取消报警 / **对码确认页:自减序号 (99->01)** |
|
||||
| **`e` / `E`** | 仿真短按 / 长按 **侧边 ■ 确认键** | 选中并进入等待配对 / 短按取消报警 / **对码确认页:确认保存配置** |
|
||||
| **`s` / `S`** | 仿真短按 / 长按 **上部 SOS 1 键** | 触发本地主动 SOS 警报 / 触发对码保存 / **对码确认页:确认保存配置** |
|
||||
| **`x` / `X`** | 仿真短按 / 长按 **上部 SOS 2 键** | 同上,验证双 SOS 键并联触发等效性 |
|
||||
| **`c`** | 仿真同时长按 **▲ + ▼ 键 3 秒** | 系统直接进入配对模式(P-00) |
|
||||
| **`u`** | 仿真短按 **侧边 ▲ 键** | 菜单向上滚动 / 序号自增 / 增加数值 |
|
||||
| **`d`** | 仿真短按 **侧边 ▼ 键** | 菜单向下滚动 / 序号自减 / 减少数值 |
|
||||
| **`D`** | 仿真长按 **侧边 ▼ 键** (2 秒) | 解除警报退回时钟 / 放弃 IPC 绑定返回时钟 |
|
||||
| **`e`** | 仿真短按 **侧边 ■ 确认键 (CONFIRM)** | 确认选中进入 / 确认保存退出 |
|
||||
| **`E`** | 仿真长按 **侧边 ■ 确认键 (CONFIRM)** (3 秒) | 从时钟待机进入菜单 / 菜单返回时钟 / 放弃保存或绑定返回时钟 |
|
||||
| **`s` / `S`** | 仿真短按 / 长按 **上部 SOS 1 键** | 触发本地主动 SOS 报警发送 / 解除警报退回时钟 |
|
||||
| **`x` / `X`** | 仿真短按 / 长按 **上部 SOS 2 键** | 验证双 SOS 键并联触发等效性 |
|
||||
| **`a`** | 仿真捕获到**已配对门磁**报警信号 | 系统跳转到门磁报警界面,亮红灯,振动 1 次 |
|
||||
| **`p`** | 仿真捕获到**已配对 PIR 红外**信号 | 系统跳转到 PIR 报警界面,亮橙灯,振动 2 次 |
|
||||
| **`1`** | 强制切换系统状态为 **NORMAL** (撤防/常态) | 屏幕时钟状态栏显示 `NORMAL` |
|
||||
| **`2`** | 强制切换系统状态为 **ARMED** (布防) | 屏幕时钟状态栏显示红色闭锁 `🔒` |
|
||||
| **`3`** | 强制切换系统状态为 **DISARMED** (撤防) | 屏幕时钟状态栏显示绿色开锁 `🔓` |
|
||||
| **`1`** | 强制唤醒手环并退回 **STATE_CLOCK** | 屏幕时钟状态栏显示待机时钟 |
|
||||
|
||||
---
|
||||
|
||||
## 2. LED 与马达 IO 跳变日志
|
||||
|
||||
主循环对外设引脚的电平状态进行了跟踪,当引脚电平发生变化时,自动通过串口向外部终端打印输出日志。这可以在没有焊接实体马达或 LED灯的情况下验证控制逻辑是否正确:
|
||||
* **LED 状态日志格式**:`[STATE] LED status -> R:1 G:0 B:0` (0表示亮,1表示灭,WS2812B 幻彩 LED 控制状态)
|
||||
* **马达状态日志格式**:`[STATE] MOTOR -> 1` (1表示开启振动,0表示关闭振动)
|
||||
* **LED 状态日志格式**:`[STATE] LED status -> R:1 G:0 B:0` (WS2812B 级联双灯珠输出状态)
|
||||
* **马达状态日志格式**:`[STATE] MOTOR -> 1` (1表示开启振动,0表示关闭)
|
||||
|
||||
---
|
||||
|
||||
@@ -36,32 +35,38 @@
|
||||
* **测试方法**:
|
||||
1. 正常上电启动,查看待机界面右上方电量。
|
||||
2. 使用外部电压源微调电量采样引脚 **`P0.0`**(模拟输入)输入电压在 1.03V 到 1.31V 之间变化,检查电量百分比是否从 `0%` 线性平滑变化到 `100%`。
|
||||
3. 拔插 USB 充电器,或者直接改变引脚 **`P2.7`** 的电平输入(拉高至 3.3V 或拉低到地),观察百分比数值后面是否能同步增加或移除 `+` 后缀(如在 `85%` 与 `85%+` 之间切换,且格式化与电池图标不贴连)。
|
||||
* **预期结果**:时钟、日期显示正常。在 **135 像素宽** 屏幕上,电量百分比与电池图标(X=107, Y=27)对齐美观,间距大于 6 像素。在 USB 插入时电量后追加 `+` 后缀且能完整显示。
|
||||
3. 拔插 USB 充电器,或者直接改变引脚 **`P2.7`** 的电平输入,观察百分比数值后面是否能同步增加或移除 `+` 后缀(如在 `85%` 与 `85%+` 之间切换,且格式化与电池图标不贴连)。
|
||||
* **预期结果**:时钟、日期显示正常。在 **120 像素宽** AMOLED 屏幕上,电量百分比与电池图标(X=82, Y=27)对齐美观。在 USB 插入时电量后追加 `+` 后缀且能完整显示。
|
||||
|
||||
### 3.2 传感器对码与保存
|
||||
* **测试方法**:同时长按 ▲+▼ 3秒进入配对,用上下键选中 `DETEC. PIR`,按下侧边 **■ 确认键** 开启等待,随后物理触发 PIR 传感器。进入对码确认页后,按 **▲ 键** 将中间括号内数字调节至 `02`(即显示 `PIR [ 02 ]`),最后按下 **■ 确认键** (或 **SOS 1**)确认保存。
|
||||
* **预期结果**:
|
||||
1. 进入配对时,LED 亮白色闪烁(3Hz),马达短振 1 次确认。
|
||||
2. 解码匹配成功后,LCD 屏显示 `✓已保存` 以及 `PIR 02`,LED 绿色常亮 2 秒,马达强振 1 次(400ms),随后自动退回配对菜单。
|
||||
|
||||
### 3.3 常亮长显与射频全时监听验证
|
||||
* **测试方法**:在常态待机下静置手环超过 10 秒,并在此期间使用发射装置发送已配对的传感器射频报警包,或随时短按上部的 SOS 键。
|
||||
* **预期结果**:
|
||||
1. 手环在静置超过 10 秒后,屏幕背光不关闭,继续常亮展示时钟待机画面。
|
||||
2. 无线接收解调模块 100% 保持在监听状态,即使在长时间静置后,只要触发匹配的射频报警,手环能立即接收响应,进入报警闪烁及马达震动状态。
|
||||
3. 随时短按 SOS 键能立刻跳转到主动发送界面并开启 EV1527 信号广播。
|
||||
|
||||
### 3.4 手环主动发射 SOS 与 Factory ID 验证
|
||||
### 3.2 低功耗休眠与唤醒验证
|
||||
* **测试方法**:
|
||||
1. 正常开机,在串口输出中查看获取到的 20 位 `Factory ID`(或在绑定界面核对 ID)。
|
||||
2. 短按上部任意一个 SOS 键触发紧急求救。
|
||||
3. 使用 433MHz 接收调试工具或逻辑分析仪抓取手环发射引脚或射频信号。
|
||||
1. 手环置于时钟待机状态下,静置 10 秒以上,观察系统状态。
|
||||
2. 按下侧边任意键,或者触发射频接收信号,观察系统状态。
|
||||
* **预期结果**:
|
||||
1. 手环立刻切入 `SOS EMIS` 界面,红灯闪烁,马达周期性震动。
|
||||
2. 接收工具抓取到以手环 `Factory ID` 为源地址的 24 位 EV1527 信号,其 4 位数据码为 `0x08`。
|
||||
3. 该信号以 2 秒为周期循环向外发射,直到按下“确认键”或其它任意键退出报警状态。
|
||||
1. 静置 10 秒后,OLED 屏幕立刻完全黑屏,检测 `SGM_CTRL` (P3.4) 输出电平为低电平(0V),单片机电流降为微安级(Power-Down 挂起状态)。
|
||||
2. 短按侧边任意按键,或触发 433MHz 信号发射,手环应能被**瞬间唤醒**,`SGM_CTRL` 重新输出高电平(3.3V),AMOLED 重新点亮显示,无花屏或时钟错乱。
|
||||
|
||||
### 3.3 按键菜单交互与功能选择
|
||||
* **测试方法**:
|
||||
1. 在时钟待机页下,长按侧边 **■ 确认键** 达 3 秒。
|
||||
2. 在主菜单页面使用 ▲ 和 ▼ 键进行滚动,分别选中 `1. DATE/HEURE` 和 `2. APPAIRAGE`,按下 **■ 确认键** 进入。
|
||||
* **预期结果**:
|
||||
1. 长按 3 秒后,屏幕立刻切换显示 `- MENU -` 选项卡,且默认首项高亮。
|
||||
2. 滚动选择灵活响应,高亮行外围有 `> <` 箭头指示。按下确认键后能顺利切换至子修改界面或雷达对码界面。
|
||||
|
||||
### 3.4 对码自动识别与序号微调验证
|
||||
* **测试方法**:
|
||||
1. 同时长按 ▲+▼ 3秒进入对码,触发门磁信号对码成功。
|
||||
2. 观察屏幕,手环应**自动根据射频数据码识别出传感器类型为 PORTE**,并直接显示只读名称及门磁图标。
|
||||
3. 序号选框 `[ 01 ]` 默认高亮,按 ▲/▼ 键确认序号数值是否可以进行增减微调。
|
||||
4. 点击 **■ 确认键**,手环是否将数据写入 Flash 数据库,并立刻退回到待机时钟页。
|
||||
* **预期结果**:
|
||||
对码成功进入微调后,传感器类型自动填入,用户仅微调序号,点击 CONFIRM 键直接保存退回时钟。按 CONFIRM 长按 3s 可放弃退出。
|
||||
|
||||
### 3.5 手环主动发射 SOS 与 Factory ID 验证
|
||||
* **测试方法**:短按或长按上部任意一个 SOS 键触发紧急求救,使用 433MHz 接收调试工具或逻辑分析仪抓取手环发射信号。
|
||||
* **预期结果**:
|
||||
1. 手环立刻切入 `SOS EMIS` 界面,级联双红灯闪烁,马达周期性间歇长振。
|
||||
2. 接收工具抓取到以手环 `Factory ID` 为源地址的 24 位 EV1527 信号,其 4 位数据码为 `0x08`,以 2 秒为周期循环向外发射。再次按下 SOS 键或其它任意键退出。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
33851
Hardware/text.kicad_pcb
33851
Hardware/text.kicad_pcb
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
"hidden_nets": [
|
||||
"GND"
|
||||
],
|
||||
"high_contrast_mode": 1,
|
||||
"high_contrast_mode": 0,
|
||||
"net_color_mode": 1,
|
||||
"opacity": {
|
||||
"images": 0.6,
|
||||
@@ -33,7 +33,6 @@
|
||||
},
|
||||
"visible_items": [
|
||||
"vias",
|
||||
"footprint_text",
|
||||
"footprint_anchors",
|
||||
"ratsnest",
|
||||
"grid",
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
"other_text_upright": false,
|
||||
"pads": {
|
||||
"drill": 0.0,
|
||||
"height": 0.310008,
|
||||
"width": 0.529997
|
||||
"height": 2.8,
|
||||
"width": 2.8
|
||||
},
|
||||
"silk_line_width": 0.1,
|
||||
"silk_text_italic": false,
|
||||
@@ -279,12 +279,7 @@
|
||||
"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|",
|
||||
""
|
||||
]
|
||||
],
|
||||
"erc_exclusions": [],
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
@@ -470,9 +465,9 @@
|
||||
"endpoint_off_grid": "warning",
|
||||
"extra_units": "error",
|
||||
"field_name_whitespace": "warning",
|
||||
"footprint_filter": "ignore",
|
||||
"footprint_filter": "warning",
|
||||
"footprint_link_issues": "warning",
|
||||
"four_way_junction": "ignore",
|
||||
"four_way_junction": "warning",
|
||||
"ground_pin_not_ground": "warning",
|
||||
"hier_label_mismatch": "error",
|
||||
"isolated_pin_label": "warning",
|
||||
@@ -488,7 +483,7 @@
|
||||
"net_not_bus_member": "warning",
|
||||
"no_connect_connected": "warning",
|
||||
"no_connect_dangling": "warning",
|
||||
"pin_not_connected": "error",
|
||||
"pin_not_connected": "warning",
|
||||
"pin_not_driven": "error",
|
||||
"pin_to_pin": "warning",
|
||||
"power_pin_not_driven": "error",
|
||||
@@ -496,8 +491,8 @@
|
||||
"similar_label_and_power": "warning",
|
||||
"similar_labels": "warning",
|
||||
"similar_power": "warning",
|
||||
"simulation_model_issue": "ignore",
|
||||
"single_global_label": "ignore",
|
||||
"simulation_model_issue": "warning",
|
||||
"single_global_label": "warning",
|
||||
"stacked_pin_name": "warning",
|
||||
"unannotated": "error",
|
||||
"unconnected_wire_endpoint": "warning",
|
||||
@@ -622,14 +617,50 @@
|
||||
"label": "Datasheet",
|
||||
"name": "Datasheet",
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Sim.Device",
|
||||
"name": "Sim.Device",
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Sim.Pins",
|
||||
"name": "Sim.Pins",
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "Sim.Type",
|
||||
"name": "Sim.Type",
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "LCSC",
|
||||
"name": "LCSC",
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "描述",
|
||||
"name": "Description",
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"group_by": false,
|
||||
"label": "#",
|
||||
"name": "${ITEM_NUMBER}",
|
||||
"show": false
|
||||
}
|
||||
],
|
||||
"filter_string": "",
|
||||
"group_symbols": true,
|
||||
"include_excluded_from_bom": true,
|
||||
"name": "Default Editing",
|
||||
"name": "",
|
||||
"sort_asc": true,
|
||||
"sort_field": "位号"
|
||||
"sort_field": "${EXCLUDE_FROM_BOM}"
|
||||
},
|
||||
"bus_aliases": {},
|
||||
"connection_grid_size": 50.0,
|
||||
@@ -660,6 +691,14 @@
|
||||
"meta": {
|
||||
"version": 1
|
||||
},
|
||||
"ngspice": {
|
||||
"fix_include_paths": true,
|
||||
"meta": {
|
||||
"version": 0
|
||||
},
|
||||
"model_mode": 4,
|
||||
"workbook_filename": ""
|
||||
},
|
||||
"page_layout_descr_file": "",
|
||||
"plot_directory": "",
|
||||
"reuse_designators": true,
|
||||
@@ -672,7 +711,7 @@
|
||||
"uuid": "72df0bee-e55e-4d81-989a-168573031a0a"
|
||||
}
|
||||
],
|
||||
"used_designators": "#PWR28,#PWR57-58",
|
||||
"used_designators": "U6,U10-11,J1,R18-19,D2,#PWR73-75,C14-15",
|
||||
"variants": []
|
||||
},
|
||||
"sheets": [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user