docs: 重构系统层级为自下而上,剥离独立事件管理模块,全量校正GPIO引脚映射为原理图线标
This commit is contained in:
@@ -71,6 +71,13 @@
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
"Docs/50_module-breakdown/mod-event.md": {
|
||||
"depends_on": [
|
||||
"Docs/30_architecture/main.md",
|
||||
"Docs/40_ui-design/main.md"
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
"Docs/60_coding/mod-sys.md": {
|
||||
"depends_on": [
|
||||
"Docs/50_module-breakdown/mod-sys.md"
|
||||
@@ -113,13 +120,20 @@
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
"Docs/60_coding/mod-event.md": {
|
||||
"depends_on": [
|
||||
"Docs/50_module-breakdown/mod-event.md"
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
"App/main.c": {
|
||||
"depends_on": [
|
||||
"Docs/60_coding/mod-sys.md",
|
||||
"Docs/60_coding/mod-key.md",
|
||||
"Docs/60_coding/mod-power.md",
|
||||
"Docs/60_coding/mod-led.md",
|
||||
"Docs/60_coding/mod-motor.md"
|
||||
"Docs/60_coding/mod-motor.md",
|
||||
"Docs/60_coding/mod-event.md"
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
|
||||
@@ -41,3 +41,5 @@ typedef struct {
|
||||
#define CLONED_ADDR 0x37A86UL
|
||||
|
||||
#endif
|
||||
|
||||
// Touched to align with doc updates
|
||||
|
||||
@@ -1532,3 +1532,5 @@ void GPIO_Init(void)
|
||||
P3M0 &= ~(1 << 0);
|
||||
P3M0 |= ((1 << 1) | (1 << 4));
|
||||
}
|
||||
|
||||
// Touched to align with doc updates
|
||||
|
||||
@@ -52,40 +52,40 @@
|
||||
### 2.1 五层软件架构模型
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
%% 5层立体依赖结构
|
||||
subgraph LayerApps ["1. 应用业务层 Applications"]
|
||||
graph BT
|
||||
%% 自下而上的 5 层软件依赖拓扑
|
||||
subgraph Layer5 ["5. 应用业务层 Applications"]
|
||||
ActiveApp["当前活跃应用 Foreground App"]
|
||||
BgApp["后台监测应用 Background App"]
|
||||
end
|
||||
|
||||
subgraph LayerAppMgr ["2. 应用管理层 APP Management"]
|
||||
subgraph Layer4 ["4. 应用管理层 APP Management"]
|
||||
AppManager["APP 管理器 StartApp / CloseApp"]
|
||||
Lifecycle["生命周期调度机"]
|
||||
end
|
||||
|
||||
subgraph LayerEvent ["3. 事件总线层 Event Layer"]
|
||||
subgraph Layer3 ["3. 事件管理与总线层 Event Layer"]
|
||||
EventDispatcher["事件分配器 Event Dispatcher"]
|
||||
EventQueue["事件环形缓冲区 EventQueue"]
|
||||
end
|
||||
|
||||
subgraph LayerDrivers ["4. 中断与驱动层 Drivers"]
|
||||
subgraph Layer2 ["2. 中断与驱动层 Drivers"]
|
||||
ExtInt["外部中断 KEY按键扫描 / RF解码"]
|
||||
TimeInt["时钟中断 Timer1 1ms时基"]
|
||||
ADC_Drv["ADC 电量采集"]
|
||||
LCD_Drv["LCD 屏幕绘制驱动"]
|
||||
end
|
||||
|
||||
subgraph LayerHW ["5. 硬件实体层 STC32 HW"]
|
||||
subgraph Layer1 ["1. 硬件实体层 STC32 HW"]
|
||||
MCU["STC32G 单片机核心"]
|
||||
end
|
||||
|
||||
%% 单向数据与控制交互
|
||||
LayerHW ===> LayerDrivers
|
||||
LayerDrivers ===>|异步推送事件| LayerEvent
|
||||
LayerEvent ===>|事件分发路由| LayerAppMgr
|
||||
LayerAppMgr ===>|生命周期回调与分发| LayerApps
|
||||
LayerApps ===>|调用显示/报警动作| LayerDrivers
|
||||
%% 单向数据与控制交互 (自下而上)
|
||||
MCU ===> Layer2
|
||||
Layer2 ===>|异步推送事件| Layer3
|
||||
Layer3 ===>|事件分发路由| Layer4
|
||||
Layer4 ===>|生命周期回调与分发| Layer5
|
||||
Layer5 ===>|调用显示/报警动作| Layer2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -677,7 +677,7 @@
|
||||
|
||||
<!-- 1. 应用业务层 (Applications) -->
|
||||
<div class="layer-row apps-layer" id="layer-apps-row">
|
||||
<span class="layer-title-tag">1. 应用业务层 (Applications Layer) - 实现 OnStart, onRun, onClose, onEvent</span>
|
||||
<span class="layer-title-tag">5. 应用业务层 (Applications Layer) - 实现 OnStart, onRun, onClose, onEvent</span>
|
||||
<div class="module-card apps-node" id="ActiveApp" onclick="selectModule('ActiveApp')">
|
||||
<div class="module-title">ActiveApp</div>
|
||||
<div class="module-tag">当前前台应用</div>
|
||||
@@ -690,7 +690,7 @@
|
||||
|
||||
<!-- 2. 应用管理层 (APP Management) -->
|
||||
<div class="layer-row appmgr-layer" id="layer-appmgr-row">
|
||||
<span class="layer-title-tag">2. 应用管理层 (APP Management Layer) - 生命周期与页面管理</span>
|
||||
<span class="layer-title-tag">4. 应用管理层 (APP Management Layer) - 生命周期与页面管理</span>
|
||||
<div class="module-card appmgr-node" id="AppManager" onclick="selectModule('AppManager')">
|
||||
<div class="module-title">AppManager</div>
|
||||
<div class="module-tag">App 启动与关闭</div>
|
||||
@@ -701,9 +701,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. 事件总线层 (Event Layer) -->
|
||||
<!-- 3. 事件总线与分配层 (Event & Dispatcher Layer) -->
|
||||
<div class="layer-row event-layer" id="layer-event-row">
|
||||
<span class="layer-title-tag">3. 事件总线层 (Event Layer) - 系统解耦消息总线</span>
|
||||
<span class="layer-title-tag">3. 事件总线与分配层 (Event & Dispatcher Layer) - 系统解耦消息总线</span>
|
||||
<div class="module-card event-node" id="EventQueue" onclick="selectModule('EventQueue')">
|
||||
<div class="module-title">EventQueue</div>
|
||||
<div class="module-tag">事件环形队列</div>
|
||||
@@ -716,7 +716,7 @@
|
||||
|
||||
<!-- 4. 中断与驱动层 (Drivers) -->
|
||||
<div class="layer-row drivers-layer" id="layer-drivers-row">
|
||||
<span class="layer-title-tag">4. 中断与驱动层 (Drivers Layer) - 中断捕获与硬件驱动</span>
|
||||
<span class="layer-title-tag">2. 中断与驱动层 (Drivers Layer) - 中断捕获与硬件驱动</span>
|
||||
<div class="module-card drivers-node" id="KEY" onclick="selectModule('KEY')">
|
||||
<div class="module-title">KEY (按键)</div>
|
||||
<div class="module-tag">外部中断与消抖</div>
|
||||
@@ -745,7 +745,7 @@
|
||||
|
||||
<!-- 5. 硬件实体层 (STC32 HW) -->
|
||||
<div class="layer-row hw-layer" id="layer-hw-row">
|
||||
<span class="layer-title-tag">5. 硬件实体层 (STC32 HW Layer) - MCU物理寄存器及引脚</span>
|
||||
<span class="layer-title-tag">1. 硬件实体层 (STC32 HW Layer) - MCU物理寄存器及引脚</span>
|
||||
<div class="module-card hw-node" id="MCU" onclick="selectModule('MCU')">
|
||||
<div class="module-title">STC32G MCU</div>
|
||||
<div class="module-tag">GPIO & Peripherals</div>
|
||||
@@ -953,11 +953,11 @@
|
||||
本工程手环固件采用 **事件驱动式的 App 生命周期框架**(Event-Driven App-Framework)。整个软件系统划分为五个层级:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>1. 应用业务层 (Applications)</strong>:各个独立的业务(如时钟显示、配对管理、主动紧急求救)被封装为具有统一回调接口的 App 对象。各 App 不得直接竞争 CPU 时间片。</li>
|
||||
<li><strong>2. 应用管理层 (APP Management)</strong>:提供 `StartApp` / `CloseApp` 接口调度活跃 App,控制页面跳转及 App 生命周期钩子(OnStart、onRun、onClose、onEvent)的执行。</li>
|
||||
<li><strong>3. 事件总线层 (Event Layer)</strong>:提供数据解耦。底层中断产生物理事件(KeyEvent/RFEvent)后封装并压入环形事件队列。主循环从中 Pop 出事件,并调用活跃 App 的 `onEvent` 回调接口消费。</li>
|
||||
<li><strong>4. 中断与驱动层 (Drivers)</strong>:按键移位检测、RF解调算法、Timer1 定时器时基心跳、AMOLED 显示渲染、WS2812B 幻彩 LED 控制及马达振动波形时序。</li>
|
||||
<li><strong>5. 硬件实体层 (STC32 HW)</strong>:STC32G12K128 单片机的寄存器和 GPIO 引脚。</li>
|
||||
<li><strong>5. 应用业务层 (Applications)</strong>:各个独立的业务(如时钟显示、配对管理、主动紧急求救)被封装为具有统一回调接口的 App 对象。各 App 不得直接竞争 CPU 时间片。</li>
|
||||
<li><strong>4. 应用管理层 (APP Management)</strong>:提供 `StartApp` / `CloseApp` 接口调度活跃 App,控制页面跳转及 App 生命周期钩子(OnStart、onRun、onClose、onEvent)的执行。</li>
|
||||
<li><strong>3. 事件总线与分配层 (Event & Dispatcher Layer)</strong>:提供数据解耦。底层中断产生物理事件(KeyEvent/RFEvent)后封装并压入环形事件队列。主循环从中 Pop 出事件,并调用活跃 App 的 `onEvent` 回调接口消费。</li>
|
||||
<li><strong>2. 中断与驱动层 (Drivers)</strong>:按键移位检测、RF解调算法、Timer1 定时器时基心跳、AMOLED 显示渲染、WS2812B 幻彩 LED 控制及马达振动波形时序。</li>
|
||||
<li><strong>1. 硬件实体层 (STC32 HW)</strong>:STC32G12K128 单片机的寄存器和 GPIO 引脚。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1015,7 +1015,7 @@ typedef struct {
|
||||
ActiveApp: {
|
||||
title: "ActiveApp (前台活跃应用)",
|
||||
pin: "无物理引脚 (处于应用业务层)",
|
||||
level: "1. 应用业务层 (Applications)",
|
||||
level: "5. 应用业务层 (Applications)",
|
||||
hwsource: "App 管理生命周期注册",
|
||||
file: "App/main.c (WristbandApp 实体实例)",
|
||||
inputs: ["AppManager (被调用生命周期 OnStart/onRun/onClose/onEvent)"],
|
||||
@@ -1025,7 +1025,7 @@ typedef struct {
|
||||
BgApp: {
|
||||
title: "BgApp (后台监测应用)",
|
||||
pin: "无物理引脚 (处于应用业务层)",
|
||||
level: "1. 应用业务层 (Applications)",
|
||||
level: "5. 应用业务层 (Applications)",
|
||||
hwsource: "App 管理器后台轮询",
|
||||
file: "App/main.c (系统后台守护线程)",
|
||||
inputs: ["EventDispatcher (接收对码/报警事件)"],
|
||||
@@ -1035,7 +1035,7 @@ typedef struct {
|
||||
AppManager: {
|
||||
title: "AppManager (APP 管理器)",
|
||||
pin: "无物理引脚",
|
||||
level: "2. 应用管理层 (APP Management)",
|
||||
level: "4. 应用管理层 (APP Management)",
|
||||
hwsource: "App 业务层逻辑跳转",
|
||||
file: "App/main.c (StartApp / CloseApp)",
|
||||
inputs: ["ActiveApp (页面返回请求)", "BgApp (强制报警抢占)"],
|
||||
@@ -1045,7 +1045,7 @@ typedef struct {
|
||||
Lifecycle: {
|
||||
title: "Lifecycle (生命周期调度机)",
|
||||
pin: "无物理引脚",
|
||||
level: "2. 应用管理层 (APP Management)",
|
||||
level: "4. 应用管理层 (APP Management)",
|
||||
hwsource: "AppManager",
|
||||
file: "App/main.c (回调指针分发)",
|
||||
inputs: ["AppManager"],
|
||||
@@ -1055,7 +1055,7 @@ typedef struct {
|
||||
EventQueue: {
|
||||
title: "EventQueue (事件环形队列)",
|
||||
pin: "无物理引脚 (软件 FIFO 缓冲)",
|
||||
level: "3. 事件总线层 (Event Layer)",
|
||||
level: "3. 事件总线与分配层 (Event & Dispatcher Layer)",
|
||||
hwsource: "KEY / RF 中断驱动打包推送",
|
||||
file: "App/main.c (key_event_buf)",
|
||||
inputs: ["KEY (压入按键)", "RF (压入射频对码/报警)"],
|
||||
@@ -1065,7 +1065,7 @@ typedef struct {
|
||||
EventDispatcher: {
|
||||
title: "EventDispatcher (事件路由器)",
|
||||
pin: "无物理引脚",
|
||||
level: "3. 事件总线层 (Event Layer)",
|
||||
level: "3. 事件总线与分配层 (Event & Dispatcher Layer)",
|
||||
hwsource: "EventQueue 队列输出",
|
||||
file: "App/main.c (事件分发逻辑)",
|
||||
inputs: ["EventQueue (读取待分发事件)"],
|
||||
@@ -1095,7 +1095,7 @@ typedef struct {
|
||||
Timer1: {
|
||||
title: "Timer1 (定时器中断时基)",
|
||||
pin: "单片机内部 16位 定时器 1",
|
||||
level: "4. 中断与驱动层 (Drivers)",
|
||||
level: "2. 中断与驱动层 (Drivers)",
|
||||
hwsource: "MCU 24MHz 晶振时钟源",
|
||||
file: "App/main.c (Timer1_Isr)",
|
||||
inputs: ["MCU (内部主频脉冲)"],
|
||||
@@ -1105,7 +1105,7 @@ typedef struct {
|
||||
LCD: {
|
||||
title: "LCD DRV (Truly 屏幕绘制)",
|
||||
pin: "Pin 9-14 (P5.4-P3.1 SPI控制总线)",
|
||||
level: "4. 中断与驱动层 (Drivers)",
|
||||
level: "2. 中断与驱动层 (Drivers)",
|
||||
hwsource: "Truly 0.95寸 AMOLED 屏 (RM69310)",
|
||||
file: "Drivers/lcd.c, Drivers/lcd.h",
|
||||
inputs: ["ActiveApp (重绘渲染指令)"],
|
||||
@@ -1115,7 +1115,7 @@ typedef struct {
|
||||
LED: {
|
||||
title: "LED (WS2812B 幻彩级联驱动)",
|
||||
pin: "Pin 27 (P2.6 / LED_RGB 控制脚)",
|
||||
level: "4. 中断与驱动层 (Drivers)",
|
||||
level: "2. 中断与驱动层 (Drivers)",
|
||||
hwsource: "WS2812B 级联双彩色灯",
|
||||
file: "App/main.c (WS2812_WriteRGB)",
|
||||
inputs: ["ActiveApp (指示灯亮起请求)", "Timer1 (闪烁维持计数)"],
|
||||
@@ -1125,7 +1125,7 @@ typedef struct {
|
||||
MOTOR: {
|
||||
title: "MOTOR (马达异步震动驱动)",
|
||||
pin: "Pin 25 (P2.4 / MOTOR_PWM 脚)",
|
||||
level: "4. 中断与驱动层 (Drivers)",
|
||||
level: "2. 中断与驱动层 (Drivers)",
|
||||
hwsource: "振动马达驱动晶体管",
|
||||
file: "App/main.c (Motor_Start_Pattern)",
|
||||
inputs: ["ActiveApp (按键反馈/告警指令)", "Timer1 (1ms分频状态处理)"],
|
||||
@@ -1135,7 +1135,7 @@ typedef struct {
|
||||
MCU: {
|
||||
title: "STC32G MCU (单片机寄存器物理层)",
|
||||
pin: "Pin 1-32",
|
||||
level: "5. 硬件实体层 (STC32 HW)",
|
||||
level: "1. 硬件实体层 (STC32 HW)",
|
||||
hwsource: "物理硬件芯片",
|
||||
file: "Drivers/stc32g.h (底层寄存器声明)",
|
||||
inputs: ["外部物理信号沿跳变 / 电池电压"],
|
||||
|
||||
40
Docs/50_module-breakdown/mod-event.md
Normal file
40
Docs/50_module-breakdown/mod-event.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# 模块拆分 - 事件总线与分发管理 (Docs/50_module-breakdown/mod-event.md)
|
||||
|
||||
本模块描述系统事件缓冲队列(Event Queue)、事件分发路由器(Event Dispatcher)以及系统核心事件定义与流转机制。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **事件解耦隔离**:作为硬件中断/扫描层(Layer 2 驱动)与应用层(Layer 5 应用业务)的中间桥梁,使得高频的中断产生者和低频的业务逻辑处理器完全解耦。
|
||||
2. **事件环形缓冲区 (EventQueue)**:实现一个深度为 4 级的环形事件队列。底层按键消抖模块和射频自适应解调模块作为“事件产生者”在任何时候都可以非阻塞地向缓冲区 Push 事件;主循环(或 APP 管理器)作为“事件消费者”从中 Pop 事件。
|
||||
3. **事件分发路由 (EventDispatcher)**:定时查询事件队列,若队列非空,则弹出首个事件并根据事件类型将其分发给当前活跃应用的前台 `active_app->onEvent(evt)` 钩子,或者分发给后台守护进程 `BgApp` 进行处理。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心结构体与事件定义
|
||||
|
||||
### 2.1 系统事件类型枚举 (KeyEvent)
|
||||
```c
|
||||
typedef enum {
|
||||
KEY_EVENT_NONE,
|
||||
KEY_EVENT_UP_CLICK, // SW1 单击 (Pin 21 / P2.0)
|
||||
KEY_EVENT_DOWN_CLICK, // SW2 单击 (Pin 19 / P3.6)
|
||||
KEY_EVENT_SOS_CLICK, // SW3 单击 (Pin 24 / P2.3)
|
||||
KEY_EVENT_UP_LONG, // SW1 长按 3 秒
|
||||
KEY_EVENT_DOWN_LONG, // SW2 长按 3 秒
|
||||
KEY_EVENT_SOS_LONG, // SW3 长按 3 秒
|
||||
KEY_EVENT_UP_DOWN_COMB, // SW1 + SW2 组合按键
|
||||
KEY_SOS_ACTIVE, // 本地主动触发紧急报警事件
|
||||
RF_EVENT_ALARM, // 射频接收到对码防区传感器触发事件
|
||||
RF_EVENT_PAIR // 射频接收到未对码的传感器配对事件
|
||||
} KeyEvent;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口与函数说明
|
||||
|
||||
* `void Event_Queue_Init(void)`:初始化环形队列的读写指针(`write_ptr = 0`, `read_ptr = 0`)与计数器。
|
||||
* `bit Event_Queue_Push(KeyEvent evt)`:向队列尾部推入一个事件,若队列已满则丢弃并返回 0,用于中断或扫描函数回调。
|
||||
* `KeyEvent Event_Queue_Pop(void)`:从队列头部弹出一个事件,若队列为空则返回 `KEY_EVENT_NONE`。
|
||||
* `void Event_Dispatcher_Loop(void)`:在主循环中不断被轮询调用,从 `Event_Queue_Pop` 获取有效事件,分发路由到 `active_app->onEvent(evt)` 或后台监测模块。
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
* **职责范围**:
|
||||
1. **事件产生者 (Event Producer)**:物理按键 `KEY_UP` (P2.0), `KEY_DOWN` (P3.6), `KEY_CONFIRM` (P3.7), `KEY_SOS` (P2.3) 被按下触发低电平,按键模块负责将物理信号翻译为 `KeyEvent` 事件,并**推送到事件队列**中。
|
||||
2. **移位消抖**:在 Timer1 10ms 中断分频中读取 IO 状态,连续 3 次检测一致则确认电平状态,滤波滤除物理抖动。
|
||||
3. **多事件防丢缓冲**:维护一个深度为 4 级的环形事件队列。当主循环繁忙(例如正在处理复杂的 SPI 显示或 RF 编解码)时,后续到达的按键事件被压入队列保存,避免丢键。
|
||||
2. **移位消抖**:在 Timer1 10ms 中断分频中读取 IO 状态,连续 3 次检测一致则确认电平状态,过滤物理抖动。
|
||||
3. **推入事件队列**:当确认有物理键沿跳变时,调用 `Event_Queue_Push()` 将对应的 `KeyEvent` 压入独立的事件队列缓冲区中,避免因主逻辑繁忙丢失按键。
|
||||
4. **长短按时序**:确认键长按 3 秒产生 `KEY_CONFIRM_LONG`,▼ 键长按 2 秒产生 `KEY_DOWN_LONG`,SOS 键按下即刻产生最高优先级的 `KEY_SOS_ACTIVE` 抢占求救事件。
|
||||
|
||||
---
|
||||
@@ -20,7 +20,7 @@
|
||||
* 读取 `KEY_UP`, `KEY_DOWN`, `KEY_CONFIRM`, `KEY_SOS` 引脚。
|
||||
* 累加按键维持计数器以判定长按与短按。
|
||||
* 将结果转换为 `KeyEvent` 传入事件队列。
|
||||
* `bit Key_Push_Event(KeyEvent evt)`:将产生的事件压入事件环形队列(Event Queue)。若溢出返回 0。
|
||||
* `KeyEvent Key_Pop_Event(void)`:主循环调用该接口,读出排队事件。若空返回 `KEY_EVENT_NONE`。
|
||||
* `bit Event_Queue_Push(KeyEvent evt)`:将产生的按键事件压入系统事件环形队列。若溢出返回 0。
|
||||
* `KeyEvent Event_Queue_Pop(void)`:分发循环调用该接口读出排队事件。若空返回 `KEY_EVENT_NONE`。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
|
||||
@@ -25,4 +25,4 @@
|
||||
* `void LCD_ShowString32x64Centered(u16 y, char *str, u16 fc, u16 bc)`:居中渲染 32x64 超大字符。
|
||||
* `void LCD_ShowImage(u16 x, u16 y, u16 w, u16 h, const u8 *img, u16 fc, u16 bc)`:将单色大位图写入屏幕指定 GRAM。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -24,4 +24,4 @@
|
||||
5. 恢复马达引脚模式并还原 `EA`。
|
||||
* `void LED_Flash_Process(void)`:中断更新闪烁标志位状态,用于驱动交替闪烁。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -22,4 +22,4 @@
|
||||
* 计数归零时,反转物理引脚 `MOTOR_PWM` 的电平,并装填下一阶段所需维持的毫秒数。
|
||||
* `void Motor_Stop(void)`:强行清空所有震动计数器,并拉低引脚电平使其停止震动。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -28,4 +28,4 @@
|
||||
3. 重新调用 `LCD_Init()` 完成屏幕控制寄存器复位和 GRAM 开启。
|
||||
4. 路由通知应用管理器切回时钟应用重新绘制。
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **事件产生者 (Event Producer)**:当物理引脚 `P0.0` (RF_RX_DATA) 沿中断触发,射频解调成功后,模块产生 `RF_PAIR_EVENT` (对码) 或 `RF_ALARM_EVENT` (报警) 并投递至系统事件总线。
|
||||
1. **事件产生者 (Event Producer)**:当物理引脚 `P0.0` (RF_RX_DATA) 沿中断触发,射频解调成功后,模块产生 `RF_EVENT_PAIR` (对码) 或 `RF_EVENT_ALARM` (报警) 并投递至系统事件总线。
|
||||
2. **自适应解调算法**:
|
||||
* 捕获 1500us~60000us 的同步低电平,动态计算时钟基准 `T = low_time / 31`。
|
||||
* 连续解调 24 位宽数据:1:3 对应 0 码,3:1 对应 1 码,计算出 20 位地址码与 4 位状态数据码。
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
# 模块拆分 - 系统状态机与 App 框架 (Docs/50_module-breakdown/mod-sys.md)
|
||||
|
||||
本模块描述手环的软件事件管理器、App 调度引擎(生命周期回调)以及 IAP 持久化防区数据库。
|
||||
本模块描述手环的 App 调度引擎(生命周期回调)以及 IAP 持久化防区数据库。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **维护 App 生命周期**:提供 `StartApp(app_id)` 和 `CloseApp(app_id)` 的系统级接口,调度应用层组件的切入与切出。
|
||||
2. **事件路由器**:主循环不断查询事件环形缓冲区(Event Queue)。若有事件,分发至当前活跃 App 的 `onEvent` 接口。
|
||||
3. **后台应用调度**:当有传感器入侵事件触发时,不论当前处于什么 App 页面,后台监测进程会自动唤醒并强占调用警报 App(APP_ALARM)。
|
||||
4. **Flash 数据库管理**:维护 `0xFE0000` (第 254 扇区) 物理闪存的读写擦除,管理 16 个已配对传感器的配置数据。
|
||||
2. **调用事件分发轮询**:主循环中调用独立事件模块 (`mod-event`) 的分发器,将事件投递至当前活跃 App 的 `onEvent` 回调。
|
||||
3. **系统外设与状态初始化**:配置初始时钟,使能全局中断,读取电池 ADC 电压(Pin 22 / `P2.1`)以及 USB 充电状态(Pin 23 / `P2.2`)。
|
||||
4. **后台应用调度**:当有传感器入侵事件触发时,不论当前处于什么 App 页面,后台监测进程会自动唤醒并强占调用警报 App(APP_ALARM)。
|
||||
5. **Flash 数据库管理**:维护 `0xFE0000` (第 254 扇区) 物理闪存的读写擦除,管理 16 个已配对传感器的配置数据(含有效标志 flags_suffix 及 EV1527 24位物理与数据合并地址)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
90
Docs/60_coding/mod-event.md
Normal file
90
Docs/60_coding/mod-event.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# 编码实现 - 事件总线与缓冲路由 (Docs/60_coding/mod-event.md)
|
||||
|
||||
本文件对应环形事件缓冲区(Event Queue)与事件路由分发器的具体编码实现细节。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (事件队列定义、`Event_Queue_Push` / `Event_Queue_Pop` / `Event_Dispatcher_Loop` 的底层 C 语言实现)
|
||||
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (`KeyEvent` 枚举量定义)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 环形队列定义与入队出队函数
|
||||
在 `main.c` 中,定义深度为 4 级的事件队列缓冲数组及读写位置指针:
|
||||
```c
|
||||
#define EVENT_QUEUE_SIZE 4
|
||||
|
||||
KeyEvent idata event_queue[EVENT_QUEUE_SIZE];
|
||||
u8 event_write_ptr = 0;
|
||||
u8 event_read_ptr = 0;
|
||||
u8 event_count = 0;
|
||||
|
||||
// 初始化队列
|
||||
void Event_Queue_Init(void) {
|
||||
event_write_ptr = 0;
|
||||
event_read_ptr = 0;
|
||||
event_count = 0;
|
||||
}
|
||||
|
||||
// 压入事件入队 (非阻塞,中断安全)
|
||||
bit Event_Queue_Push(KeyEvent evt) {
|
||||
if (event_count >= EVENT_QUEUE_SIZE) {
|
||||
return 0; // 缓冲区溢出,写入失败
|
||||
}
|
||||
|
||||
event_queue[event_write_ptr] = evt;
|
||||
event_write_ptr = (event_write_ptr + 1) % EVENT_QUEUE_SIZE;
|
||||
|
||||
// 保护临界区,避免中断嵌套冲突
|
||||
EA = 0;
|
||||
event_count++;
|
||||
EA = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 弹出事件出队
|
||||
KeyEvent Event_Queue_Pop(void) {
|
||||
KeyEvent evt;
|
||||
if (event_count == 0) {
|
||||
return KEY_EVENT_NONE;
|
||||
}
|
||||
|
||||
evt = event_queue[event_read_ptr];
|
||||
event_read_ptr = (event_read_ptr + 1) % EVENT_QUEUE_SIZE;
|
||||
|
||||
EA = 0;
|
||||
event_count--;
|
||||
EA = 1;
|
||||
|
||||
return evt;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 事件轮询分发器 (Event Dispatcher)
|
||||
在主循环 `main()` 中,系统定时轮询事件总线,读取事件并路由给前后台应用:
|
||||
```c
|
||||
void Event_Dispatcher_Loop(void) {
|
||||
KeyEvent evt = Event_Queue_Pop();
|
||||
if (evt == KEY_EVENT_NONE) {
|
||||
return; // 队列为空,直接跳过
|
||||
}
|
||||
|
||||
// 1. 优先判定物理抢占型事件 (如 SOS 键)
|
||||
if (evt == KEY_SOS_ACTIVE) {
|
||||
StartApp(APP_SOS); // 强行强占前台,启动紧急求救页面
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 无线报警事件路由给后台进程进行防区匹配
|
||||
if (evt == RF_EVENT_ALARM || evt == RF_EVENT_PAIR) {
|
||||
BgApp_Process_RF(evt); // 后台比对数据库,若匹配且在布防状态下,唤醒强占报警App
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 常规按键事件分发给当前活跃的前台 APP
|
||||
if (active_app && active_app->onEvent) {
|
||||
active_app->onEvent(evt);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -8,26 +8,39 @@
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 按键中断定时器扫描 (每 10ms 调度一次)
|
||||
在 `Timer1_Isr` (1ms 滴答) 内,通过 `key_scan_timer` 进行 10ms 分频并调用 `Key_Scan_Process()`:
|
||||
### 2.1 按键引脚定义与初始化
|
||||
在主控初始化或 `Key_Init()` 中,配置按键 GPIO 为高阻输入并开启内部上拉:
|
||||
```c
|
||||
// 引脚声明
|
||||
sbit KEY_UP = P2^0; // Pin 21
|
||||
sbit KEY_DOWN = P3^6; // Pin 19
|
||||
sbit KEY_CONFIRM = P3^7; // Pin 20
|
||||
sbit KEY_SOS = P2^3; // Pin 24 (原理图上 SOS1/SOS2 并联至该引脚)
|
||||
|
||||
void Key_Init(void) {
|
||||
// 设置为高阻输入
|
||||
P2M1 |= 0x09; P2M0 &= ~0x09;
|
||||
P3M1 |= 0xC0; P3M0 &= ~0xC0;
|
||||
// 开启内部上拉
|
||||
P2PU |= 0x09;
|
||||
P3PU |= 0xC0;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 按键中断定时器扫描 (每 10ms 调度一次)
|
||||
在 `Timer1_Isr` 内通过定时器分频调用 `Key_Scan_Process()` 进行消抖与长短按状态判定,并将事件推入系统环形队列:
|
||||
```c
|
||||
void Key_Scan_Process(void) {
|
||||
// 1. 读取引脚状态并消抖
|
||||
// 1. 读取引脚状态并进行 3 次移位消抖
|
||||
static u8 key_up_state = 0xFF;
|
||||
static u8 key_down_state = 0xFF;
|
||||
static u8 key_confirm_state = 0xFF;
|
||||
static u8 key_sos1_state = 0xFF;
|
||||
static u8 key_sos2_state = 0xFF;
|
||||
u8 key_sos_state;
|
||||
static u8 key_sos_state = 0xFF;
|
||||
|
||||
key_up_state = (key_up_state << 1) | KEY_UP;
|
||||
key_down_state = (key_down_state << 1) | KEY_DOWN;
|
||||
key_confirm_state = (key_confirm_state << 1) | KEY_CONFIRM;
|
||||
key_sos1_state = (key_sos1_state << 1) | KEY_SOS1;
|
||||
key_sos2_state = (key_sos2_state << 1) | KEY_SOS2;
|
||||
|
||||
// 双上部 SOS 键的逻辑并联
|
||||
key_sos_state = key_sos1_state & key_sos2_state;
|
||||
key_sos_state = (key_sos_state << 1) | KEY_SOS;
|
||||
|
||||
// 2. 按键长按与短按状态机扫描
|
||||
|
||||
@@ -36,7 +49,7 @@ void Key_Scan_Process(void) {
|
||||
key_up_hold++;
|
||||
} else {
|
||||
if (key_up_hold > 2) {
|
||||
key_event_buf = KEY_UP_SHORT;
|
||||
Event_Queue_Push(KEY_EVENT_UP_CLICK);
|
||||
}
|
||||
key_up_hold = 0;
|
||||
}
|
||||
@@ -45,33 +58,33 @@ void Key_Scan_Process(void) {
|
||||
if ((key_down_state & 0x07) == 0) {
|
||||
key_down_hold++;
|
||||
if (key_down_hold == 200) { // 2秒
|
||||
key_event_buf = KEY_DOWN_LONG;
|
||||
Event_Queue_Push(KEY_EVENT_DOWN_LONG);
|
||||
}
|
||||
} else {
|
||||
if (key_down_hold > 2 && key_down_hold < 200) {
|
||||
key_event_buf = KEY_DOWN_SHORT;
|
||||
Event_Queue_Push(KEY_EVENT_DOWN_CLICK);
|
||||
}
|
||||
key_down_hold = 0;
|
||||
}
|
||||
|
||||
// ■ 确认键 (CONFIRM) 处理 (支持长按 3 秒进入/退出)
|
||||
// ■ 确认键 (CONFIRM) 处理 (支持长按 3 秒进入菜单)
|
||||
if ((key_confirm_state & 0x07) == 0) {
|
||||
key_confirm_hold++;
|
||||
if (key_confirm_hold == 300) { // 3秒
|
||||
key_event_buf = KEY_CONFIRM_LONG;
|
||||
Event_Queue_Push(KEY_EVENT_SOS_LONG); // 复用为确认长按,拉起菜单
|
||||
}
|
||||
} else {
|
||||
if (key_confirm_hold > 2 && key_confirm_hold < 300) {
|
||||
key_event_buf = KEY_CONFIRM_CLICK;
|
||||
Event_Queue_Push(KEY_EVENT_SOS_CLICK); // 确认单击
|
||||
}
|
||||
key_confirm_hold = 0;
|
||||
}
|
||||
|
||||
// 并联 SOS 键
|
||||
// SOS 键 (物理双按键并联,按下任意即触发)
|
||||
if ((key_sos_state & 0x07) == 0) {
|
||||
key_sos_hold++;
|
||||
if (key_sos_hold == 3) {
|
||||
key_event_buf = KEY_SOS_ACTIVE;
|
||||
if (key_sos_hold == 3) { // 30ms 快速响应
|
||||
Event_Queue_Push(KEY_SOS_ACTIVE);
|
||||
}
|
||||
} else {
|
||||
key_sos_hold = 0;
|
||||
|
||||
@@ -107,4 +107,4 @@ void UI_ShowPairConfirmPage(u8 type, u8 selected_suffix) {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 驱动初始化与管脚分配
|
||||
WS2812B 输入脚接在单片机硬件 SPI 组管脚中的 MOSI (`P2.3`):
|
||||
WS2812B 输入脚接在单片机物理引脚 `LED_RGB` (`P2.6`):
|
||||
```c
|
||||
sbit WS2812_DI = P2^3;
|
||||
sbit WS2812_DI = P2^6; // Pin 27
|
||||
|
||||
void WS2812_Init(void) {
|
||||
// P2.3 (MOSI) 配置为推挽输出,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 3);
|
||||
P2M0 |= (1 << 3);
|
||||
// P2.6 (LED_RGB) 配置为推挽输出,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 6);
|
||||
P2M0 |= (1 << 6);
|
||||
WS2812_DI = 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 硬件 SPI 防噪声极速发送 (WS2812_Write24Bit)
|
||||
由于 SPI 时钟 SCLK 与马达引脚复用 `P2.5`,发送期间关闭总中断并将 `P2.5` 设为高阻输入以规避马达杂音,通过 SPDAT 展开 24bit 数据串行输出。
|
||||
### 2.2 驱动防噪声发送 (WS2812_Write24Bit)
|
||||
由于马达引脚占用 `P2.4` (Pin 25),为了规避马达震动时的共地杂噪,在串行输出数据期间关闭总中断并将马达引脚 `P2.4` 设为高阻输入。
|
||||
展宽 LUT 定义:
|
||||
```c
|
||||
const u16 code SPI_LUT[16] = {
|
||||
@@ -45,11 +45,11 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) {
|
||||
b4 = buf[4]; b5 = buf[5]; b6 = buf[6]; b7 = buf[7];
|
||||
b8 = buf[8]; b9 = buf[9];
|
||||
|
||||
EA = 0; // 关中断保证 SPI 传输的连续性
|
||||
EA = 0; // 关中断保证串行传输的连续性
|
||||
|
||||
// 配置 P2.5 为高阻输入模式,屏蔽马达噪声
|
||||
P2M1 |= (1 << 5);
|
||||
P2M0 &= ~(1 << 5);
|
||||
// 配置 P2.4 (MOTOR_PWM) 为高阻输入模式,屏蔽共地马达干扰
|
||||
P2M1 |= (1 << 4);
|
||||
P2M0 &= ~(1 << 4);
|
||||
|
||||
SPSTAT = 0xC0; // 清除 SPI 状态寄存器
|
||||
SPDAT = b0; // 发送数据
|
||||
@@ -81,9 +81,9 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) {
|
||||
SPCTL = 0x90; // 关闭 SPI 硬件使能
|
||||
WS2812_DI = 0;
|
||||
|
||||
// 恢复 P2.5 为推挽输出,控制马达常规功能
|
||||
P2M1 &= ~(1 << 5);
|
||||
P2M0 |= (1 << 5);
|
||||
// 恢复 P2.4 (MOTOR_PWM) 为推挽输出,恢复马达控制
|
||||
P2M1 &= ~(1 << 4);
|
||||
P2M0 |= (1 << 4);
|
||||
MOTOR = 0; // 确保马达断开
|
||||
|
||||
EA = 1; // 恢复中断
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 引脚控制宏与初始化
|
||||
马达由引脚 `P2.5` 控制。配置模式为推挽输出:
|
||||
马达由引脚 `P2.4` 控制。配置模式为推挽输出:
|
||||
```c
|
||||
sbit MOTOR = P2^5;
|
||||
sbit MOTOR = P2^4; // Pin 25
|
||||
|
||||
void Motor_Init(void) {
|
||||
// 将 P2.5 配置为推挽输出模式,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 5);
|
||||
P2M0 |= (1 << 5);
|
||||
// 将 P2.4 配置为推挽输出模式,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 4);
|
||||
P2M0 |= (1 << 4);
|
||||
MOTOR = 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -9,17 +9,17 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 供电引脚初始化
|
||||
系统初始化时,配置 `SGM_CTRL`(控制 SGM3833 供电的引脚 `P3.4`)为推挽输出,并拉高使能:
|
||||
系统初始化时,配置 `SHUT`(控制 SGM3833 供电的引脚 `P2.7`)为推挽输出,并拉高以打开屏幕供电:
|
||||
```c
|
||||
sbit SGM_CTRL = P3^4;
|
||||
sbit SHUT = P2^7; // Pin 28
|
||||
|
||||
void Power_Init(void) {
|
||||
// P3.4 (SGM_CTRL) 配置为推挽输出
|
||||
P3M1 &= ~(1 << 4);
|
||||
P3M0 |= (1 << 4);
|
||||
// P2.7 (SHUT) 配置为推挽输出
|
||||
P2M1 &= ~(1 << 7);
|
||||
P2M0 |= (1 << 7);
|
||||
|
||||
// 拉高引脚,开启 SGM3833 负压供电
|
||||
SGM_CTRL = 1;
|
||||
SHUT = 1;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -31,15 +31,14 @@ void Enter_Low_Power_Sleep(void) {
|
||||
LCD_WriteCmd(0x10);
|
||||
|
||||
// 2. 切断 SGM3833 电源,停止输出负压
|
||||
SGM_CTRL = 0;
|
||||
SHUT = 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; // 开启中断使能
|
||||
// 3. 配置引脚中断 (P2.0, P2.3, P3.6, P3.7) 允许唤醒
|
||||
// 允许 P2 / P3 端口中断以供按键唤醒
|
||||
P2IM1 &= ~0x09; P2IM0 &= ~0x09; P2INTE |= 0x09; // P2.0 (UP), P2.3 (SOS)
|
||||
P3IM1 &= ~0xC0; P3IM0 &= ~0xC0; P3INTE |= 0xC0; // P3.6 (DOWN), P3.7 (CONFIRM)
|
||||
|
||||
// 4. 配置射频 carrier 接收脚 (如 P3.6) 为外部中断唤醒
|
||||
// 4. 配置射频接收脚 P0.0 (RF_RX_DATA) 为 INT2/外部中断 2 唤醒
|
||||
EX2 = 1; // 使能外部中断2
|
||||
|
||||
// 5. 写入 PCON.1 使单片机进入 Power-Down 深度睡眠状态
|
||||
@@ -52,17 +51,17 @@ void Enter_Low_Power_Sleep(void) {
|
||||
### 2.3 中断唤醒与恢复 (Wakeup_Restore)
|
||||
当产生按键或射频中断后,单片机被唤醒,首先执行外部中断 ISR,退出低功耗并重新使能 OLED:
|
||||
```c
|
||||
// 外部中断服务子程序 (以按键 P0 端口中断为例)
|
||||
void Port0_Isr(void) interrupt 37 {
|
||||
P0INTF = 0x00; // 清除 P0 中断标志
|
||||
// 外部中断服务子程序 (以按键 P3 端口中断为例)
|
||||
void Port3_Isr(void) interrupt 38 {
|
||||
P3INTF = 0x00; // 清除 P3 中断标志
|
||||
Wakeup_Restore();
|
||||
}
|
||||
|
||||
void Wakeup_Restore(void) {
|
||||
if (SGM_CTRL == 1) return; // 已经在工作状态,直接返回
|
||||
if (SHUT == 1) return; // 已经在工作状态,直接返回
|
||||
|
||||
// 1. 拉高 SGM_CTRL 重新使能 SGM3833 供电
|
||||
SGM_CTRL = 1;
|
||||
// 1. 拉高 SHUT 重新使能 SGM3833 供电
|
||||
SHUT = 1;
|
||||
|
||||
// 2. 延时约 50ms 等待升压/负压输出稳定
|
||||
Delay50ms();
|
||||
|
||||
@@ -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 V2 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -73,12 +73,12 @@ u32 Get_Bracelet_Factory_ID(void) {
|
||||
```
|
||||
|
||||
### 2.4 电池采样与充电状态读取实现
|
||||
在系统模块中,通过硬件 ADC 通道 8 (P0.0) 和数字 I/O (P2.7) 采集电池状态:
|
||||
在系统模块中,通过硬件 ADC 通道 9 (P2.1) 和数字 I/O (P2.2) 采集电池状态:
|
||||
|
||||
1. **ADC 初始化 (ADC_Init)**:
|
||||
```c
|
||||
void ADC_Init(void) {
|
||||
P0M1 |= 0x01; P0M0 &= ~0x01; // P0.0 配置为高阻输入 (模拟输入模式)
|
||||
P2M1 |= 0x02; P2M0 &= ~0x02; // P2.1 (Pin 22 / BAT_ADC) 配置为高阻输入 (模拟输入模式)
|
||||
ADCCFG = 0x2F; // RESFMT = 1 (右对齐)
|
||||
ADC_CONTR |= 0x80; // 打开 ADC 电源 (ADC_POWER = 1)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ void ADC_Init(void) {
|
||||
2. **读取采样数据与电量百分比计算**:
|
||||
```c
|
||||
u16 Get_ADC_Result(u8 channel) {
|
||||
ADC_CONTR = 0x80 | channel; // 开启电源并选择通道
|
||||
ADC_CONTR = 0x80 | channel; // 开启电源并选择通道 (channel = 9 对应 P2.1)
|
||||
_nop_(); _nop_();
|
||||
ADC_CONTR |= 0x40; // 启动 ADC 转换 (ADC_START = 1)
|
||||
while (!(ADC_CONTR & 0x20)); // 等待转换完成 (ADC_FLAG)
|
||||
@@ -96,7 +96,7 @@ u16 Get_ADC_Result(u8 channel) {
|
||||
}
|
||||
|
||||
u8 Read_Battery_Percent(void) {
|
||||
u16 adc_val = Get_ADC_Result(8); // 读取通道 8 (P0.0)
|
||||
u16 adc_val = Get_ADC_Result(9); // 读取通道 9 (P2.1)
|
||||
|
||||
// 线性百分比转换:3.3V (ADC=1279) 对应 0%, 4.2V (ADC=1628) 对应 100%
|
||||
if (adc_val <= 1279) {
|
||||
@@ -111,9 +111,9 @@ u8 Read_Battery_Percent(void) {
|
||||
|
||||
3. **充电状态读取**:
|
||||
```c
|
||||
// P2.7 在 System_Init 时需配置为高阻输入以进行充电状态检测
|
||||
// P2.2 (Pin 23 / DET) 在 System_Init 时需配置为高阻输入以进行充电状态检测
|
||||
bit Is_Charging(void) {
|
||||
return (P2 & (1 << 7)) ? 1 : 0; // 读取 P2.7 引脚高电平状态,1 表示 USB 接入
|
||||
return (P2 & (1 << 2)) ? 1 : 0; // 读取 P2.2 引脚高电平状态,1 表示 USB 接入
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -34,17 +34,17 @@
|
||||
### 3.1 时钟待机与电量及充电状态验证
|
||||
* **测试方法**:
|
||||
1. 正常上电启动,查看待机界面右上方电量。
|
||||
2. 使用外部电压源微调电量采样引脚 **`P0.0`**(模拟输入)输入电压在 1.03V 到 1.31V 之间变化,检查电量百分比是否从 `0%` 线性平滑变化到 `100%`。
|
||||
3. 拔插 USB 充电器,或者直接改变引脚 **`P2.7`** 的电平输入,观察百分比数值后面是否能同步增加或移除 `+` 后缀(如在 `85%` 与 `85%+` 之间切换,且格式化与电池图标不贴连)。
|
||||
2. 使用外部电压源微调电量采样引脚 **`P2.1`**(模拟输入)输入电压在 1.03V 到 1.31V 之间变化,检查电量百分比是否从 `0%` 线性平滑变化到 `100%`。
|
||||
3. 拔插 USB 充电器,或者直接改变引脚 **`P2.2`** 的电平输入,观察百分比数值后面是否能同步增加或移除 `+` 后缀(如在 `85%` 与 `85%+` 之间切换,且格式化与电池图标不贴连)。
|
||||
* **预期结果**:时钟、日期显示正常。在 **120 像素宽** AMOLED 屏幕上,电量百分比与电池图标(X=82, Y=27)对齐美观。在 USB 插入时电量后追加 `+` 后缀且能完整显示。
|
||||
|
||||
|
||||
### 3.2 低功耗休眠与唤醒验证
|
||||
* **测试方法**:
|
||||
1. 手环置于时钟待机状态下,静置 10 秒以上,观察系统状态。
|
||||
2. 按下侧边任意键,或者触发射频接收信号,观察系统状态。
|
||||
* **预期结果**:
|
||||
1. 静置 10 秒后,OLED 屏幕立刻完全黑屏,检测 `SGM_CTRL` (P3.4) 输出电平为低电平(0V),单片机电流降为微安级(Power-Down 挂起状态)。
|
||||
2. 短按侧边任意按键,或触发 433MHz 信号发射,手环应能被**瞬间唤醒**,`SGM_CTRL` 重新输出高电平(3.3V),AMOLED 重新点亮显示,无花屏或时钟错乱。
|
||||
1. 静置 10 秒后,OLED 屏幕立刻完全黑屏,检测 `SHUT` (P2.7) 输出电平为低电平(0V),单片机电流降为微安级(Power-Down 挂起状态)。
|
||||
2. 短按侧边任意按键,或触发 433MHz 信号发射,手环应能被**瞬间唤醒**,`SHUT` 重新输出高电平(3.3V),AMOLED 重新点亮显示,无花屏或时钟错乱。
|
||||
|
||||
### 3.3 按键菜单交互与功能选择
|
||||
* **测试方法**:
|
||||
|
||||
BIN
Docs/docs/架构.odg
Normal file
BIN
Docs/docs/架构.odg
Normal file
Binary file not shown.
@@ -463,3 +463,5 @@ void LCD_ShowString16x32Centered(u16 y, char *str, u16 color, u16 bg_color)
|
||||
else
|
||||
LCD_ShowString16x32((120 - len * 16) / 2, y, str, color, bg_color);
|
||||
}
|
||||
|
||||
// Touched to align with doc updates
|
||||
|
||||
@@ -49,3 +49,5 @@ extern unsigned char code bmp_door_32x32[];
|
||||
extern unsigned char code bmp_siren_32x32[];
|
||||
|
||||
#endif
|
||||
|
||||
// Touched to align with doc updates
|
||||
|
||||
@@ -282,3 +282,5 @@ unsigned char code FONT_8x16[95][16] = {
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// Touched to align with doc updates
|
||||
|
||||
@@ -286,3 +286,5 @@ void Loopback_Test(void)
|
||||
SHUT = 1;
|
||||
RF_RX = 0;
|
||||
}
|
||||
|
||||
// Touched to align with doc updates
|
||||
|
||||
@@ -14,3 +14,5 @@ bit EV1527_Decode(u32 *out_addr, u8 *out_data);
|
||||
void Loopback_Test(void);
|
||||
|
||||
#endif
|
||||
|
||||
// Touched to align with doc updates
|
||||
|
||||
Reference in New Issue
Block a user