docs: restructure framework, extract app execution module, group event collection & align GPIOs
This commit is contained in:
@@ -78,6 +78,13 @@
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
"Docs/50_module-breakdown/mod-app.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"
|
||||
@@ -126,6 +133,12 @@
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
"Docs/60_coding/mod-app.md": {
|
||||
"depends_on": [
|
||||
"Docs/50_module-breakdown/mod-app.md"
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
"App/main.c": {
|
||||
"depends_on": [
|
||||
"Docs/60_coding/mod-sys.md",
|
||||
@@ -133,7 +146,8 @@
|
||||
"Docs/60_coding/mod-power.md",
|
||||
"Docs/60_coding/mod-led.md",
|
||||
"Docs/60_coding/mod-motor.md",
|
||||
"Docs/60_coding/mod-event.md"
|
||||
"Docs/60_coding/mod-event.md",
|
||||
"Docs/60_coding/mod-app.md"
|
||||
],
|
||||
"lock": null
|
||||
},
|
||||
|
||||
@@ -42,4 +42,4 @@ typedef struct {
|
||||
|
||||
#endif
|
||||
|
||||
// Touched to align with doc updates
|
||||
// Touched to align with doc updates V3
|
||||
|
||||
@@ -1533,4 +1533,4 @@ void GPIO_Init(void)
|
||||
P3M0 |= ((1 << 1) | (1 << 4));
|
||||
}
|
||||
|
||||
// Touched to align with doc updates
|
||||
// Touched to align with doc updates V3
|
||||
|
||||
@@ -17,31 +17,30 @@
|
||||
|
||||
| 芯片引脚号 | 引脚名称 | 逻辑网络标号 | IO 模式 | 连接外设与功能描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **Pin 1** | `P1.0` | `TXD` | 推挽输出 | 串口 1 (UART1) 发送脚 |
|
||||
| **Pin 2** | `P1.1` | `RXD` | 高阻输入 | 串口 1 (UART1) 接收脚 |
|
||||
| **Pin 4** | `P1.5` | `+3.3V` | 电源 | 屏幕/系统 3.3V 逻辑供电 |
|
||||
| **Pin 5** | `P1.6` | `+3.3V` | 电源 | 屏幕/系统 3.3V 逻辑供电 |
|
||||
| **Pin 6** | `P1.7` | `TP_RST` | 推挽输出 | 触摸屏复位脚 (NC) |
|
||||
| **Pin 8** | `UCAP` | `TP_INT` | 输入中断 | 触摸屏中断唤醒脚 (NC) |
|
||||
| **Pin 9** | `P5.4` | `SPI_SDO` | 推挽输出 | Truly AMOLED 屏幕 SPI 串行数据输出 (MISO) |
|
||||
| **Pin 10** | `Vcc` | `SPI_CS` | 推挽输出 | Truly AMOLED 屏幕 SPI 片选信号 (CS) |
|
||||
| **Pin 11** | `VREF+` | `SPI_CLK` | 推挽输出 | Truly AMOLED 屏幕 SPI 串行时钟信号 (SCL) |
|
||||
| **Pin 12** | `GND` | `SPI_SDI` | 推挽输出 | Truly AMOLED 屏幕 SPI 串行数据输入 (MOSI/SDA) |
|
||||
| **Pin 13** | `P3.0` | `SPI_DCX` | 推挽输出 | Truly AMOLED 屏幕 SPI 数据/指令选择脚 (D/C) |
|
||||
| **Pin 14** | `P3.1` | `DIS_RST` | 推挽输出 | Truly AMOLED 屏幕复位控制脚 (RESET) |
|
||||
| **Pin 19** | `P3.6` | `KEY_DOWN` | 高阻输入 + 上拉 | 侧边按键 ▼ (下移),按下为低电平 |
|
||||
| **Pin 20** | `P3.7` | `KEY_CONFIRM` | 高阻输入 + 上拉 | 侧边按键 ■ (确认/菜单),按下为低电平 |
|
||||
| **Pin 21** | `P2.0` | `KEY_UP` | 高阻输入 + 上拉 | 侧边按键 ▲ (上移),按下为低电平 |
|
||||
| **Pin 22** | `P2.1` | `BAT_ADC` | 模拟输入 | 电池电压采样输入端口,对应硬件 ADC 通道 9 (A9) |
|
||||
| **Pin 23** | `P2.2` | `DET` | 高阻输入 | USB 插入充电检测引脚,高电平代表正在充电 |
|
||||
| **Pin 24** | `P2.3` | `KEY_SOS` | 高阻输入 + 上拉 | 上部并联 SOS 求救按键,按下为低电平 |
|
||||
| **Pin 25** | `P2.4` | `MOTOR_PWM` | 推挽输出 | 连接振动马达驱动电路。高电平震动,低电平静止 |
|
||||
| **Pin 27** | `P2.6` | `LED_RGB` | SPI MOSI | WS2812B 级联双幻彩灯珠 DIN 控制信号 |
|
||||
| **Pin 28** | `P2.7` | `SHUT` | 推挽输出 | OLED 供电芯片 SGM3833 控制引脚。高电平开启供电,低电平切断 |
|
||||
| **Pin 29** | `P0.0` | `RF_RX_DATA` | 输入中断 | LR690L 433MHz 射频接收芯片数据输出脚 (INT0/INT2) |
|
||||
| **Pin 30** | `P0.1` | `RF_TX` | 推挽输出 | LR690L 射频芯片发射使能控制引脚 |
|
||||
| **Pin 31** | `P0.2` | `RF_RX` | 推挽输出 | LR690L 射频芯片接收使能控制引脚 |
|
||||
| **Pin 32** | `P0.3` | `RF_TX_DAT` | 推挽输出 | LR690L 射频芯片发射调制数据输入引脚 |
|
||||
| **Pin 1** | `P1.0` | `DIS_RST` | 推挽输出 | Truly AMOLED 屏幕复位控制脚 (RESET) |
|
||||
| **Pin 2** | `P1.1` | `SPI_DCX` | 推挽输出 | Truly AMOLED 屏幕 SPI 数据/指令选择脚 (D/C) |
|
||||
| **Pin 3** | `P1.4` | `SPI_SDI` | 推挽输出 | Truly AMOLED 屏幕 SPI 串行数据输入 (MOSI/SDA) |
|
||||
| **Pin 4** | `P1.5` |`SPI_CLK` | 推挽输出 | Truly AMOLED 屏幕 SPI 串行时钟信号 (SCL) |
|
||||
| **Pin 5** | `P1.6` | `SPI_CS` | 推挽输出 | Truly AMOLED 屏幕 SPI 片选信号 (CS) |
|
||||
| **Pin 6** | `P1.7` | `SPI_SDO` | 推挽输出 | Truly AMOLED 屏幕 SPI 串行数据输出 (MISO) |
|
||||
| **Pin 10** | `Vcc` | `+3.3V` | 电源 | 屏幕/系统 3.3V 逻辑供电 |
|
||||
| **Pin 11** | `VREF+` | `+3.3V` | 电源 | 屏幕/系统 3.3V 逻辑供电 |
|
||||
| **Pin 12** | `GND` | `+3.3V` | 电源 | 屏幕/系统 3.3V 逻辑供电 |
|
||||
| **Pin 13** |`P3.1` |`RXD` | 高阻输入 | 串口 1 (UART1) 接收脚 |
|
||||
| **Pin 14** | `P3.0` | `TXD` | 推挽输出 | 串口 1 (UART1) 发送脚 |
|
||||
| **Pin 19** | `P3.6` | `RF_TX_DAT` | 推挽输出 | LR690L 射频芯片发射调制数据输入引脚 |
|
||||
| **Pin 20** | `P3.7` | `RF_RX` | 推挽输出 | LR690L 射频芯片接收使能控制引脚
|
||||
| **Pin 21** | `P2.0` | `RF_TX` | 推挽输出 | LR690L 射频芯片发射使能控制引脚 |
|
||||
| **Pin 22** | `P2.1` | `RF_RX_DATA` | 输入中断 | LR690L 433MHz 射频接收芯片数据输出脚
|
||||
| **Pin 23** | `P2.2` |`SHUT` | 推挽输出 | OLED 供电芯片 SGM3833 控制引脚。高电平开启供电
|
||||
| **Pin 24** | `P2.3` | `LED_RGB` | SPI MOSI | WS2812B 级联双幻彩灯珠 DIN 控制信号
|
||||
| **Pin 26** | `P2.5` | `MOTOR_PWM` | 推挽输出 | 连接振动马达驱动电路。高电平震动,低电平静止 |
|
||||
| **Pin 27** | `P2.6` | `KEY_SOS` | 高阻输入 + 上拉 | 上部并联 SOS 求救按键,按下为低电平 |
|
||||
| **Pin 28** | `P2.7` | `DET` | 高阻输入 | USB 插入充电检测引脚,高电平代表正在充电 |
|
||||
| **Pin 29** | `P0.0` | `BAT_ADC` |ADC 输入 | 电池电压采集
|
||||
| **Pin 30** | `P0.1` | `KEY_UP` | 高阻输入 + 上拉 | 侧边按键 ▲ (上移),按下为低电平 |
|
||||
| **Pin 31** | `P0.2` | `KEY_CONFIRM` | 高阻输入 + 上拉 | 侧边按键 ■ (确认/菜单),按下为低电平 |
|
||||
| **Pin 32** | `P0.3` | `KEY_DOWN` | 高阻输入 + 上拉 | 侧边按键 ▼ (下移),按下为低电平 |
|
||||
|
||||
---
|
||||
|
||||
@@ -157,11 +156,11 @@ typedef struct {
|
||||
|
||||
| 事件名称 | 输入源 (触发条件与参数) | 事件总线流转 (产生端 -> 分发端) | 活跃 APP 消费处理 (逻辑响应与动作) |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **按键操作事件**<br>`KEY_EVENT` | **源**:Pin 19/20/21 下降沿中断。<br>**参数**:▲/▼/■ (短按/长按)。 | **产生**:`KEY` 驱动 10ms 中断消抖扫描包装。<br>**分发**:`Key_Push_Event` 压入队列,主循环读出并传入活跃 App。 | **待机应用**:长按确认键 3 秒,调用 `StartApp(APP_MENU)`;<br>**菜单应用**:短按 ▲/▼ 键移动高亮焦点;短按确认键调用 `StartApp` 进入对应子设置应用。 |
|
||||
| **主动求救事件**<br>`SOS_ACTIVE_EVENT` | **源**:Pin 24 (`P2.3`) SOS 物理键拉低。 | **产生**:检测到低电平,直接压入事件队列 `KEY_SOS_ACTIVE`。<br>**分发**:主循环捕获,APP 管理器强制抢占调用 `StartApp(APP_SOS)`。 | **SOS报警应用**:<br>1. 显示:AMOLED 亮起 `SOS EMIS`;<br>2. 灯效:WS2812B 红色交替闪烁 (50ms);<br>3. 马达:开启间歇长振 (振1000ms,停200ms);<br>4. 射频:启动发送线程周期性(2s)发射手环 Factory ID 及 `0x08` (SOS) 包。 |
|
||||
| **无线对码捕获事件**<br>`RF_PAIR_RECV_EVENT` | **源**:Pin 29 沿变化中断。<br>**参数**:EV1527 24位对码信号。 | **产生**:RF 驱动解调同步头并还原二进制码字。<br>**分发**:包装为 `RF_PAIR_EVENT` 传入事件队列,主循环分发。 | **配对应用**:<br>1. 状态:跳转进入 `STATE_PAIR_CONFIRM` (微调保存页);<br>2. 显示:只读显示自动识别的传感器类型及大图标;<br>3. 马达:短振 300ms 提醒成功;<br>4. 交互:通过按键微调序号并写入 Flash 数据库。 |
|
||||
| **传感器入侵警报事件**<br>`RF_ALARM_RECV_EVENT` | **源**:Pin 29 沿变化中断。<br>**参数**:传感器物理地址 + 4位状态码。 | **产生**:RF 驱动还原码字。<br>**分发**:主循环比对 Flash 数据库匹配槽位成功,触发防区报警事件。 | **警报应用**:若该防区为 ZONE 0 (24h) 或处于已布防,APP管理器启动 `StartApp(APP_ALARM)`。<br>1. 显示:AMOLED 刷红边框与对应大图标,显示入侵警报文字;<br>2. 灯效:同步闪烁该防区专属色彩;<br>3. 马达:输出对应防区的特定异步振动波形。 |
|
||||
| **系统自动休眠事件**<br>`AUTO_SLEEP_EVENT` | **源**:软件时钟计时 `inactivity_timer >= 1000` (10s)。 | **产生**:Timer1 中断秒分频累加。<br>**分发**:触发超时休眠事件,分发至当前应用。 | **所有非警报应用**:执行 `onClose()` $
|
||||
ightarrow$ 调用 PM 模块拉低 `SHUT=0`(Pin 28)彻底切断屏幕供电 $
|
||||
| **按键操作事件**<br>`KEY_EVENT` | **源**:Pin 30/31/32 (Port 0) 下降沿中断。<br>**参数**:▲/▼/■ (短按/长按)。 | **产生**:`KEY` 驱动 10ms 中断消抖扫描包装。<br>**分发**:`Event_Queue_Push` 压入队列,主循环调用 `Event_Dispatcher_Loop` 传入活跃 App。 | **待机应用**:长按确认键 3 秒,调用 `StartApp(APP_MENU)`;<br>**菜单应用**:短按 ▲/▼ 键移动高亮焦点;短按确认键调用 `StartApp` 进入对应子设置应用。 |
|
||||
| **主动求救事件**<br>`SOS_ACTIVE_EVENT` | **源**:Pin 27 (`P2.6`) SOS 物理键拉低。 | **产生**:检测到低电平,直接压入事件队列 `KEY_SOS_ACTIVE`。<br>**分发**:主循环捕获,APP 管理器强制抢占调用 `StartApp(APP_SOS)`。 | **SOS报警应用**:<br>1. 显示: OEL 屏亮起 `SOS EMIS`;<br>2. 灯效:WS2812B 红色交替闪烁 (50ms);<br>3. 马达:开启间歇长振 (振1000ms,停200ms);<br>4. 射频:启动发送线程周期性(2s)发射手环 Factory ID 及 `0x08` (SOS) 包。 |
|
||||
| **无线对码捕获事件**<br>`RF_PAIR_RECV_EVENT` | **源**:Pin 22 (`P2.1`) 沿变化中断。<br>**参数**:EV1527 24位对码信号。 | **产生**:RF 驱动解调同步头并还原二进制码字。<br>**分发**:包装为 `RF_EVENT_PAIR` 传入事件队列,主循环分发。 | **配对应用**:<br>1. 状态:跳转进入 `STATE_PAIR_CONFIRM` (微调保存页);<br>2. 显示:只读显示自动识别 of 传感器类型及大图标;<br>3. 马达:短振 300ms 提醒成功;<br>4. 交互:通过按键微调序号并写入 Flash 数据库。 |
|
||||
| **传感器入侵警报事件**<br>`RF_ALARM_RECV_EVENT` | **源**:Pin 22 (`P2.1`) 沿变化中断。<br>**参数**:传感器物理地址 + 4位状态码。 | **产生**:RF 驱动还原码字。<br>**分发**:主循环比对 Flash 数据库匹配槽位成功,触发防区报警事件。 | **警报应用**:若该防区为 ZONE 0 (24h) 或处于已布防,APP管理器启动 `StartApp(APP_ALARM)`。<br>1. 显示:OLED 刷红边框与对应大图标,显示入侵警报文字;<br>2. 灯效:同步闪烁该防区专属色彩;<br>3. 马达:输出对应防区的特定异步振动波形。 |
|
||||
| **系统自动休眠事件**<br>`AUTO_SLEEP_EVENT` | **源**:软件时钟计时 `inactivity_timer >= 1000` (10s)。 | **产生**:Timer1 中断秒分频累加。<br>**分发**:触发超时休眠事件,分发至当前应用。 | **所有非警报应用**:执行 `onClose()` $
|
||||
ightarrow$ 调用 PM 模块拉低 `SHUT=0`(Pin 23)彻底切断屏幕供电 $
|
||||
ightarrow$ 配置 GPIO 变化中断和无线唤醒源 $
|
||||
ightarrow$ 执行 `PCON|=0x02` 进入停机休眠。 |
|
||||
ightarrow$ 执行 `PCON|=0x02` 进入停机休眠。 |
|
||||
|
||||
@@ -686,6 +686,10 @@
|
||||
<div class="module-title">BgApp</div>
|
||||
<div class="module-tag">后台监测应用</div>
|
||||
</div>
|
||||
<div class="module-card apps-node" id="APP" onclick="selectModule('APP')">
|
||||
<div class="module-title">APP (应用模块)</div>
|
||||
<div class="module-tag">运行与页面逻辑</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. 应用管理层 (APP Management) -->
|
||||
@@ -1012,6 +1016,16 @@ typedef struct {
|
||||
|
||||
// 模块细节定义 (数据驱动 - 符合5层架构)
|
||||
const modulesData = {
|
||||
APP: {
|
||||
title: "APP (页面运行与渲染模块)",
|
||||
pin: "无物理引脚 (处于应用业务层)",
|
||||
level: "5. 应用业务层 (Applications)",
|
||||
hwsource: "App 管理器与主循环生命周期注册",
|
||||
file: "Docs/50_module-breakdown/mod-app.md",
|
||||
inputs: ["AppManager (生命周期 OnStart/onRun/onClose/onEvent)", "EventDispatcher (路由按键与射频警报事件)"],
|
||||
outputs: ["LCD (刷写 Truly GRAM 窗口)", "MOTOR/LED (发出状态特定的异步动作指令)"],
|
||||
desc: "手环的核心页面运行与交互层。ClockApp 在前台绘制大字时钟及右上角电量指示;MenuApp 显示单屏菜单项并引导页面跳转;PairApp 接收按键输入在 [01]~[99] 范围内微调序号并保存至 Flash 数据库;AlarmApp 刷新红粗边框,闪烁灯效,异步输出防区特定的马达振动;SOSApp 周期发射 0x08 求救包并红灯爆闪。"
|
||||
},
|
||||
ActiveApp: {
|
||||
title: "ActiveApp (前台活跃应用)",
|
||||
pin: "无物理引脚 (处于应用业务层)",
|
||||
@@ -1306,31 +1320,30 @@ typedef struct {
|
||||
|
||||
// ------------------ 引脚配置交互数据 ------------------
|
||||
const pinsInfo = {
|
||||
'1': { mcu: "P1.0 / RXD2", net: "TXD", mode: "推挽输出", hw: "外部调试串口发送端,用来下载及打印架构运行日志。", sw: "通过 UART1 串口发送缓冲寄存器 SBUF 直接写入。" },
|
||||
'2': { mcu: "P1.1 / TXD2", net: "RXD", mode: "高阻输入", hw: "外部调试串口接收端,支持在测试页面输入控制指令。", sw: "UART1 中断接收,解析对应的指令字并投入状态调度。" },
|
||||
'4': { mcu: "P1.5 / SCL", net: "+3.3V", mode: "电源逻辑供电", hw: "提供 Truly AMOLED 显示芯片的 3.3V 逻辑正向工作电压。", sw: "N/A" },
|
||||
'5': { mcu: "P1.6 / SDA", net: "+3.3V", mode: "电源逻辑供电并联线", hw: "Truly 0.95 AMOLED 屏 3.3V 逻辑并联通道。", sw: "N/A" },
|
||||
'6': { mcu: "P1.7 / RST", net: "TP_RST", mode: "推挽输出", hw: "触摸屏复位控制线,本手环为非触摸,引脚悬空扩展。", sw: "GPIO 设置为高电平输出挂起。" },
|
||||
'8': { mcu: "UCAP", net: "TP_INT", mode: "输入中断", hw: "触摸板中断唤醒电平,非触摸手环,物理悬空。", sw: "N/A" },
|
||||
'9': { mcu: "P5.4 / SS", net: "SPI_SDO", mode: "推挽输出", hw: " Truly AMOLED 屏 SPI 主动输出 (MISO) 对应 P5.4 物理控制线。", sw: "SPI 寄存器配置复用输出。" },
|
||||
'10': { mcu: "Vcc / AVcc", net: "SPI_CS", mode: "推挽输出", hw: " Truly AMOLED 屏 SPI 片选使能线,低电平使能对 RM69310 的写屏操作。", sw: "LCD 读写驱动中,写像素前拉低 CS,写完后拉高 CS。" },
|
||||
'11': { mcu: "VREF+", net: "SPI_CLK", mode: "推挽输出", hw: " Truly AMOLED 屏 SPI 时钟同步脉冲控制引脚 (SCL)。", sw: "SPI 写入数据时由硬件模块自动产生串行移位脉冲。" },
|
||||
'12': { mcu: "GND / AGND", net: "SPI_SDI", mode: "推挽输出", hw: " Truly AMOLED 屏 SPI 输入引脚 (MOSI/SDA),写入像素二进制色彩数据流。", sw: "SPI 发送数据寄存器 SPDAT 写入字节时产生该路时序。" },
|
||||
'13': { mcu: "P3.0 / RxD", net: "SPI_DCX", mode: "推挽输出", hw: " Truly AMOLED 屏幕的数据命令指示线。拉高表示当前写入 GRAM 的是 16-bit 像素数据;拉低表示写入的是控制寄存器指令。", sw: "由 `lcd.c` 的 `LCD_WriteData` 和 `LCD_WriteCmd` 进行拉高/低控制。" },
|
||||
'14': { mcu: "P3.1 / TxD", net: "DIS_RST", mode: "推挽输出", hw: " Truly AMOLED 屏硬件复位引脚。开机或安全唤醒时通过高低电平跳变重置屏幕控制寄存器。", sw: "唤醒序列中先拉低 10ms,再拉高 10ms 触发硬件复位配置命令。" },
|
||||
'19': { mcu: "P3.6 / INT2", net: "KEY_DOWN", mode: "高阻输入 + 使能内部上拉", hw: "侧边 ▼ (下移键),按下触发引脚接地低电平;休眠时支持 P3.6 端口中断直接唤醒 CPU。", sw: "KEY 初始化设置 P3PU=0x40,Timer1 中断中以 10ms 周期读取 P3.6 电平值进行滤波。" },
|
||||
'20': { mcu: "P3.7 / INT3", net: "KEY_CONFIRM", mode: "高阻输入 + 使能内部上拉", hw: "侧边 ■ (确认键),短按确认,长按 3 秒进入主菜单;支持休眠中断唤醒。", sw: "KEY 初始化设置 P3PU=0x80,中断中定时扫描累加计数,若计数满足 300 判定为 CONFIRM_LONG 并投递事件。" },
|
||||
'21': { mcu: "P2.0 / A8", net: "KEY_UP", mode: "高阻输入 + 使能内部上拉", hw: "侧边 ▲ (上移键),按下触发引脚低电平;支持休眠时中断唤醒系统。", sw: "KEY 初始化设置 P2PU=0x01,通过移位计数器累加消抖。" },
|
||||
'22': { mcu: "P2.1 / A9", net: "BAT_ADC", mode: "模拟输入", hw: "连接电池分压电路。采集 0~1.3V 电池模拟电压提供给系统电量处理模块。", sw: "开启内置 12位 ADC 并配置通道 9 转换。取多次累加平均值消噪,线性转换为 0%~100%。" },
|
||||
'23': { mcu: "P2.2 / A10", net: "DET", mode: "高阻输入", hw: "底座 USB 充电插入检测。充电时底座供电输出将其拉为高电平;常态为低电平。", sw: "时钟待机 App (ClockApp) 在 onRun 轮询中读取 P2.2 引脚状态更新充电加号显示。" },
|
||||
'24': { mcu: "P2.3 / A11", net: "KEY_SOS", mode: "高阻输入 + 使能内部上拉", hw: "物理并联的 SOS1 与 SOS2 报警按键共地。按下任意键直接拉低 P2.3 触发紧急求救。", sw: "KEY 初始化设置 P2PU=0x08,Timer1 中断检测 P2.3,低电平消抖完毕立刻推送最高优先级的 KEY_SOS_ACTIVE 事件。" },
|
||||
'25': { mcu: "P2.4 / MISO_2", net: "MOTOR_PWM", mode: "推挽输出", hw: "连接振动马达驱动 MOS 晶体管控制栅。高电平开启震动;低电平关断马达。", sw: "由 `Motor_Start_Pattern` 发起动作,Timer1 定时中断在后台扣减时间并切换 P2.4 电平实现异步非阻塞震动。" },
|
||||
'27': { mcu: "P2.6 / SCLK_2", net: "LED_RGB", mode: "SPI_MOSI 硬件复用输出", hw: "连接上、下级联的双 WS2812B 灯珠的数据输入脚,传送高频 RGB 色彩流。", sw: "写数据时,临时屏蔽全局中断并将 P2.4 马达脚切换为高阻隔离,通过 SPI 高速推字节时序。" },
|
||||
'28': { mcu: "P2.7 / SS_2", net: "SHUT", mode: "推挽输出", hw: " AMOLED 升压 PMIC (SGM3833) 芯片的使能使能控制脚。拉高开启屏幕正负电网工作;拉低彻底切断供电消除漏电。", sw: "PM 驱动模块控制。睡眠时执行 `SHUT = 0` 关闭屏幕电源;安全唤醒后执行 `SHUT = 1` 并强延时 50ms。" },
|
||||
'29': { mcu: "P0.0 / ADC8", net: "RF_RX_DATA", mode: "输入中断 (INT0/INT2)", hw: "LR690L 433MHz 无线接收输出,检测到无线载波时输出脉冲沿,休眠时唤醒单片机。", sw: "休眠前配置为中断源;常态下 RF 解调驱动定时捕捉前导同步头宽度,计算基准时基 T 还原 24位 码。" },
|
||||
'30': { mcu: "P0.1 / ADC9", net: "RF_TX", mode: "推挽输出", hw: "LR690L 发射偏置使能引脚。拉高后射频前端开启天线能量推送。", sw: "主动发射对码或 SOS 求救码时,由 RF 驱动在底层拉高 P0.1 开启发射。" },
|
||||
'31': { mcu: "P0.2 / ADC10", net: "RF_RX", mode: "推挽输出", hw: "LR690L 接收使能控制引脚。高电平代表芯片处于监听天线高频信号状态。", sw: "常态待机和等待对码搜索下,GPIO 默认拉高 P0.2 以监听外界载波。" },
|
||||
'32': { mcu: "P0.3 / ADC11", net: "RF_TX_DAT", mode: "推挽输出", hw: "LR690L 无线调制数据输入,在此引脚输出特定的高低电平比值即可将数据射出。", sw: "主动发射时,利用 GPIO 高速反转 P0.3 产生同步前导宽及 EV1527 对应的 1/0 码脉冲。" }
|
||||
'1': { mcu: "P1.0 / DIS_RST", net: "DIS_RST", mode: "推挽输出", hw: "Truly AMOLED 屏幕复位控制脚 (RESET)。拉低重置屏幕驱动芯片寄存器。", sw: "LCD_Init 模块复位时置低 10ms,再置高 10ms 以启动上电序列。" },
|
||||
'2': { mcu: "P1.1 / SPI_DCX", net: "SPI_DCX", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 数据/指令选择脚。拉高写数据,拉低写指令。", sw: "写数据时拉高引脚;写配置控制命令时拉低引脚。" },
|
||||
'3': { mcu: "P1.4 / SPI_SDI", net: "SPI_SDI", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 串行数据输入端 (MOSI/SDA)。", sw: "向 SPI 发送缓存寄存器 SPDAT 写入 8 位字节自动串行移位输出。" },
|
||||
'4': { mcu: "P1.5 / SPI_CLK", net: "SPI_CLK", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 串行同步时钟引脚 (SCL)。", sw: "SPI 通信时由单片机片上外设硬件模块自动产生串行移位脉冲。" },
|
||||
'5': { mcu: "P1.6 / SPI_CS", net: "SPI_CS", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 片选输入脚。低电平选中Truly显示芯片操作。", sw: "在对屏幕进行像素或指令读写前置 0,读写完毕后置 1 挂起片选线。" },
|
||||
'6': { mcu: "P1.7 / SPI_SDO", net: "SPI_SDO", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 串行数据输出端 (MISO) 用于状态读取。", sw: "N/A" },
|
||||
'10': { mcu: "Vcc / AVcc", net: "+3.3V", mode: "电源逻辑供电", hw: "屏幕与系统 3.3V 逻辑工作正向电压轨道。", sw: "N/A" },
|
||||
'11': { mcu: "VREF+", net: "+3.3V", mode: "电源并联线", hw: "芯片基准电压与 3.3V 电源物理并联通道。", sw: "N/A" },
|
||||
'12': { mcu: "GND / AGND", net: "+3.3V", mode: "电源并联线", hw: "电源并联,稳定模拟和数字地电平轨道通道。", sw: "N/A" },
|
||||
'13': { mcu: "P3.1 / RxD", net: "RXD", mode: "高阻输入", hw: "外部调试串口 1 (UART1) 接收引脚,用于接收控制指令或测试配置包。", sw: "UART1 串口接收中断。当收到指定调试帧时触发对应的状态切换。" },
|
||||
'14': { mcu: "P3.0 / TxD", net: "TXD", mode: "推挽输出", hw: "外部调试串口 1 (UART1) 发送引脚,用于向PC输出系统日志及调试标志。", sw: "通过 UART 串口发送缓存寄存器 SBUF 直接写入以触发物理串行传输。" },
|
||||
'19': { mcu: "P3.6", net: "RF_TX_DAT", mode: "推挽输出", hw: "LR690L 射频模块数据发射脚,向天线前端输入特定的高低电平比值信号。", sw: "主动发射时,利用 GPIO 高速反转产生符合 EV1527 时域码宽的串行方波。" },
|
||||
'20': { mcu: "P3.7", net: "RF_RX", mode: "推挽输出", hw: "LR690L 射频芯片接收监听使能控制脚,高电平开始监听无线载波。", sw: "常态待机和搜码模式下 GPIO 默认拉高引脚以保持持续接收侦听状态。" },
|
||||
'21': { mcu: "P2.0", net: "RF_TX", mode: "推挽输出", hw: "LR690L 射频芯片发射偏置使能引脚,拉高打开射频前端发射天线电磁波。", sw: "当需要主动求救或对码发射时,先拉高此引脚,发射完毕后置 0 关闭天线。" },
|
||||
'22': { mcu: "P2.1", net: "RF_RX_DATA", mode: "输入中断 (INT2)", hw: "LR690L 433MHz 无线接收输出引脚,在捕获到无线载波变化时输出沿信号。", sw: "休眠前配置该引脚上升/下降沿作为 INT2 中断唤醒源;平时由沿捕捉解码。" },
|
||||
'23': { mcu: "P2.2", net: "SHUT", mode: "推挽输出", hw: "AMOLED 升压芯片 SGM3833 供电控制脚。拉高开启屏幕电网;拉低关断。", sw: "电源管理模块操作。睡眠时置 0 切断屏幕正负压;唤醒后置 1 并强延时 50ms。" },
|
||||
'24': { mcu: "P2.3", net: "LED_RGB", mode: "SPI_MOSI 硬件复用输出", hw: "WS2812B 级联双幻彩灯 DIN 控制引脚,输入符合 800kHz 高频的 RGB 码流。", sw: "写彩灯时临时屏蔽中断,将 P2.5 马达隔离引脚,高速送出 24bit 灯效数据。" },
|
||||
'26': { mcu: "P2.5", net: "MOTOR_PWM", mode: "推挽输出", hw: "连接振动马达驱动 MOS 晶体管控制栅。高电平触发震动;低电平关断马达。", sw: "马达驱动模块负责在 Timer1 后台定时控制 P2.5 输出指定时间的占空波形。" },
|
||||
'27': { mcu: "P2.6", net: "KEY_SOS", mode: "高阻输入 + 上拉", hw: "物理并联的 SOS1 与 SOS2 报警按键,按下将引脚接地拉低,休眠支持唤醒。", sw: "KEY 初始化使能 P2PU 的 Bit 6 上拉,Timer1 读取引脚电平沿推送 SOS 警报。" },
|
||||
'28': { mcu: "P2.7", net: "DET", mode: "高阻输入", hw: "USB 底座充电插入检测。USB 连接时输入高电平,平时为低电平。", sw: "时钟待机应用在 OnRun 循环中读取引脚电平状态,更新时钟后是否带 '+' 充电符。" },
|
||||
'29': { mcu: "P0.0 / ADC8", net: "BAT_ADC", mode: "模拟输入", hw: "连接电池采样分压电阻中点。采集 0~1.3V 电压以判定当前电池容量。", sw: "使能内置 12位 ADC 的通道 8 进行模数转换,将结果换算为电池百分比。" },
|
||||
'30': { mcu: "P0.1", net: "KEY_UP", mode: "高阻输入 + 上拉", hw: "侧边按键 ▲ (上移键)。短按进行参数累加或高亮切换,休眠支持唤醒。", sw: "KEY 初始化使能 P0PU 的 Bit 1 上拉,消抖后向事件队列投递 UP_CLICK 事件。" },
|
||||
'31': { mcu: "P0.2", net: "KEY_CONFIRM", mode: "高阻输入 + 上拉", hw: "侧边按键 ■ (确认/菜单键)。短按确认,长按 3 秒调出主菜单交互。", sw: "P0PU 使能上拉,10ms 定时判定短击 (CONFIRM_CLICK) 与 3秒长按 (CONFIRM_LONG)。" },
|
||||
'32': { mcu: "P0.3", net: "KEY_DOWN", mode: "高阻输入 + 上拉", hw: "侧边按键 ▼ (下移键)。短按移动高亮,长按 2 秒退出警报,休眠支持唤醒。", sw: "P0PU 使能上拉,判定短击 (DOWN_CLICK) 与 2秒长按 (DOWN_LONG) 并投递。" }
|
||||
};
|
||||
|
||||
function selectPin(pinNum) {
|
||||
|
||||
25
Docs/50_module-breakdown/mod-app.md
Normal file
25
Docs/50_module-breakdown/mod-app.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 模块拆分 - 应用执行层 (Docs/50_module-breakdown/mod-app.md)
|
||||
|
||||
本模块描述手环的 App 调度管理器(AppManager)、活跃前台应用生命周期钩子(OnStart, onRun, onClose, onEvent)以及各功能模块的页面渲染与状态机调度设计。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **应用生命周期调度 (AppManager)**:维护当前活跃应用的实例指针 `active_app`。当触发切换时,调用旧 App 的 `onClose()` 并调用新 App 的 `OnStart()`,初始化相应的视窗 GRAM。
|
||||
2. **待机时钟应用 (ClockApp)**:手环默认待机状态。中央以 `32x64px` 超大点阵渲染当前时分,右上角渲染 `16x32px` 电量百分比及充电指示 `+`;10秒无操作时触发睡眠调度。
|
||||
3. **主菜单应用 (MenuApp)**:单屏单条目显示交互。每次仅在中央渲染选中项的 `48x48px` 大图标,下方以大字渲染菜单名称,支持 ▲/▼ 键高亮切换,确认键进入对应子页面。
|
||||
4. **配对与微调应用 (PairApp)**:对码捕捉到未配对 24 位射频码时拉起。自动匹配识别传感器类型图标,提供 `32x64px` 超大微调序号选框(可通过 ▲/▼ 键在 `[01]`~`[99]` 之间滚动微调),确认后存入持久化 Flash。
|
||||
5. **传感器报警应用 (AlarmApp)**:被后台监测唤醒拉起。识别触发的对码槽位,屏幕闪烁红色粗边框,中央渲染该类传感器的 `48x48px` 警报大图标与防区前缀,调度对应的专属马达振动波形与 LED 警示颜色。
|
||||
6. **主动求救应用 (SOSApp)**:在待机时短按/长按 SOS 物理按键(Pin 27 / `P2.6`)拉起。屏幕高亮显示 `SOS EMIS`;调度发射模块以 2 秒为周期循环向外界发射 `0x08` (SOS) 无线电数据;触发最高优先级的持续马达震动及红色幻彩灯交替爆闪。
|
||||
|
||||
---
|
||||
|
||||
## 2. 接口与函数说明
|
||||
|
||||
* `void AppManager_Init(void)`:注册所有 WristbandApp 页面实例并设置默认活跃 App 指针为 ClockApp。
|
||||
* `void StartApp(u8 app_id)`:执行应用切换动作。安全切出旧前台应用并唤醒载入新应用。
|
||||
* `void CloseApp(void)`:退出当前活跃 App 实例,默认回退至待机时钟 ClockApp。
|
||||
* `void UI_ShowClockPage(SystemState state, u8 hour, u8 min)`:ClockApp 的专有刷屏绘制函数。
|
||||
* `void UI_ShowMenuPage(u8 selected_item)`:MenuApp 的专有菜单绘制函数。
|
||||
* `void UI_ShowPairConfirmPage(u8 type, u8 selected_suffix)`:PairApp 对码序号微调与保存绘制函数。
|
||||
* `void UI_ShowAlarmPage(u8 type, char *name_prefix, u8 suffix_num)`:AlarmApp 入侵警报粗红框与大图标绘制函数。
|
||||
@@ -1,40 +1,29 @@
|
||||
# 模块拆分 - 事件总线与分发管理 (Docs/50_module-breakdown/mod-event.md)
|
||||
# 模块拆分 - 事件采集与总线分发管理 (Docs/50_module-breakdown/mod-event.md)
|
||||
|
||||
本模块描述系统事件缓冲队列(Event Queue)、事件分发路由器(Event Dispatcher)以及系统核心事件定义与流转机制。
|
||||
本模块描述系统输入事件采集(按键移位消抖滤波与 RF 自适应解调解码)、事件环形队列(EventQueue)缓冲以及事件输出分配(EventDispatcher)的整体流转规格。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **事件解耦隔离**:作为硬件中断/扫描层(Layer 2 驱动)与应用层(Layer 5 应用业务)的中间桥梁,使得高频的中断产生者和低频的业务逻辑处理器完全解耦。
|
||||
2. **事件环形缓冲区 (EventQueue)**:实现一个深度为 4 级的环形事件队列。底层按键消抖模块和射频自适应解调模块作为“事件产生者”在任何时候都可以非阻塞地向缓冲区 Push 事件;主循环(或 APP 管理器)作为“事件消费者”从中 Pop 事件。
|
||||
3. **事件分发路由 (EventDispatcher)**:定时查询事件队列,若队列非空,则弹出首个事件并根据事件类型将其分发给当前活跃应用的前台 `active_app->onEvent(evt)` 钩子,或者分发给后台守护进程 `BgApp` 进行处理。
|
||||
1. **事件采集(按键输入)**:
|
||||
* 在 Timer1 中断 (10ms 时基) 中以移位方式读取物理引脚 `KEY_UP` (P0.1), `KEY_CONFIRM` (P0.2), `KEY_DOWN` (P0.3), `KEY_SOS` (P2.6) 的电平状态,连续 3 次检测一致确立电平。
|
||||
* 物理确认键长按 3 秒生成 `KEY_EVENT_SOS_LONG`,下移键长按 2 秒生成 `KEY_EVENT_DOWN_LONG`,SOS键按下即刻产生最高优先级的 `KEY_SOS_ACTIVE` 求救事件。
|
||||
2. **事件采集(射频接收)**:
|
||||
* 当射频输入引脚 `RF_RX_DATA` (Pin 22 / `P2.1`) 发生电平沿变化时触发外部中断,定时器捕获高低电平比值。
|
||||
* 解调自适应基准 T。连续采集 24 个数据位并组合还原 20 位物理 ID 及 4 位状态码。解密通过后打包为无线对码事件 `RF_EVENT_PAIR` 或报警事件 `RF_EVENT_ALARM`。
|
||||
3. **多事件环形队列缓冲 (EventQueue)**:
|
||||
* 维护一个深度为 4 级的软件环形事件队列。按键和射频中断作为“事件产生者”非阻塞地向其中 Push 事件,隔离高频中断和低频业务交互。
|
||||
4. **事件输出路由分发 (EventDispatcher)**:
|
||||
* 在主循环轮询中,若检测到队列非空,从中 Pop 弹出第一个有效事件。
|
||||
* 优先分发给物理强占型 APP(如 `KEY_SOS_ACTIVE` 强制启动 SOSApp);或分发给后台守护进程 `BgApp` 匹对防区决定是否唤醒 `AlarmApp`;其余常规交互事件分发给当前前台应用 `active_app->onEvent(evt)` 钩子。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心结构体与事件定义
|
||||
## 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)` 或后台监测模块。
|
||||
* `void Event_Queue_Init(void)`:复位环形队列读写指针与总计数器。
|
||||
* `bit Event_Queue_Push(KeyEvent evt)`:非阻塞将物理采集的事件推入队列尾部,成功返回 1。
|
||||
* `KeyEvent Event_Queue_Pop(void)`:从队列头部弹出一个事件并返回,若空返回 `KEY_EVENT_NONE`。
|
||||
* `void Key_Scan_Process(void)`:Timer1 (10ms) 滴答调度。扫描物理引脚 P0.1-P0.3 / P2.6 并判定长短按逻辑,调用 `Event_Queue_Push` 产生输入源。
|
||||
* `bit EV1527_Decode(u32 *out_addr, u8 *out_type)`:无线引脚 `P2.1` 边沿触发,捕获解密数据,解密成功后由主轮询捕获并 Push 对应的射频事件。
|
||||
* `void Event_Dispatcher_Loop(void)`:主循环轮询总线路由器,调用 `Event_Queue_Pop()` 并分发路由。
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **事件产生者 (Event Producer)**:物理按键 `KEY_UP` (P2.0), `KEY_DOWN` (P3.6), `KEY_CONFIRM` (P3.7), `KEY_SOS` (P2.3) 被按下触发低电平,按键模块负责将物理信号翻译为 `KeyEvent` 事件,并**推送到事件队列**中。
|
||||
1. **事件产生者 (Event Producer)**:物理按键 `KEY_UP` (P0.1), `KEY_DOWN` (P0.3), `KEY_CONFIRM` (P0.2), `KEY_SOS` (P2.6) 被按下触发低电平,按键模块负责定义物理端口输入并将物理信号翻译为 `KeyEvent` 事件。
|
||||
2. **移位消抖**:在 Timer1 10ms 中断分频中读取 IO 状态,连续 3 次检测一致则确认电平状态,过滤物理抖动。
|
||||
3. **推入事件队列**:当确认有物理键沿跳变时,调用 `Event_Queue_Push()` 将对应的 `KeyEvent` 压入独立的事件队列缓冲区中,避免因主逻辑繁忙丢失按键。
|
||||
4. **长短按时序**:确认键长按 3 秒产生 `KEY_CONFIRM_LONG`,▼ 键长按 2 秒产生 `KEY_DOWN_LONG`,SOS 键按下即刻产生最高优先级的 `KEY_SOS_ACTIVE` 抢占求救事件。
|
||||
4. **长短按时序**:确认键长按 3 秒产生长按事件,▼ 键长按 2 秒产生长按事件,SOS 键按下即刻产生最高优先级的 `KEY_SOS_ACTIVE` 抢占求救事件。
|
||||
|
||||
---
|
||||
|
||||
## 2. 接口与函数说明
|
||||
|
||||
* `void Key_Init(void)`:将 Pin 19, 20, 21, 24 配置为高阻输入并开启内部上拉电阻 (`P3PU |= 0xC0`, `P2PU |= 0x09`)。
|
||||
* `void Key_Init(void)`:将 Pin 30, 31, 32, 27 配置为高阻输入并开启内部上拉电阻 (`P0PU |= 0x0E`, `P2PU |= 0x40`)。
|
||||
* `void Key_Scan_Process(void)`:
|
||||
在 Timer1 的 10ms 定时周期中回调。
|
||||
* 读取 `KEY_UP`, `KEY_DOWN`, `KEY_CONFIRM`, `KEY_SOS` 引脚。
|
||||
@@ -23,4 +23,4 @@
|
||||
* `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 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V3 -->
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
## 2. 接口与函数说明
|
||||
|
||||
* `void LCD_Init(void)`:配置 Pin 9 到 Pin 14 的 SPI 通信总线引脚为推挽输出。拉高 `SHUT` 稳定后,向 RM69310 芯片写入初始化指令序列。
|
||||
* `void LCD_Init(void)`:配置 Pin 1 到 Pin 6 的 SPI 通信总线引脚为推挽输出。拉高 `SHUT` 稳定后,向 RM69310 芯片写入初始化指令序列。
|
||||
* `void LCD_SetWindow(u16 x1, u16 y1, u16 x2, u16 y2)`:设置局部像素写入视窗,自动执行 `+4` 偏置修正。
|
||||
* `void LCD_Clear(u16 color)`:用指定颜色刷满屏幕 GRAM。
|
||||
* `void LCD_ShowStringCentered(u16 y, char *str, u16 fc, u16 bc)`:居中渲染 16x32 大字符。
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* **职责范围**:
|
||||
1. **响应指示请求**:提供底层硬件 SPI 写接口,受前台应用(如对码指示)或后台警报进程的控制,点亮特定色彩。
|
||||
2. **隔离抗干扰时序**:
|
||||
WS2812B 的单线纳秒级控制数据流极易受到地线高频噪声干扰。在每次调用 `WS2812_WriteRGB` 之前,必须执行 **临时关闭全局中断 (EA=0) 并切换马达引脚 (P2.4) 为高阻输入** 状态,发送完毕后恢复 `EA=1`,以屏蔽共地杂噪。
|
||||
WS2812B 的单线纳秒级控制数据流极易受到地线高频噪声干扰。在每次调用 `WS2812_WriteRGB` 之前,必须执行 **临时关闭全局中断 (EA=0) 并切换马达引脚 (P2.5) 为高阻输入** 状态,发送完毕后恢复 `EA=1`,以屏蔽共地杂噪。
|
||||
3. **软件定时器异步更新**:
|
||||
提供 `LED_Flash_Process` 中断分频函数,由 Timer1 (1ms) 定期回调自增,以非阻塞方式改变闪烁标志电平,避免软件 `delay` 阻塞 CPU。
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
## 2. 接口与函数说明
|
||||
|
||||
* `void WS2812_Init(void)`:初始化物理引脚 `P2.6` (LED_RGB) 复用硬件 SPI 功能。
|
||||
* `void WS2812_Init(void)`:初始化物理引脚 `P2.3` (LED_RGB) 复用硬件 SPI 功能。
|
||||
* `void WS2812_WriteRGB(u8 l1_g, u8 l1_r, u8 l1_b, u8 l2_g, u8 l2_r, u8 l2_b)`:
|
||||
1. 保存并拉低 `EA = 0`。
|
||||
2. 临时设置马达控制脚 `P2.4` 为高阻输入。
|
||||
2. 临时设置马达控制脚 `P2.5` 为高阻输入。
|
||||
3. 通过 SPI 数据寄存器连续发送两个灯珠的 GRB 控制字节。
|
||||
4. 发送完毕后发出 >80us 低电平复位脉冲。
|
||||
5. 恢复马达引脚模式并还原 `EA`。
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
## 2. 接口与函数说明
|
||||
|
||||
* `void Motor_Init(void)`:配置 Pin 25 (`P2.4` / MOTOR_PWM) 为推挽输出,默认输出 `MOTOR_PWM = 0`。
|
||||
* `void Motor_Init(void)`:配置 Pin 26 (`P2.5` / MOTOR_PWM) 为推挽输出,默认输出 `MOTOR_PWM = 0`。
|
||||
* `void Motor_Start_Pattern(u8 pattern_type)`:传入震动节奏类型(按键微振/各防区警报震动/主动SOS循环震),装载维持时间片,开启异步状态机。
|
||||
* `void Motor_Pulse_Process(void)`:
|
||||
在 Timer1 的 10ms 中断分频中被调度调用。
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
* **职责范围**:
|
||||
1. **低功耗决策与断电**:
|
||||
当应用管理层判定 10 秒无按键且无无线事件时,PM 模块向 AMOLED 发送 Display OFF 命令,随后拉低 `SHUT = 0` (Pin 28 / P2.7),**彻底切断 SGM3833 供电**。
|
||||
当应用管理层判定 10 秒无按键且无无线事件时,PM 模块向 AMOLED 发送 Display OFF 命令,随后拉低 `SHUT = 0` (Pin 23 / P2.2),**彻底切断 SGM3833 供电**。
|
||||
2. **挂起 CPU (Power-Down)**:
|
||||
使能 GPIO 按键沿中断和无线接收 `P0.0` 沿中断,写入 `PCON |= 0x02` 关闭高频振荡器,使 MCU 进入深度停机挂起。
|
||||
使能 GPIO 按键沿中断和无线接收沿中断,写入 `PCON |= 0x02` 关闭高频振荡器,使 MCU 进入深度停机挂起。
|
||||
3. **防浪涌安全唤醒初始化**:
|
||||
发生中断唤醒后,PM 必须遵循安全上电时序:首先拉高 `SHUT = 1` 开启 SGM3833,随后**执行 50ms 强阻塞延时**避开冲击电流并等待电源轨稳定,最后调用 `LCD_Init()` 完整重新配置 RM69310 寄存器,方可恢复应用绘制。
|
||||
|
||||
@@ -16,12 +16,11 @@
|
||||
|
||||
## 2. 接口与函数说明
|
||||
|
||||
* `void Power_Init(void)`:配置 Pin 28 为推挽输出,默认 `SHUT = 1` 开启屏幕 PMIC。
|
||||
* `void Power_Init(void)`:配置 Pin 23 为推挽输出,默认 `SHUT = 1` 开启屏幕 PMIC。
|
||||
* `void Enter_Low_Power_Sleep(void)`:
|
||||
1. 向 RM69310 写入关屏指令 (0x28)。
|
||||
2. 拉低 `SHUT = 0` 关断 SGM3833 PMIC。
|
||||
3. 使能端口引脚沿中断 (P3.6/P3.7/P2.0/P2.3) 及 INT2 沿中断。
|
||||
4. 执行 `PCON |= 0x02` 进入停机模式。
|
||||
3. 使能端口引脚沿中断并进入 `PCON |= 0x02` 停机状态。
|
||||
* `void Wakeup_Restore(void)`:
|
||||
1. 拉高 `SHUT = 1` 重新开启 SGM3833。
|
||||
2. 执行 `delay_ms(50)` 硬件稳压阻塞等待。
|
||||
|
||||
@@ -5,18 +5,18 @@
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **事件产生者 (Event Producer)**:当物理引脚 `P0.0` (RF_RX_DATA) 沿中断触发,射频解调成功后,模块产生 `RF_EVENT_PAIR` (对码) 或 `RF_EVENT_ALARM` (报警) 并投递至系统事件总线。
|
||||
1. **事件产生者 (Event Producer)**:当物理引脚 `P2.1` (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 位状态数据码。
|
||||
3. **屏蔽接收 0x08 SOS 码**:手环被动接收到数据码为 `0x08` 的载波信号时,强制过滤忽略,不产生任何事件。仅保留主动向外界发射 `0x08` 求救码的能力。
|
||||
4. **主动发送驱动**:在应用层请求下,使能 `P0.1` (RF_TX) 和数据线 `P0.3` (RF_TX_DAT),连续发射多遍调制数据(如对码绑定 `0x01` 或求救包 `0x08`)。
|
||||
4. **主动发送驱动**:在应用层请求下,使能 `P2.0` (RF_TX) 和数据线 `P3.6` (RF_TX_DAT),连续发射多遍调制数据(如对码绑定 `0x01` 或求救包 `0x08`)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 接口与函数说明
|
||||
|
||||
* `void RF_Init(void)`:配置 `P0.0~P0.3` 物理引脚。使能接收控制 `RF_RX = 1`。使能引脚电平变化中断用于休眠唤醒。
|
||||
* `void RF_Init(void)`:配置 Pin 19, 20, 21, 22 物理引脚。使能接收控制 `RF_RX` (P3.7) = 1。使能引脚电平变化中断用于休眠唤醒。
|
||||
* `bit EV1527_Decode(u32 *out_addr, u8 *out_type)`:
|
||||
被主循环 `main.c` 轮询轮空调用。
|
||||
* 通过状态标志检测引脚跳变沿。
|
||||
@@ -24,4 +24,4 @@
|
||||
* `void EV1527_Transmit(u32 addr, u8 data_code)`:
|
||||
由主动发送 App 调度。产生前导头及 24 位电平时序。连续发送 5 遍,以确保 IPC 摄像头可靠捕获。
|
||||
|
||||
<!-- 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 -->
|
||||
|
||||
@@ -1,53 +1,36 @@
|
||||
# 模块拆分 - 系统状态机与 App 框架 (Docs/50_module-breakdown/mod-sys.md)
|
||||
# 模块拆分 - 系统初始化与 IAP 数据库 (Docs/50_module-breakdown/mod-sys.md)
|
||||
|
||||
本模块描述手环的 App 调度引擎(生命周期回调)以及 IAP 持久化防区数据库。
|
||||
本模块描述手环的系统基础时钟/中断配置、IAP 闪存数据库以及电池/充电硬件状态采样。
|
||||
|
||||
## 1. 模块职责说明
|
||||
|
||||
* **职责范围**:
|
||||
1. **维护 App 生命周期**:提供 `StartApp(app_id)` 和 `CloseApp(app_id)` 的系统级接口,调度应用层组件的切入与切出。
|
||||
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位物理与数据合并地址)。
|
||||
1. **系统外设与状态初始化**:配置初始时钟,使能全局中断,初始化基本寄存器状态。
|
||||
2. **ADC 电量与充电读取**:通过硬件 ADC 通道 8 (Pin 29 / `P0.0`) 采样电池电压,并读取充电检测引脚 (Pin 28 / `P2.7`) 判断 USB 是否正在充电。
|
||||
3. **Flash 数据库管理**:维护 `0xFE0000` (第 254 扇区) 物理闪存的读写擦除,管理 16 个已配对传感器的配置数据(含有效位 flags_suffix 及 EV1527 24位地址)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心结构体与接口定义
|
||||
|
||||
### 2.1 应用程序结构体原型 (WristbandApp)
|
||||
### 2.1 传感器存储插槽定义 (Sensor_Slot)
|
||||
```c
|
||||
typedef struct {
|
||||
u8 app_id; // 应用程序 ID
|
||||
void (*OnStart)(void); // 启动接口:渲染初始画面、装载应用资源
|
||||
void (*onRun)(void); // 循环接口:主循环轮空调用,执行非阻塞业务逻辑
|
||||
void (*onClose)(void); // 关闭接口:退出前台,保存状态、复位相关驱动
|
||||
void (*onEvent)(KeyEvent evt); // 事件处理:接收并消耗事件队列分配的按键/射频事件
|
||||
} WristbandApp;
|
||||
```
|
||||
typedef struct {
|
||||
u8 flags_suffix; // 属性字节:Bit 7 代表有效标志 (1: 有效, 0: 空闲);Bit 0~6 代表法语防区名称的后缀序号 (01~99)
|
||||
u8 addr[3]; // 24位射频物理地址 (EV1527 地址 + 4位状态数据码)
|
||||
} Sensor_Slot;
|
||||
|
||||
### 2.2 APP 管理器全局状态
|
||||
```c
|
||||
extern WristbandApp* active_app; // 指向当前前台活跃应用的指针
|
||||
extern u16 inactivity_timer; // 无操作自动睡眠计时器
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口与函数说明
|
||||
|
||||
* `void App_Manager_Init(void)`:注册所有支持的应用实例(待机时钟、主菜单、时间设置、对码、布撤防、主动SOS、被动报警),默认设置 `active_app` 指向时钟应用并执行 `active_app->OnStart()`。
|
||||
* `void StartApp(u8 app_id)`:
|
||||
1. 执行当前 `active_app->onClose()` 清理现场。
|
||||
2. 切换 `active_app` 指向目标 `app_id` 实例。
|
||||
3. 执行新应用的 `active_app->OnStart()`,并置 `Redraw = 1`。
|
||||
* `void System_Init(void)`:配置 STC32G 系统时钟与中断,初始化各外设模块的 GPIO 状态。
|
||||
* `void Load_Database(void)`:读取 `0xFE0000` 扇区,载入 16 组 `Sensor_Slot` 数据。
|
||||
* `void Save_Database(void)`:擦除 IAP 扇区并写回当前缓存的配对记录。
|
||||
* `void Add_Sensor(u32 addr, u8 suffix_idx)`:添加配对(保存物理地址与后缀序号)并持久化。
|
||||
* `void Save_Database(void)`:擦除 IAP 扇区并写回当前缓存 of 配对记录。
|
||||
* `void Add_Sensor_To_Flash(u32 addr, u8 flags_suffix)`:添加配对并写入闪存。
|
||||
* `bit Check_Sensor_ID(u32 addr, u8 *out_slot_index)`:在数据库中匹配已对码的传感器 ID,获取槽位。
|
||||
* `u8 Read_Battery_Percent(void)`:通过硬件 ADC 通道 8 (Pin 29 / `P0.0`) 采样计算当前电量。
|
||||
* `bit Is_Charging(void)`:读取检测引脚 (Pin 28 / `P2.7`) 判定 USB 是否正在充电。
|
||||
|
||||
<!-- 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 -->
|
||||
|
||||
126
Docs/60_coding/mod-app.md
Normal file
126
Docs/60_coding/mod-app.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 编码实现 - 应用执行与页面渲染 (Docs/60_coding/mod-app.md)
|
||||
|
||||
本文件对应手环前台 App 调度管理、活跃实例生命周期交互与各子应用页面像素级渲染的具体编码实现。
|
||||
|
||||
## 1. 对应代码源文件
|
||||
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (定义 App 数组、`StartApp` 生命周期函数、各子应用的 `OnStart` / `onRun` / `onClose` / `onEvent` 钩子回调)
|
||||
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (声明 `WristbandApp` 结构体原型及应用 ID 枚举)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 应用生命周期对象定义
|
||||
每个功能页面被抽象为结构体 `WristbandApp` 的实体实例,定义了完整的输入与输出操作回调:
|
||||
```c
|
||||
typedef struct {
|
||||
u8 app_id; // 应用程序 ID
|
||||
void (*OnStart)(void); // 启动回调:应用切入前台,加载资源、初始化显示
|
||||
void (*onRun)(void); // 循环回调:主循环轮询轮空调用,执行非阻塞业务逻辑
|
||||
void (*onClose)(void); // 关闭回调:应用退出前台,保存状态、清理外设
|
||||
void (*onEvent)(KeyEvent evt); // 事件回调:接收并消耗来自事件层的系统事件
|
||||
} WristbandApp;
|
||||
|
||||
#define APP_CLOCK 0
|
||||
#define APP_MENU 1
|
||||
#define APP_PAIR 2
|
||||
#define APP_ALARM 3
|
||||
#define APP_SOS 4
|
||||
|
||||
WristbandApp* active_app = NULL; // 当前前台活跃 App
|
||||
```
|
||||
|
||||
### 2.2 AppManager 调度执行引擎
|
||||
在主循环框架中,通过调用 `StartApp()` 执行非阻塞的前台应用切换:
|
||||
```c
|
||||
void StartApp(u8 app_id) {
|
||||
// 1. 切出当前活跃应用,释放资源并清理引脚状态
|
||||
if (active_app && active_app->onClose) {
|
||||
active_app->onClose();
|
||||
}
|
||||
|
||||
// 2. 指针重定向
|
||||
switch (app_id) {
|
||||
case APP_CLOCK: active_app = &App_Clock_Instance; break;
|
||||
case APP_MENU: active_app = &App_Menu_Instance; break;
|
||||
case APP_PAIR: active_app = &App_Pair_Instance; break;
|
||||
case APP_ALARM: active_app = &App_Alarm_Instance; break;
|
||||
case APP_SOS: active_app = &App_SOS_Instance; break;
|
||||
default: active_app = &App_Clock_Instance; break;
|
||||
}
|
||||
|
||||
// 3. 切入新应用前台,并强制标记 Redraw 触发 GRAM 刷新
|
||||
if (active_app && active_app->OnStart) {
|
||||
active_app->OnStart();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 待机大字时钟页面像素刷写 (ClockApp)
|
||||
在待机状态时,应用通过 LCD 驱动将 `32x64px` 居中字模刷写在屏幕的 Column [0, 119], Row [0, 239] 的 Column+4 窗口中:
|
||||
```c
|
||||
void UI_ShowClockPage(SystemState state, u8 hour, u8 min) {
|
||||
char time_str[6];
|
||||
char bat_str[10];
|
||||
u8 bat_val = Read_Battery_Percent(); // 读取 P0.0 ADC 数据进行百分比计算
|
||||
bit charging = Is_Charging(); // 读取 P2.7 数字 IO 输入
|
||||
|
||||
LCD_Clear(COLOR_BLACK);
|
||||
|
||||
// 1. 绘制顶部电量状态栏 (16x32px 标准无障碍字体)
|
||||
if (charging) {
|
||||
sprintf(bat_str, "%d%%+", (int)bat_val);
|
||||
LCD_ShowString(40, 20, bat_str, COLOR_GREEN, COLOR_BLACK);
|
||||
} else {
|
||||
sprintf(bat_str, "%d%%", (int)bat_val);
|
||||
LCD_ShowString(50, 20, bat_str, 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. 绘制底部系统布撤防锁状态 (32x32px 大图标)
|
||||
if (state == STATE_ARMED) {
|
||||
LCD_ShowImage(44, 180, 32, 32, bmp_lock_32x32, COLOR_RED, COLOR_BLACK);
|
||||
} else {
|
||||
LCD_ShowImage(44, 180, 32, 32, bmp_unlock_32x32, COLOR_GREEN, COLOR_BLACK);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 配对微调确认与保存页面交互 (PairApp)
|
||||
当捕获到新的 EV1527 对码信号时,`PairApp` 负责在 `onEvent` 钩子中接收微调的按键输入并保存至 Flash 数据库:
|
||||
```c
|
||||
void PairApp_onEvent(KeyEvent evt) {
|
||||
if (evt == KEY_EVENT_UP_CLICK) {
|
||||
// 短按 ▲ 键增加后缀序号
|
||||
if (selected_suffix < 99) {
|
||||
selected_suffix++;
|
||||
Redraw = 1;
|
||||
}
|
||||
}
|
||||
else if (evt == KEY_EVENT_DOWN_CLICK) {
|
||||
// 短按 ▼ 键减少后缀序号
|
||||
if (selected_suffix > 1) {
|
||||
selected_suffix--;
|
||||
Redraw = 1;
|
||||
}
|
||||
}
|
||||
else if (evt == KEY_EVENT_SOS_CLICK) {
|
||||
// 短按 ■ 确认键保存对码,数据格式 flags_suffix 位域重新分配
|
||||
// Bit 7: 有效位=1; Bit 0~6: 后缀序号
|
||||
u8 flags = 0x80 | (selected_suffix & 0x7F);
|
||||
|
||||
// 保存至持久化扇区
|
||||
Add_Sensor_To_Flash(captured_rf_addr, flags);
|
||||
|
||||
// 开启 300ms 成功振动反馈并退回时钟
|
||||
Motor_Start_Pattern(0); // 300ms 短振
|
||||
StartApp(APP_CLOCK);
|
||||
}
|
||||
else if (evt == KEY_EVENT_SOS_LONG) {
|
||||
// 长按 ■ 确认键 3 秒放弃保存并回退
|
||||
StartApp(APP_CLOCK);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,16 +1,99 @@
|
||||
# 编码实现 - 事件总线与缓冲路由 (Docs/60_coding/mod-event.md)
|
||||
# 编码实现 - 事件采集与总线路由器 (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` 枚举量定义)
|
||||
* [App/main.c](file:///c:/workfile/105/stc32g12k128/App/main.c) (按键消抖 `Key_Scan_Process`、事件队列及 `Event_Dispatcher_Loop` 分发逻辑)
|
||||
* [Drivers/rf.c](file:///c:/workfile/105/stc32g12k128/Drivers/rf.c) (配置 `P2.1` 输入捕捉及解码逻辑)
|
||||
* [App/config.h](file:///c:/workfile/105/stc32g12k128/App/config.h) (`KeyEvent` 核心事件枚举类型声明)
|
||||
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 环形队列定义与入队出队函数
|
||||
在 `main.c` 中,定义深度为 4 级的事件队列缓冲数组及读写位置指针:
|
||||
### 2.1 事件采集输入(按键定时扫描与消抖)
|
||||
定义按键 IO 宏,在 `Timer1` (10ms) 分频中读取并判定:
|
||||
```c
|
||||
sbit KEY_UP = P0^1; // Pin 30
|
||||
sbit KEY_CONFIRM = P0^2; // Pin 31
|
||||
sbit KEY_DOWN = P0^3; // Pin 32
|
||||
sbit KEY_SOS = P2^6; // Pin 27 (物理并联 SOS1/SOS2 按键)
|
||||
|
||||
void Key_Scan_Process(void) {
|
||||
static u8 key_up_state = 0xFF;
|
||||
static u8 key_down_state = 0xFF;
|
||||
static u8 key_confirm_state = 0xFF;
|
||||
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_sos_state = (key_sos_state << 1) | KEY_SOS;
|
||||
|
||||
// ▲ 键 (UP) 处理
|
||||
if ((key_up_state & 0x07) == 0) {
|
||||
key_up_hold++;
|
||||
} else {
|
||||
if (key_up_hold > 2) {
|
||||
Event_Queue_Push(KEY_EVENT_UP_CLICK);
|
||||
}
|
||||
key_up_hold = 0;
|
||||
}
|
||||
|
||||
// ▼ 键 (DOWN) 处理 (长按 2 秒退出或清除警报)
|
||||
if ((key_down_state & 0x07) == 0) {
|
||||
key_down_hold++;
|
||||
if (key_down_hold == 200) {
|
||||
Event_Queue_Push(KEY_EVENT_DOWN_LONG);
|
||||
}
|
||||
} else {
|
||||
if (key_down_hold > 2 && key_down_hold < 200) {
|
||||
Event_Queue_Push(KEY_EVENT_DOWN_CLICK);
|
||||
}
|
||||
key_down_hold = 0;
|
||||
}
|
||||
|
||||
// ■ 确认键 (CONFIRM) 处理 (长按 3 秒进入菜单,短按确认)
|
||||
if ((key_confirm_state & 0x07) == 0) {
|
||||
key_confirm_hold++;
|
||||
if (key_confirm_hold == 300) {
|
||||
Event_Queue_Push(KEY_EVENT_SOS_LONG); // 长按事件
|
||||
}
|
||||
} else {
|
||||
if (key_confirm_hold > 2 && key_confirm_hold < 300) {
|
||||
Event_Queue_Push(KEY_EVENT_SOS_CLICK); // 短击事件
|
||||
}
|
||||
key_confirm_hold = 0;
|
||||
}
|
||||
|
||||
// SOS 求救键 (下降沿低电平即刻触发)
|
||||
if ((key_sos_state & 0x07) == 0) {
|
||||
key_sos_hold++;
|
||||
if (key_sos_hold == 3) {
|
||||
Event_Queue_Push(KEY_SOS_ACTIVE); // 触发本地主动报警
|
||||
}
|
||||
} else {
|
||||
key_sos_hold = 0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 事件采集输入(射频数据解调)
|
||||
射频数据接收线连在 `P2.1`。当发生跳变时触发 INT2 外部沿中断:
|
||||
```c
|
||||
sbit RF_RX_DATA = P2^1; // Pin 22
|
||||
|
||||
bit EV1527_Decode(u32 *out_addr, u8 *out_type) {
|
||||
// 轮询或中断检测引脚 P2.1 沿变化
|
||||
// 自适应同步低电平 T = low_time / 31
|
||||
// 连续读取 24 位宽数据 (1:3 对应 0,3:1 对应 1)
|
||||
// 解密出地址和数据码,返回结果给事件总线
|
||||
// ...
|
||||
return 1;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 事件环形缓冲存储区
|
||||
```c
|
||||
#define EVENT_QUEUE_SIZE 4
|
||||
|
||||
@@ -19,70 +102,54 @@ 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; // 缓冲区溢出,写入失败
|
||||
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()` 中,系统定时轮询事件总线,读取事件并路由给前后台应用:
|
||||
### 2.4 事件输出路由路由器 (Event Dispatcher)
|
||||
在主循环 `while(1)` 内,系统以极速轮询该路由分发引擎:
|
||||
```c
|
||||
void Event_Dispatcher_Loop(void) {
|
||||
KeyEvent evt = Event_Queue_Pop();
|
||||
if (evt == KEY_EVENT_NONE) {
|
||||
return; // 队列为空,直接跳过
|
||||
return; // 无事件
|
||||
}
|
||||
|
||||
// 1. 优先判定物理抢占型事件 (如 SOS 键)
|
||||
// 1. 本地最高优先级强占处理
|
||||
if (evt == KEY_SOS_ACTIVE) {
|
||||
StartApp(APP_SOS); // 强行强占前台,启动紧急求救页面
|
||||
StartApp(APP_SOS); // 物理强制唤醒并抢占前台
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 无线报警事件路由给后台进程进行防区匹配
|
||||
// 2. 无线报警/配对包推送给后台守护进程
|
||||
if (evt == RF_EVENT_ALARM || evt == RF_EVENT_PAIR) {
|
||||
BgApp_Process_RF(evt); // 后台比对数据库,若匹配且在布防状态下,唤醒强占报警App
|
||||
BgApp_Process_RF(evt); // 后台比对 Flash 决定是否启动 APP_ALARM 报警页
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 常规按键事件分发给当前活跃的前台 APP
|
||||
// 3. 常规业务事件分发给前台活跃 APP
|
||||
if (active_app && active_app->onEvent) {
|
||||
active_app->onEvent(evt);
|
||||
}
|
||||
|
||||
@@ -146,4 +146,4 @@ void Process_System_Event(KeyEvent evt) {
|
||||
}
|
||||
```
|
||||
|
||||
<!-- 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 -->
|
||||
|
||||
@@ -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 V3 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V4 -->
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 驱动初始化与管脚分配
|
||||
WS2812B 输入脚接在单片机物理引脚 `LED_RGB` (`P2.6`):
|
||||
WS2812B 输入脚接在单片机物理引脚 `LED_RGB` (`P2.3`):
|
||||
```c
|
||||
sbit WS2812_DI = P2^6; // Pin 27
|
||||
sbit WS2812_DI = P2^3; // Pin 24
|
||||
|
||||
void WS2812_Init(void) {
|
||||
// P2.6 (LED_RGB) 配置为推挽输出,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 6);
|
||||
P2M0 |= (1 << 6);
|
||||
// P2.3 (LED_RGB) 配置为推挽输出,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 3);
|
||||
P2M0 |= (1 << 3);
|
||||
WS2812_DI = 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 驱动防噪声发送 (WS2812_Write24Bit)
|
||||
由于马达引脚占用 `P2.4` (Pin 25),为了规避马达震动时的共地杂噪,在串行输出数据期间关闭总中断并将马达引脚 `P2.4` 设为高阻输入。
|
||||
由于马达引脚占用 `P2.5` (Pin 26),为了规避马达震动时的共地杂噪,在串行输出数据期间关闭总中断并将马达引脚 `P2.5` 设为高阻输入。
|
||||
展宽 LUT 定义:
|
||||
```c
|
||||
const u16 code SPI_LUT[16] = {
|
||||
@@ -47,9 +47,9 @@ void WS2812_Write24Bit(u8 g, u8 r, u8 b) {
|
||||
|
||||
EA = 0; // 关中断保证串行传输的连续性
|
||||
|
||||
// 配置 P2.4 (MOTOR_PWM) 为高阻输入模式,屏蔽共地马达干扰
|
||||
P2M1 |= (1 << 4);
|
||||
P2M0 &= ~(1 << 4);
|
||||
// 配置 P2.5 (MOTOR_PWM) 为高阻输入模式,屏蔽共地马达干扰
|
||||
P2M1 |= (1 << 5);
|
||||
P2M0 &= ~(1 << 5);
|
||||
|
||||
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.4 (MOTOR_PWM) 为推挽输出,恢复马达控制
|
||||
P2M1 &= ~(1 << 4);
|
||||
P2M0 |= (1 << 4);
|
||||
// 恢复 P2.5 (MOTOR_PWM) 为推挽输出,恢复马达控制
|
||||
P2M1 &= ~(1 << 5);
|
||||
P2M0 |= (1 << 5);
|
||||
MOTOR = 0; // 确保马达断开
|
||||
|
||||
EA = 1; // 恢复中断
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 引脚控制宏与初始化
|
||||
马达由引脚 `P2.4` 控制。配置模式为推挽输出:
|
||||
马达由引脚 `P2.5` 控制。配置模式为推挽输出:
|
||||
```c
|
||||
sbit MOTOR = P2^4; // Pin 25
|
||||
sbit MOTOR = P2^5; // Pin 26
|
||||
|
||||
void Motor_Init(void) {
|
||||
// 将 P2.4 配置为推挽输出模式,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 4);
|
||||
P2M0 |= (1 << 4);
|
||||
// 将 P2.5 配置为推挽输出模式,默认输出低电平 0
|
||||
P2M1 &= ~(1 << 5);
|
||||
P2M0 |= (1 << 5);
|
||||
MOTOR = 0;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
## 2. 关键代码片段与逻辑实现
|
||||
|
||||
### 2.1 供电引脚初始化
|
||||
系统初始化时,配置 `SHUT`(控制 SGM3833 供电的引脚 `P2.7`)为推挽输出,并拉高以打开屏幕供电:
|
||||
系统初始化时,配置 `SHUT`(控制 SGM3833 供电的引脚 `P2.2`)为推挽输出,并拉高以开启屏幕供电:
|
||||
```c
|
||||
sbit SHUT = P2^7; // Pin 28
|
||||
sbit SHUT = P2^2; // Pin 23
|
||||
|
||||
void Power_Init(void) {
|
||||
// P2.7 (SHUT) 配置为推挽输出
|
||||
P2M1 &= ~(1 << 7);
|
||||
P2M0 |= (1 << 7);
|
||||
// P2.2 (SHUT) 配置为推挽输出
|
||||
P2M1 &= ~(1 << 2);
|
||||
P2M0 |= (1 << 2);
|
||||
|
||||
// 拉高引脚,开启 SGM3833 负压供电
|
||||
SHUT = 1;
|
||||
@@ -33,12 +33,12 @@ void Enter_Low_Power_Sleep(void) {
|
||||
// 2. 切断 SGM3833 电源,停止输出负压
|
||||
SHUT = 0;
|
||||
|
||||
// 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)
|
||||
// 3. 配置引脚中断 (P0.1, P0.2, P0.3, P2.6) 允许唤醒
|
||||
// 允许 P0 / P2 端口中断以供按键唤醒
|
||||
P0IM1 &= ~0x0E; P0IM0 &= ~0x0E; P0INTE |= 0x0E; // P0.1 (UP), P0.2 (CONFIRM), P0.3 (DOWN)
|
||||
P2IM1 &= ~0x40; P2IM0 &= ~0x40; P2INTE |= 0x40; // P2.6 (SOS)
|
||||
|
||||
// 4. 配置射频接收脚 P0.0 (RF_RX_DATA) 为 INT2/外部中断 2 唤醒
|
||||
// 4. 配置射频接收脚 P2.1 (RF_RX_DATA) 为 INT2/外部中断 2 唤醒
|
||||
EX2 = 1; // 使能外部中断2
|
||||
|
||||
// 5. 写入 PCON.1 使单片机进入 Power-Down 深度睡眠状态
|
||||
@@ -51,9 +51,9 @@ void Enter_Low_Power_Sleep(void) {
|
||||
### 2.3 中断唤醒与恢复 (Wakeup_Restore)
|
||||
当产生按键或射频中断后,单片机被唤醒,首先执行外部中断 ISR,退出低功耗并重新使能 OLED:
|
||||
```c
|
||||
// 外部中断服务子程序 (以按键 P3 端口中断为例)
|
||||
void Port3_Isr(void) interrupt 38 {
|
||||
P3INTF = 0x00; // 清除 P3 中断标志
|
||||
// 外部中断服务子程序 (以按键 P0 端口中断为例)
|
||||
void Port0_Isr(void) interrupt 37 {
|
||||
P0INTF = 0x00; // 清除 P0 中断标志
|
||||
Wakeup_Restore();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 V3 -->
|
||||
<!-- Checked and verified with SGM3833 boost/inverting PMIC removal and LCD_PWR_CTRL update changes V4 -->
|
||||
|
||||
@@ -73,12 +73,12 @@ u32 Get_Bracelet_Factory_ID(void) {
|
||||
```
|
||||
|
||||
### 2.4 电池采样与充电状态读取实现
|
||||
在系统模块中,通过硬件 ADC 通道 9 (P2.1) 和数字 I/O (P2.2) 采集电池状态:
|
||||
在系统模块中,通过硬件 ADC 通道 8 (P0.0) 和数字 I/O (P2.7) 采集电池状态:
|
||||
|
||||
1. **ADC 初始化 (ADC_Init)**:
|
||||
```c
|
||||
void ADC_Init(void) {
|
||||
P2M1 |= 0x02; P2M0 &= ~0x02; // P2.1 (Pin 22 / BAT_ADC) 配置为高阻输入 (模拟输入模式)
|
||||
P0M1 |= 0x01; P0M0 &= ~0x01; // P0.0 (Pin 29 / 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; // 开启电源并选择通道 (channel = 9 对应 P2.1)
|
||||
ADC_CONTR = 0x80 | channel; // 开启电源并选择通道 (channel = 8 对应 P0.0)
|
||||
_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(9); // 读取通道 9 (P2.1)
|
||||
u16 adc_val = Get_ADC_Result(8); // 读取通道 8 (P0.0)
|
||||
|
||||
// 线性百分比转换:3.3V (ADC=1279) 对应 0%, 4.2V (ADC=1628) 对应 100%
|
||||
if (adc_val <= 1279) {
|
||||
@@ -111,10 +111,10 @@ u8 Read_Battery_Percent(void) {
|
||||
|
||||
3. **充电状态读取**:
|
||||
```c
|
||||
// P2.2 (Pin 23 / DET) 在 System_Init 时需配置为高阻输入以进行充电状态检测
|
||||
// P2.7 (Pin 28 / DET) 在 System_Init 时需配置为高阻输入以进行充电状态检测
|
||||
bit Is_Charging(void) {
|
||||
return (P2 & (1 << 2)) ? 1 : 0; // 读取 P2.2 引脚高电平状态,1 表示 USB 接入
|
||||
return (P2 & (1 << 7)) ? 1 : 0; // 读取 P2.7 引脚高电平状态,1 表示 USB 接入
|
||||
}
|
||||
```
|
||||
|
||||
<!-- 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 -->
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
### 3.1 时钟待机与电量及充电状态验证
|
||||
* **测试方法**:
|
||||
1. 正常上电启动,查看待机界面右上方电量。
|
||||
2. 使用外部电压源微调电量采样引脚 **`P2.1`**(模拟输入)输入电压在 1.03V 到 1.31V 之间变化,检查电量百分比是否从 `0%` 线性平滑变化到 `100%`。
|
||||
3. 拔插 USB 充电器,或者直接改变引脚 **`P2.2`** 的电平输入,观察百分比数值后面是否能同步增加或移除 `+` 后缀(如在 `85%` 与 `85%+` 之间切换,且格式化与电池图标不贴连)。
|
||||
2. 使用外部电压源微调电量采样引脚 **`P0.0`**(模拟输入)输入电压在 1.03V 到 1.31V 之间变化,检查电量百分比是否从 `0%` 线性平滑变化到 `100%`。
|
||||
3. 拔插 USB 充电器,或者直接改变引脚 **`P2.7`** 的电平输入,观察百分比数值后面是否能同步增加或移除 `+` 后缀(如在 `85%` 与 `85%+` 之间切换,且格式化与电池图标对齐不贴连)。
|
||||
* **预期结果**:时钟、日期显示正常。在 **120 像素宽** AMOLED 屏幕上,电量百分比与电池图标(X=82, Y=27)对齐美观。在 USB 插入时电量后追加 `+` 后缀且能完整显示。
|
||||
|
||||
### 3.2 低功耗休眠与唤醒验证
|
||||
@@ -43,7 +43,7 @@
|
||||
1. 手环置于时钟待机状态下,静置 10 秒以上,观察系统状态。
|
||||
2. 按下侧边任意键,或者触发射频接收信号,观察系统状态。
|
||||
* **预期结果**:
|
||||
1. 静置 10 秒后,OLED 屏幕立刻完全黑屏,检测 `SHUT` (P2.7) 输出电平为低电平(0V),单片机电流降为微安级(Power-Down 挂起状态)。
|
||||
1. 静置 10 秒后,OLED 屏幕立刻完全黑屏,检测 `SHUT` (P2.2) 输出电平为低电平(0V),单片机电流降为微安级(Power-Down 挂起状态)。
|
||||
2. 短按侧边任意按键,或触发 433MHz 信号发射,手环应能被**瞬间唤醒**,`SHUT` 重新输出高电平(3.3V),AMOLED 重新点亮显示,无花屏或时钟错乱。
|
||||
|
||||
### 3.3 按键菜单交互与功能选择
|
||||
|
||||
Reference in New Issue
Block a user