Files
stc32g128k/Docs/30_architecture/main.md

108 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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

# 架构设计 (Docs/30_architecture/main.md)
本章节阐述手环的硬件拓扑、引脚分配、软件状态机设计、以及 IAP Flash 数据库存储设计。
## 1. 硬件规格与引脚映射
主控芯片采用 **STC32G12K128** 单片机(工作频率 24.0 MHz单周期 8051 内核32位乘除法器
显示端采用 **1.14寸 TFT LCD 屏幕**,物理分辨率为 **135x240 像素**
### 1.1 GPIO 引脚配置表
| 引脚号 | 引脚定义 | 模式配置 | 物理外设与功能说明 |
| :--- | :--- | :--- | :--- |
| **P2.3** | `WS2812_DI` | 双向/SPI MOSI | 连接可编程 RGB 灯珠WS2812B/FCOB-2.7)的 DIN 信号输入 |
| **P2.5** | `MOTOR` | 推挽输出/SCLK | 连接振动马达驱动电路。高电平震动,低电平静止 |
| **P0.1** | `KEY_UP` | 高阻输入+上拉 | 侧边按键 ▲ (上移),按下为低电平 |
| **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.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`),调用数据库写入函数。
---
## 2. 核心软件业务状态机 (SystemState)
系统处于主循环中,根据事件和计数器在以下状态(`SystemState`)间迁移:
```mermaid
stateDiagram-v2
[*] --> STATE_NORMAL
STATE_NORMAL --> STATE_ARMED : 接收到布防广播
STATE_ARMED --> STATE_DISARMED : 接收到撤防广播
STATE_DISARMED --> STATE_NORMAL : 自动恢复/按键返回
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_NORMAL --> STATE_SOS_EMITTED : 短按 SOS
STATE_ARMED --> STATE_ALARMING : 捕获已配对传感器报警
STATE_ALARMING --> STATE_NORMAL : 按任意键/超时解除
STATE_SOS_EMITTED --> STATE_NORMAL : 长按任意键/超时解除
```
---
## 3. IAP Flash 传感器数据库设计
为了断电保存传感器配对信息,使用 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()` 进行统一序列化读写。