Files
stc32g128k/Docs/30_architecture/wristband_architecture.html

1528 lines
76 KiB
HTML
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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>STC32G 手环核心系统架构设计交互分析器 (架构.odg)</title>
<!-- 引入 Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700&family=Noto+Sans+SC:wght@300;400;700&family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--bg-dark: #070b13;
--bg-card: rgba(17, 24, 39, 0.7);
--border-glass: rgba(255, 255, 255, 0.08);
--neon-cyan: #00f2fe;
--neon-pink: #ff007f;
--neon-blue: #3b82f6;
--neon-purple: #8b5cf6;
--neon-green: #10b981;
--neon-gold: #f59e0b;
--text-main: #f3f4f6;
--text-muted: #9ca3af;
--font-display: 'Outfit', 'Noto Sans SC', sans-serif;
--font-mono: 'Fira Code', monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: var(--bg-dark);
color: var(--text-main);
font-family: var(--font-display);
overflow-x: hidden;
background-image:
radial-gradient(at 10% 20%, rgba(59, 130, 246, 0.1) 0px, transparent 50%),
radial-gradient(at 90% 80%, rgba(139, 92, 246, 0.1) 0px, transparent 50%);
height: 100vh;
display: flex;
flex-direction: column;
}
/* 顶部导航 */
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: rgba(10, 15, 30, 0.8);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border-glass);
z-index: 100;
}
.logo-area {
display: flex;
align-items: center;
gap: 0.75rem;
}
.logo-icon {
width: 2.5rem;
height: 2.5rem;
background: linear-gradient(135deg, var(--neon-cyan), var(--neon-blue));
border-radius: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 15px rgba(0, 242, 254, 0.4);
font-weight: 700;
color: #000;
}
.logo-title h1 {
font-size: 1.25rem;
font-weight: 700;
background: linear-gradient(90deg, #fff, var(--text-muted));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.logo-title p {
font-size: 0.75rem;
color: var(--neon-cyan);
letter-spacing: 1px;
text-transform: uppercase;
}
.tab-menu {
display: flex;
gap: 1rem;
}
.tab-btn {
background: transparent;
border: 1px solid transparent;
color: var(--text-muted);
padding: 0.5rem 1.25rem;
border-radius: 2rem;
cursor: pointer;
font-family: var(--font-display);
font-weight: 600;
transition: all 0.3s ease;
}
.tab-btn.active {
color: var(--neon-cyan);
background: rgba(0, 242, 254, 0.08);
border-color: rgba(0, 242, 254, 0.3);
box-shadow: 0 0 15px rgba(0, 242, 254, 0.1);
}
.tab-btn:hover:not(.active) {
color: #fff;
background: rgba(255, 255, 255, 0.03);
}
/* 主体布局 */
main {
flex: 1;
display: flex;
overflow: hidden;
position: relative;
}
.content-panel {
flex: 1;
display: none;
padding: 1.5rem;
overflow-y: auto;
gap: 1.5rem;
}
.content-panel.active-panel {
display: flex;
}
/* ------------------ 架构拓扑面板样式 ------------------ */
#panel-topology {
flex-direction: row;
}
.diagram-container {
flex: 2;
position: relative;
background: rgba(10, 16, 32, 0.5);
border: 1px solid var(--border-glass);
border-radius: 1rem;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: space-around;
padding: 2.5rem 1rem 1rem 1rem;
}
.canvas-svg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1;
}
.layer-row {
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
z-index: 2;
position: relative;
padding: 0.9rem 0;
border-radius: 0.75rem;
background: rgba(255, 255, 255, 0.015);
border: 1px dashed rgba(255, 255, 255, 0.03);
margin-bottom: 0.5rem;
}
.layer-title-tag {
position: absolute;
left: 1.5rem;
top: -0.75rem;
background: #141f36;
border: 1px solid var(--border-glass);
padding: 0.2rem 0.75rem;
border-radius: 1rem;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.5px;
color: var(--text-muted);
}
.layer-row.apps-layer .layer-title-tag { color: var(--neon-cyan); border-color: rgba(0, 242, 254, 0.2); }
.layer-row.appmgr-layer .layer-title-tag { color: var(--neon-green); border-color: rgba(16, 185, 129, 0.2); }
.layer-row.event-layer .layer-title-tag { color: var(--neon-pink); border-color: rgba(255, 0, 127, 0.2); }
.layer-row.drivers-layer .layer-title-tag { color: var(--neon-purple); border-color: rgba(139, 92, 246, 0.2); }
.layer-row.hw-layer .layer-title-tag { color: var(--neon-gold); border-color: rgba(245, 158, 11, 0.2); }
.module-card {
background: var(--bg-card);
border: 1px solid var(--border-glass);
border-radius: 0.75rem;
padding: 0.6rem 1.1rem;
width: 8.5rem;
text-align: center;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
user-select: none;
backdrop-filter: blur(8px);
}
.module-card:hover {
transform: translateY(-3px);
border-color: rgba(255, 255, 255, 0.2);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
}
.module-card.selected-card {
background: rgba(0, 242, 254, 0.1);
border-color: var(--neon-cyan);
box-shadow: 0 0 20px rgba(0, 242, 254, 0.2);
}
.module-card.apps-node { border-left: 3px solid var(--neon-cyan); }
.module-card.appmgr-node { border-left: 3px solid var(--neon-green); }
.module-card.event-node { border-left: 3px solid var(--neon-pink); }
.module-card.drivers-node { border-left: 3px solid var(--neon-purple); }
.module-card.hw-node { border-left: 3px solid var(--neon-gold); }
.module-title {
font-size: 0.8rem;
font-weight: 700;
margin-bottom: 0.2rem;
}
.module-tag {
font-size: 0.6rem;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
/* 侧边信息抽屉 */
.info-sidebar {
flex: 1;
max-width: 25rem;
background: var(--bg-card);
border: 1px solid var(--border-glass);
border-radius: 1rem;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1.25rem;
backdrop-filter: blur(12px);
overflow-y: auto;
}
.sidebar-section h3 {
font-size: 0.9rem;
color: var(--neon-cyan);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 0.5rem;
border-left: 2px solid var(--neon-cyan);
padding-left: 0.5rem;
}
.sidebar-desc {
font-size: 0.85rem;
color: var(--text-muted);
line-height: 1.5;
}
.info-table {
width: 100%;
border-collapse: collapse;
font-size: 0.8rem;
margin-top: 0.5rem;
}
.info-table td {
padding: 0.4rem 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.info-table td.label-col {
color: var(--text-muted);
width: 35%;
}
.info-table td.value-col {
color: #fff;
font-weight: 600;
}
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
margin-top: 0.5rem;
}
.tag-badge {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-glass);
padding: 0.2rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.7rem;
color: var(--text-muted);
}
.tag-badge.active-rel {
background: rgba(0, 242, 254, 0.1);
border-color: rgba(0, 242, 254, 0.3);
color: var(--neon-cyan);
}
/* ------------------ 仿真模拟器面板样式 ------------------ */
#panel-simulator {
flex-direction: row;
}
.simulator-canvas {
flex: 2;
background: rgba(10, 16, 32, 0.5);
border: 1px solid var(--border-glass);
border-radius: 1rem;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1.5rem;
overflow: hidden;
position: relative;
}
.sim-triggers {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.sim-btn {
background: var(--bg-card);
border: 1px solid var(--border-glass);
padding: 0.75rem 1.25rem;
border-radius: 0.5rem;
color: #fff;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.5rem;
}
.sim-btn:hover {
border-color: var(--neon-cyan);
box-shadow: 0 0 15px rgba(0, 242, 254, 0.2);
transform: translateY(-2px);
}
.sim-btn.running {
background: rgba(255, 0, 127, 0.1);
border-color: var(--neon-pink);
box-shadow: 0 0 15px rgba(255, 0, 127, 0.2);
}
.sim-animation-viewport {
flex: 1;
border: 1px solid var(--border-glass);
border-radius: 0.75rem;
background: #0d1220;
position: relative;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.sim-console {
background: rgba(0, 0, 0, 0.4);
border: 1px solid var(--border-glass);
border-radius: 0.5rem;
padding: 0.75rem 1rem;
font-family: var(--font-mono);
font-size: 0.8rem;
color: var(--neon-green);
height: 8rem;
overflow-y: auto;
line-height: 1.6;
}
/* ------------------ 引脚配置面板样式 ------------------ */
#panel-pins {
flex-direction: row;
}
.pinout-container {
flex: 1.5;
background: rgba(10, 16, 32, 0.5);
border: 1px solid var(--border-glass);
border-radius: 1rem;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
/* 绘制 QFN-32 芯片的 CSS */
.qfn-package {
width: 22rem;
height: 22rem;
background: #111;
border: 4px solid #333;
border-radius: 1.5rem;
position: relative;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
}
.package-core {
width: 14rem;
height: 14rem;
border: 2px dashed #444;
border-radius: 0.5rem;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: #777;
font-size: 0.8rem;
font-weight: 700;
}
.package-core h2 {
font-size: 1rem;
color: #aaa;
margin-bottom: 0.25rem;
}
.pin-lead {
position: absolute;
background: #555;
transition: all 0.3s ease;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-family: var(--font-mono);
font-size: 0.65rem;
color: #ccc;
font-weight: 700;
}
.pin-lead:hover {
background: var(--neon-cyan);
color: #000;
box-shadow: 0 0 15px var(--neon-cyan);
z-index: 10;
}
.pin-lead.active-pin {
background: var(--neon-pink);
color: #000;
box-shadow: 0 0 15px var(--neon-pink);
z-index: 10;
}
/* QFN 4 边的引脚定位 */
/* Top side: Pin 25 to 32 */
.pin-t { width: 1.25rem; height: 1.5rem; top: -1.5rem; }
/* Bottom side: Pin 9 to 16 */
.pin-b { width: 1.25rem; height: 1.5rem; bottom: -1.5rem; }
/* Left side: Pin 1 to 8 */
.pin-l { width: 1.5rem; height: 1.25rem; left: -1.5rem; }
/* Right side: Pin 17 to 24 */
.pin-r { width: 1.5rem; height: 1.25rem; right: -1.5rem; }
/* ------------------ 分析报告面板样式 ------------------ */
#panel-report {
flex-direction: column;
max-width: 50rem;
margin: 0 auto;
}
.report-section {
background: var(--bg-card);
border: 1px solid var(--border-glass);
border-radius: 1rem;
padding: 2rem;
display: flex;
flex-direction: column;
gap: 1.25rem;
margin-bottom: 1.5rem;
}
.report-section h2 {
font-size: 1.25rem;
color: var(--neon-cyan);
border-bottom: 1px solid var(--border-glass);
padding-bottom: 0.5rem;
margin-bottom: 0.5rem;
}
.report-section p {
font-size: 0.9rem;
color: var(--text-muted);
line-height: 1.6;
}
.report-section ul {
list-style-type: none;
padding-left: 1rem;
}
.report-section li {
font-size: 0.9rem;
color: var(--text-muted);
line-height: 1.6;
margin-bottom: 0.5rem;
position: relative;
}
.report-section li::before {
content: "•";
color: var(--neon-cyan);
font-weight: bold;
display: inline-block;
width: 1em;
margin-left: -1em;
}
.code-box {
background: #080c14;
border: 1px solid var(--border-glass);
border-radius: 0.5rem;
padding: 1rem;
font-family: var(--font-mono);
font-size: 0.8rem;
color: #38bdf8;
overflow-x: auto;
line-height: 1.5;
}
/* SVG 连接线动画 */
.svg-path {
stroke: rgba(255, 255, 255, 0.08);
stroke-width: 2;
fill: none;
transition: all 0.3s ease;
}
.svg-path.active {
stroke: var(--neon-cyan);
stroke-width: 3;
stroke-dasharray: 6, 4;
animation: dash 10s linear infinite;
filter: drop-shadow(0 0 5px var(--neon-cyan));
}
.svg-path.active-pulse {
stroke: var(--neon-pink);
stroke-width: 3;
stroke-dasharray: 6, 4;
animation: dash-reverse 8s linear infinite;
filter: drop-shadow(0 0 5px var(--neon-pink));
}
@keyframes dash {
to {
stroke-dashoffset: -100;
}
}
@keyframes dash-reverse {
to {
stroke-dashoffset: 100;
}
}
/* 模拟器动画面板专用绘制 */
.bracelet-frame {
width: 10rem;
height: 18rem;
background: #111;
border: 4px solid #2c3e50;
border-radius: 1.5rem;
padding: 0.5rem;
display: flex;
flex-direction: column;
justify-content: space-between;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.7);
position: relative;
}
.bracelet-screen {
flex: 1;
background: #000;
border-radius: 0.75rem;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
border: 2px solid #222;
}
.bracelet-led {
width: 0.6rem;
height: 0.6rem;
background: #333;
border-radius: 50%;
margin: 0.2rem auto;
box-shadow: inset 0 1px 3px rgba(255,255,255,0.2);
transition: all 0.2s ease;
}
.bracelet-led.led-red {
background: #ff007f;
box-shadow: 0 0 15px #ff007f, 0 0 5px #ff007f;
}
.bracelet-led.led-green {
background: #00df89;
box-shadow: 0 0 15px #00df89, 0 0 5px #00df89;
}
.sim-step-indicator {
position: absolute;
bottom: 1.5rem;
left: 1.5rem;
right: 1.5rem;
background: rgba(0,0,0,0.85);
border: 1px solid var(--neon-cyan);
border-radius: 0.5rem;
padding: 0.75rem 1rem;
font-size: 0.85rem;
color: #fff;
display: none;
z-index: 10;
}
</style>
</head>
<body>
<!-- 顶部状态栏 -->
<header>
<div class="logo-area">
<div class="logo-icon">STC</div>
<div class="logo-title">
<h1>STC32G手环事件驱动APP系统交互分析器</h1>
<p>Architect-Level Event-Driven App-Framework Analyzer (架构.odg)</p>
</div>
</div>
<div class="tab-menu">
<button class="tab-btn active" onclick="switchTab('topology')">5层拓扑结构</button>
<button class="tab-btn" onclick="switchTab('simulator')">事件生命周期仿真</button>
<button class="tab-btn" onclick="switchTab('pins')">物理引脚映射</button>
<button class="tab-btn" onclick="switchTab('report')">核心原理说明</button>
</div>
</header>
<!-- 主分析工作区 -->
<main>
<!-- Tab 1: 5层拓扑结构面板 -->
<div id="panel-topology" class="content-panel active-panel">
<div class="diagram-container">
<svg id="svg-connections" class="canvas-svg"></svg>
<!-- 1. 应用业务层 (Applications) -->
<div class="layer-row apps-layer" id="layer-apps-row">
<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>
</div>
<div class="module-card apps-node" id="BgApp" onclick="selectModule('BgApp')">
<div class="module-title">BgApp</div>
<div class="module-tag">后台监测应用</div>
</div>
</div>
<!-- 2. 应用管理层 (APP Management) -->
<div class="layer-row appmgr-layer" id="layer-appmgr-row">
<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>
</div>
<div class="module-card appmgr-node" id="Lifecycle" onclick="selectModule('Lifecycle')">
<div class="module-title">Lifecycle</div>
<div class="module-tag">生命周期分配器</div>
</div>
</div>
<!-- 3. 事件总线与分配层 (Event & Dispatcher Layer) -->
<div class="layer-row event-layer" id="layer-event-row">
<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>
</div>
<div class="module-card event-node" id="EventDispatcher" onclick="selectModule('EventDispatcher')">
<div class="module-title">EventDispatcher</div>
<div class="module-tag">事件路由器</div>
</div>
</div>
<!-- 4. 中断与驱动层 (Drivers) -->
<div class="layer-row drivers-layer" id="layer-drivers-row">
<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>
</div>
<div class="module-card drivers-node" id="RF" onclick="selectModule('RF')">
<div class="module-title">RF (无线解码)</div>
<div class="module-tag">INT2 捕获/发送</div>
</div>
<div class="module-card drivers-node" id="Timer1" onclick="selectModule('Timer1')">
<div class="module-title">Timer1 (时基)</div>
<div class="module-tag">1ms 中断调度</div>
</div>
<div class="module-card drivers-node" id="LCD" onclick="selectModule('LCD')">
<div class="module-title">LCD DRV (屏幕)</div>
<div class="module-tag">RM69310 偏置写</div>
</div>
<div class="module-card drivers-node" id="LED" onclick="selectModule('LED')">
<div class="module-title">LED (幻彩灯)</div>
<div class="module-tag">WS2812B 驱动</div>
</div>
<div class="module-card drivers-node" id="MOTOR" onclick="selectModule('MOTOR')">
<div class="module-title">MOTOR (马达)</div>
<div class="module-tag">异步时序发生</div>
</div>
</div>
<!-- 5. 硬件实体层 (STC32 HW) -->
<div class="layer-row hw-layer" id="layer-hw-row">
<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>
</div>
</div>
</div>
<!-- 右侧信息抽屉 -->
<div class="info-sidebar" id="topology-sidebar">
<div class="sidebar-section">
<h3 id="info-title">选择架构模块</h3>
<p class="sidebar-desc" id="info-desc" style="margin-top: 0.5rem;">
点击左侧 5 层架构卡片,核对该模块在手环 APP 框架系统中的定位、输入与输出依赖、操作的代码源文件及底层逻辑机制。
</p>
</div>
<div id="info-details" style="display: none; display: flex; flex-direction: column; gap: 1rem;">
<div class="sidebar-section">
<h3>框架角色定位</h3>
<table class="info-table">
<tr>
<td class="label-col">物理/逻辑口:</td>
<td class="value-col" id="info-pin">N/A</td>
</tr>
<tr>
<td class="label-col">层级分类:</td>
<td class="value-col" id="info-level">应用层</td>
</tr>
<tr>
<td class="label-col">数据输入源:</td>
<td class="value-col" id="info-hwsource">事件分发器</td>
</tr>
</table>
</div>
<div class="sidebar-section">
<h3>代码实现位置</h3>
<p class="sidebar-desc" id="info-file" style="font-family: var(--font-mono); color: var(--neon-cyan);"></p>
</div>
<div class="sidebar-section">
<h3>输入关系流</h3>
<div class="tag-list" id="info-inputs"></div>
</div>
<div class="sidebar-section">
<h3>输出指令/事件</h3>
<div class="tag-list" id="info-outputs"></div>
</div>
<div class="sidebar-section">
<h3>架构师原理阐述</h3>
<p class="sidebar-desc" id="info-theory" style="font-size: 0.8rem; color: #cbd5e1;"></p>
</div>
</div>
</div>
</div>
<!-- Tab 2: 仿真模拟器面板 -->
<div id="panel-simulator" class="content-panel">
<div class="simulator-canvas">
<h2>基于事件流的手环运行周期仿真模拟</h2>
<p class="sidebar-desc">点击触发典型物理事件,观察信号如何流转,并在各个模块内被消费及回调:</p>
<div class="sim-triggers">
<button class="sim-btn" onclick="startSimulation('sos')">
<span style="display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--neon-pink);"></span>
1. 按下 SOS 键 (主动求救事件)
</button>
<button class="sim-btn" onclick="startSimulation('intrusion')">
<span style="display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--neon-gold);"></span>
2. 传感器入侵 (被动报警事件)
</button>
<button class="sim-btn" onclick="startSimulation('sleep')">
<span style="display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--neon-blue);"></span>
3. 10s 无按键 (自动休眠与安全唤醒)
</button>
</div>
<!-- 模拟动画区域 -->
<div class="sim-animation-viewport">
<div class="bracelet-frame">
<div class="bracelet-led" id="sim-led-1"></div>
<div class="bracelet-screen" id="sim-screen">
<span id="screen-text" style="font-size: 0.9rem; text-align: center; color: var(--text-muted);">STANDBY</span>
</div>
<div class="bracelet-led" id="sim-led-2"></div>
</div>
<!-- 动态状态提示框 -->
<div class="sim-step-indicator" id="sim-step-box">
步骤说明
</div>
</div>
<!-- 仿真控制台输出 -->
<div class="sim-console" id="sim-console">
[EVENT BUS] 事件总线就绪。等待输入事件触发...
</div>
</div>
</div>
<!-- Tab 3: 硬件引脚核对面板 -->
<div id="panel-pins" class="content-panel">
<div class="pinout-container">
<div class="qfn-package">
<div class="package-core">
<h2>STC32G12K128</h2>
<p>QFN-32 封装物理引脚图</p>
<p style="font-size: 0.65rem; color: #555; margin-top: 1rem;">点击引脚进行核对</p>
</div>
<!-- 左侧: 1-8 -->
<div class="pin-lead pin-l" style="top: 2rem;" onclick="selectPin('1')">1</div>
<div class="pin-lead pin-l" style="top: 4.2rem;" onclick="selectPin('2')">2</div>
<div class="pin-lead pin-l" style="top: 6.4rem;" onclick="selectPin('3')">3</div>
<div class="pin-lead pin-l" style="top: 8.6rem;" onclick="selectPin('4')">4</div>
<div class="pin-lead pin-l" style="top: 10.8rem;" onclick="selectPin('5')">5</div>
<div class="pin-lead pin-l" style="top: 13rem;" onclick="selectPin('6')">6</div>
<div class="pin-lead pin-l" style="top: 15.2rem;" onclick="selectPin('7')">7</div>
<div class="pin-lead pin-l" style="top: 17.4rem;" onclick="selectPin('8')">8</div>
<!-- 底侧: 9-16 -->
<div class="pin-lead pin-b" style="left: 2rem;" onclick="selectPin('9')">9</div>
<div class="pin-lead pin-b" style="left: 4.2rem;" onclick="selectPin('10')">10</div>
<div class="pin-lead pin-b" style="left: 6.4rem;" onclick="selectPin('11')">11</div>
<div class="pin-lead pin-b" style="left: 8.6rem;" onclick="selectPin('12')">12</div>
<div class="pin-lead pin-b" style="left: 10.8rem;" onclick="selectPin('13')">13</div>
<div class="pin-lead pin-b" style="left: 13rem;" onclick="selectPin('14')">14</div>
<div class="pin-lead pin-b" style="left: 15.2rem;" onclick="selectPin('15')">15</div>
<div class="pin-lead pin-b" style="left: 17.4rem;" onclick="selectPin('16')">16</div>
<!-- 右侧: 17-24 -->
<div class="pin-lead pin-r" style="bottom: 17.4rem;" onclick="selectPin('17')">17</div>
<div class="pin-lead pin-r" style="bottom: 15.2rem;" onclick="selectPin('18')">18</div>
<div class="pin-lead pin-r" style="bottom: 13rem;" onclick="selectPin('19')">19</div>
<div class="pin-lead pin-r" style="bottom: 10.8rem;" onclick="selectPin('20')">20</div>
<div class="pin-lead pin-r" style="bottom: 8.6rem;" onclick="selectPin('21')">21</div>
<div class="pin-lead pin-r" style="bottom: 6.4rem;" onclick="selectPin('22')">22</div>
<div class="pin-lead pin-r" style="bottom: 4.2rem;" onclick="selectPin('23')">23</div>
<div class="pin-lead pin-r" style="bottom: 2rem;" onclick="selectPin('24')">24</div>
<!-- 顶侧: 25-32 -->
<div class="pin-lead pin-t" style="right: 17.4rem;" onclick="selectPin('25')">25</div>
<div class="pin-lead pin-t" style="right: 15.2rem;" onclick="selectPin('26')">26</div>
<div class="pin-lead pin-t" style="right: 13rem;" onclick="selectPin('27')">27</div>
<div class="pin-lead pin-t" style="right: 10.8rem;" onclick="selectPin('28')">28</div>
<div class="pin-lead pin-t" style="right: 8.6rem;" onclick="selectPin('29')">29</div>
<div class="pin-lead pin-t" style="right: 6.4rem;" onclick="selectPin('30')">30</div>
<div class="pin-lead pin-t" style="right: 4.2rem;" onclick="selectPin('31')">31</div>
<div class="pin-lead pin-t" style="right: 2rem;" onclick="selectPin('32')">32</div>
</div>
</div>
<!-- 引脚信息抽屉 -->
<div class="info-sidebar" id="pin-sidebar">
<div class="sidebar-section">
<h3 id="pin-title">引脚核对清单</h3>
<p class="sidebar-desc" id="pin-desc">
点击 QFN-32 封装芯片引脚,获取其在 Kicad 原理图中的 Net 网线标号、物理外设连接以及在 Drivers 中具体的软件操作细节。
</p>
</div>
<div id="pin-details" style="display: none; display: flex; flex-direction: column; gap: 1rem;">
<div class="sidebar-section">
<h3>物理引脚定义</h3>
<table class="info-table">
<tr>
<td class="label-col">引脚号:</td>
<td class="value-col" id="pin-num-val">Pin 1</td>
</tr>
<tr>
<td class="label-col">GPIO端口:</td>
<td class="value-col" id="pin-mcu-val" style="font-size: 0.75rem;">P1.0</td>
</tr>
<tr>
<td class="label-col">网络标号:</td>
<td class="value-col" id="pin-net-val" style="color: var(--neon-cyan);">TXD</td>
</tr>
<tr>
<td class="label-col">控制配置:</td>
<td class="value-col" id="pin-mode-val">推挽输出</td>
</tr>
</table>
</div>
<div class="sidebar-section">
<h3>电气物理连接</h3>
<p class="sidebar-desc" id="pin-hw-desc"></p>
</div>
<div class="sidebar-section">
<h3>驱动层软件操作</h3>
<p class="sidebar-desc" id="pin-sw-desc" style="font-family: var(--font-mono); color: var(--neon-purple);"></p>
</div>
</div>
</div>
</div>
<!-- Tab 4: 架构分析说明面板 -->
<div id="panel-report" class="content-panel">
<div class="report-section">
<h2>1. 基于 架构.odg 的事件驱动 APP 框架层级关系</h2>
<p>
本工程手环固件采用 **事件驱动式的 App 生命周期框架**Event-Driven App-Framework。整个软件系统划分为五个层级
</p>
<ul>
<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>
<div class="report-section">
<h2>2. 活跃应用与后台应用的生命周期回调关系</h2>
<p>
为了在有限内存的 8051 架构上提供多页面交互,各个 App 具有极简的声明周期钩子:
</p>
<div class="code-box">
typedef struct {
u8 app_id; // 应用程序 ID
void (*OnStart)(void); // 启动:渲染初始页面
void (*onRun)(void); // 循环:主循环轮空调用,执行非阻塞业务
void (*onClose)(void); // 关闭:清理外设(如强制停振、关屏)
void (*onEvent)(KeyEvent evt); // 事件:读取并消费对应事件
} WristbandApp;</div>
<p>
当发生应用切换如对码成功返回时钟或者超时自动休眠APP 管理器通过调用原 App 的 `onClose()` 并调用新 App 的 `OnStart()`,能够以极其干净的方式清空定时器、马达振动、彩灯时序状态,避免不同业务状态之间的时序冲突。
</p>
</div>
<div class="report-section">
<h2>3. 自适应无线解调事件产生机制</h2>
<p>
无线射频解码采用非阻塞中断比值测量法:
</p>
<p>
当 LR690L 在天线收到脉冲时,引脚 P0.0 的电平沿触发 INT2 外部中断。RF 驱动测量低电平前导脉冲宽度,若落在 1500us~60000us 内则被确认为合法的同步头,并反算基准时基 T=low_time/31。
</p>
<p>
随后在接收循环中,基于 T 的宽度自适应滤出 24 位 EV1527 二进制序列1:3 宽为 0 码3:1 宽为 1 码),并将其封装为 `RF_PAIR_EVENT` 或 `RF_ALARM_EVENT` 压入环形缓冲区,不阻塞主时钟。
</p>
</div>
</div>
</main>
<!-- JS 逻辑控制 -->
<script>
// TAB 切换
function switchTab(tabId) {
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelectorAll('.content-panel').forEach(panel => panel.classList.remove('active-panel'));
event.currentTarget.classList.add('active');
document.getElementById('panel-' + tabId).classList.add('active-panel');
if (tabId === 'topology') {
setTimeout(drawConnections, 100);
}
}
// 模块细节定义 (数据驱动 - 符合5层架构)
const modulesData = {
ActiveApp: {
title: "ActiveApp (前台活跃应用)",
pin: "无物理引脚 (处于应用业务层)",
level: "5. 应用业务层 (Applications)",
hwsource: "App 管理生命周期注册",
file: "App/main.c (WristbandApp 实体实例)",
inputs: ["AppManager (被调用生命周期 OnStart/onRun/onClose/onEvent)"],
outputs: ["LCD (调用显示)", "LED / MOTOR (调用声光报警)"],
theory: "前台活跃应用代表当前手环屏幕呈现的业务(如 ClockApp, MenuApp, PairApp。它在 OnStart 中刷写页面,在 onRun 中非阻塞检查超时,并在 onEvent 中处理按键事件逻辑。"
},
BgApp: {
title: "BgApp (后台监测应用)",
pin: "无物理引脚 (处于应用业务层)",
level: "5. 应用业务层 (Applications)",
hwsource: "App 管理器后台轮询",
file: "App/main.c (系统后台守护线程)",
inputs: ["EventDispatcher (接收对码/报警事件)"],
outputs: ["AppManager (当处于布防且匹配防区报警时抢占启动警报App)"],
theory: "后台应用常驻内存,主要任务是监听无线事件。当 EventDispatcher 路由了配对防区的传感器报警包时若系统处于布防状态BgApp 将唤醒并命令 AppManager 强制开启警报页面 (APP_ALARM)。"
},
AppManager: {
title: "AppManager (APP 管理器)",
pin: "无物理引脚",
level: "4. 应用管理层 (APP Management)",
hwsource: "App 业务层逻辑跳转",
file: "App/main.c (StartApp / CloseApp)",
inputs: ["ActiveApp (页面返回请求)", "BgApp (强制报警抢占)"],
outputs: ["Lifecycle (驱动钩子回调)"],
theory: "管理各个 WristbandApp 实例的入口与出口。执行 StartApp时调度关闭旧 App执行 onClose 停振关灯),重新挂接 active_app 指针并执行新 App 的 OnStart() 初始化。"
},
Lifecycle: {
title: "Lifecycle (生命周期调度机)",
pin: "无物理引脚",
level: "4. 应用管理层 (APP Management)",
hwsource: "AppManager",
file: "App/main.c (回调指针分发)",
inputs: ["AppManager"],
outputs: ["ActiveApp (驱动 App 状态转换)"],
theory: "生命周期分配器是 App 框架运行的动力源。它控制当前活跃 App 的 `onRun` 能够在主循环中不断被轮空调用,以及 `onEvent` 能够读取缓冲区的按键动作。"
},
EventQueue: {
title: "EventQueue (事件环形队列)",
pin: "无物理引脚 (软件 FIFO 缓冲)",
level: "3. 事件总线与分配层 (Event & Dispatcher Layer)",
hwsource: "KEY / RF 中断驱动打包推送",
file: "App/main.c (key_event_buf)",
inputs: ["KEY (压入按键)", "RF (压入射频对码/报警)"],
outputs: ["EventDispatcher (弹出并分发)"],
theory: "深度为 4 级的环形事件队列。底层中断驱动可在任何时刻异步 Push 事件入队;主循环定时 Pop 弹出事件。这是解耦底层中断与上层应用的关键缓冲,保证在高频通信下按键动作不会遗漏。"
},
EventDispatcher: {
title: "EventDispatcher (事件路由器)",
pin: "无物理引脚",
level: "3. 事件总线与分配层 (Event & Dispatcher Layer)",
hwsource: "EventQueue 队列输出",
file: "App/main.c (事件分发逻辑)",
inputs: ["EventQueue (读取待分发事件)"],
outputs: ["Lifecycle (分发至活跃App)", "BgApp (路由无线警报)"],
theory: "读取环形事件队列。识别事件类型按键事件KEY_EVENT分发给 `active_app->onEvent()` 消费;对码/无线入侵事件RF_EVENT分发给后台应用 `BgApp` 进行防区比对。"
},
KEY: {
title: "KEY (按键外部中断与消抖)",
pin: "Pin 19 (P3.6), Pin 20 (P3.7), Pin 21 (P2.0), Pin 24 (P2.3)",
level: "高阻输入 + 使能内部上拉",
hwsource: "物理侧边按键及上部 SOS 求救按键",
file: "App/main.c (Key_Scan_Process)",
inputs: ["MCU (引脚电平中断沿)"],
outputs: ["EventQueue (Key_Push_Event 压入队列)"],
theory: "通过 10ms 中断进行移位滤波扫描。支持 SW3 长按 3 秒产生主菜单调用事件、SW1+SW2 组合对码长按等。识别完毕后,将按键事件压入 EventQueue。"
},
RF: {
title: "RF (LR690L 编解码驱动)",
pin: "Pin 29 (P0.0), Pin 30 (P0.1), Pin 31 (P0.2), Pin 32 (P0.3)",
level: "INT2 中断输入 / 其余IO推挽输出",
hwsource: "LR690L 433MHz 射频前端芯片",
file: "Drivers/rf.c, Drivers/rf.h",
inputs: ["MCU (INT2 电平变化中断唤醒)"],
outputs: ["EventQueue (压入射频报警/对码事件)", "MCU (P0.3 输出电平发射数据)"],
theory: "外部沿中断触发同步头自适应比值解调:解调 24 位 EV1527 码包。主动发射时开启 RF_TX通过 GPIO 串行驱动 RF_TX_DAT 引脚高低电平,发送 5 遍。屏蔽忽略被动 0x08 码求救广播。"
},
Timer1: {
title: "Timer1 (定时器中断时基)",
pin: "单片机内部 16位 定时器 1",
level: "2. 中断与驱动层 (Drivers)",
hwsource: "MCU 24MHz 晶振时钟源",
file: "App/main.c (Timer1_Isr)",
inputs: ["MCU (内部主频脉冲)"],
outputs: ["KEY (10ms时基触发)", "MOTOR (分频异步计数)", "LED (闪烁时序分频)"],
theory: "系统软件时基源。每 1ms 产生一次中断。它在 ISR 中直接调度按键移位扫描10ms、马达异步状态时间递减、幻彩 LED 闪烁状态的扣减,是多外设并发的基础。"
},
LCD: {
title: "LCD DRV (Truly 屏幕绘制)",
pin: "Pin 9-14 (P5.4-P3.1 SPI控制总线)",
level: "2. 中断与驱动层 (Drivers)",
hwsource: "Truly 0.95寸 AMOLED 屏 (RM69310)",
file: "Drivers/lcd.c, Drivers/lcd.h",
inputs: ["ActiveApp (重绘渲染指令)"],
outputs: ["MCU (写 SPI 数据寄存器)"],
theory: "提供无障碍大字号32x64px、位图图标、居中排版清屏。写 GRAM 局部视窗自动强制加上 `+4` 像素硬件物理偏置,以防花屏和漏绘。"
},
LED: {
title: "LED (WS2812B 幻彩级联驱动)",
pin: "Pin 27 (P2.6 / LED_RGB 控制脚)",
level: "2. 中断与驱动层 (Drivers)",
hwsource: "WS2812B 级联双彩色灯",
file: "App/main.c (WS2812_WriteRGB)",
inputs: ["ActiveApp (指示灯亮起请求)", "Timer1 (闪烁维持计数)"],
outputs: ["MCU (SPI_MOSI 引脚输出)"],
theory: "WS2812B 发送前关闭全局中断并临时将马达脚P2.4)置为高阻,彻底隔离噪声,发送 24-bit 占空比数据。提供异步闪烁线程更新控制字。"
},
MOTOR: {
title: "MOTOR (马达异步震动驱动)",
pin: "Pin 25 (P2.4 / MOTOR_PWM 脚)",
level: "2. 中断与驱动层 (Drivers)",
hwsource: "振动马达驱动晶体管",
file: "App/main.c (Motor_Start_Pattern)",
inputs: ["ActiveApp (按键反馈/告警指令)", "Timer1 (1ms分频状态处理)"],
outputs: ["MCU (P2.4 输出高低电平)"],
theory: "异步脉冲发生提供按键微震、各种防区节奏报警震动、SOS持续间歇振动。APP 调用后立即退出,由 Timer1 自动扣减时间改变电平状态,不阻塞系统运行。"
},
MCU: {
title: "STC32G MCU (单片机寄存器物理层)",
pin: "Pin 1-32",
level: "1. 硬件实体层 (STC32 HW)",
hwsource: "物理硬件芯片",
file: "Drivers/stc32g.h (底层寄存器声明)",
inputs: ["外部物理信号沿跳变 / 电池电压"],
outputs: ["物理端口电平控制信号"],
theory: "硬件层。包括 P0/P1/P2/P3/P5 端口寄存器、INT2 中断控制器、IAP Flash 控制器、12位 ADC 转换内核以及 PCON 电源控制寄存器。"
}
};
// 选中某个模块卡片
function selectModule(modId) {
// 清理旧选中状态
document.querySelectorAll('.module-card').forEach(card => card.classList.remove('selected-card'));
// 设为新选中
const card = document.getElementById(modId);
if (card) card.classList.add('selected-card');
// 填充右侧细节
const data = modulesData[modId];
if (data) {
document.getElementById('info-title').innerText = data.title;
document.getElementById('info-pin').innerText = data.pin;
document.getElementById('info-level').innerText = data.level;
document.getElementById('info-hwsource').innerText = data.hwsource;
document.getElementById('info-file').innerText = data.file;
document.getElementById('info-theory').innerText = data.theory;
// 输入列表
const inList = document.getElementById('info-inputs');
inList.innerHTML = '';
data.inputs.forEach(inp => {
const span = document.createElement('span');
span.className = 'tag-badge active-rel';
span.innerText = inp;
inList.appendChild(span);
});
// 输出列表
const outList = document.getElementById('info-outputs');
outList.innerHTML = '';
data.outputs.forEach(out => {
const span = document.createElement('span');
span.className = 'tag-badge';
span.innerText = out;
outList.appendChild(span);
});
document.getElementById('info-desc').style.display = 'none';
document.getElementById('info-details').style.display = 'flex';
}
// 联动高亮 SVG 连线
highlightLines(modId);
}
// SVG 连接配置关系 (5层架构依赖流向)
const connections = [
{ from: 'MCU', to: 'KEY', color: 'gold' },
{ from: 'MCU', to: 'RF', color: 'gold' },
{ from: 'MCU', to: 'Timer1', color: 'gold' },
{ from: 'Timer1', to: 'KEY', color: 'purple' },
{ from: 'Timer1', to: 'LED', color: 'purple' },
{ from: 'Timer1', to: 'MOTOR', color: 'purple' },
{ from: 'KEY', to: 'EventQueue', color: 'pink' },
{ from: 'RF', to: 'EventQueue', color: 'pink' },
{ from: 'EventQueue', to: 'EventDispatcher', color: 'pink' },
{ from: 'EventDispatcher', to: 'Lifecycle', color: 'green' },
{ from: 'EventDispatcher', to: 'BgApp', color: 'cyan' },
{ from: 'BgApp', to: 'AppManager', color: 'green' },
{ from: 'AppManager', to: 'Lifecycle', color: 'green' },
{ from: 'Lifecycle', to: 'ActiveApp', color: 'cyan' },
{ from: 'ActiveApp', to: 'LCD', color: 'purple' },
{ from: 'ActiveApp', to: 'LED', color: 'purple' },
{ from: 'ActiveApp', to: 'MOTOR', color: 'purple' },
{ from: 'LCD', to: 'MCU', color: 'gold' },
{ from: 'LED', to: 'MCU', color: 'gold' },
{ from: 'MOTOR', to: 'MCU', color: 'gold' }
];
// 动态绘制连接线 (SVG)
function drawConnections() {
const svg = document.getElementById('svg-connections');
if (!svg) return;
svg.innerHTML = ''; // 清空
const containerRect = svg.getBoundingClientRect();
connections.forEach((conn, index) => {
const fromEl = document.getElementById(conn.from);
const toEl = document.getElementById(conn.to);
if (fromEl && toEl) {
const r1 = fromEl.getBoundingClientRect();
const r2 = toEl.getBoundingClientRect();
// 计算相对 SVG 的中心坐标
const x1 = r1.left + r1.width / 2 - containerRect.left;
const y1 = r1.top + r1.height / 2 - containerRect.top;
const x2 = r2.left + r2.width / 2 - containerRect.left;
const y2 = r2.top + r2.height / 2 - containerRect.top;
// 绘制贝塞尔三次曲线获得优雅的流线效果
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
const dy = Math.abs(y2 - y1);
const controlY1 = y1 + (y2 > y1 ? dy * 0.45 : -dy * 0.45);
const controlY2 = y2 - (y2 > y1 ? dy * 0.45 : -dy * 0.45);
const d = `M ${x1} ${y1} C ${x1} ${controlY1}, ${x2} ${controlY2}, ${x2} ${y2}`;
path.setAttribute('d', d);
path.setAttribute('class', 'svg-path');
path.setAttribute('id', `conn-${conn.from}-${conn.to}`);
// 根据类型初始透明配色
if (conn.color === 'cyan') {
path.style.stroke = 'rgba(0, 242, 254, 0.15)';
} else if (conn.color === 'green') {
path.style.stroke = 'rgba(16, 185, 129, 0.15)';
} else if (conn.color === 'pink') {
path.style.stroke = 'rgba(255, 0, 127, 0.15)';
} else if (conn.color === 'purple') {
path.style.stroke = 'rgba(139, 92, 246, 0.15)';
} else {
path.style.stroke = 'rgba(245, 158, 11, 0.15)';
}
svg.appendChild(path);
}
});
}
// 高亮相关连线
function highlightLines(selectedModId) {
// 首先全部暗淡
document.querySelectorAll('.svg-path').forEach(p => {
p.classList.remove('active');
p.style.strokeWidth = '2';
if (p.id.includes('ActiveApp') || p.id.includes('BgApp')) {
p.style.stroke = 'rgba(0, 242, 254, 0.15)';
} else if (p.id.includes('AppManager') || p.id.includes('Lifecycle')) {
p.style.stroke = 'rgba(16, 185, 129, 0.15)';
} else if (p.id.includes('EventQueue') || p.id.includes('EventDispatcher')) {
p.style.stroke = 'rgba(255, 0, 127, 0.15)';
} else if (p.id.includes('Timer1') || p.id.includes('KEY') || p.id.includes('RF')) {
p.style.stroke = 'rgba(139, 92, 246, 0.15)';
} else {
p.style.stroke = 'rgba(245, 158, 11, 0.15)';
}
});
// 寻找连接到该模块的连线并高亮
connections.forEach(conn => {
if (conn.from === selectedModId || conn.to === selectedModId) {
const path = document.getElementById(`conn-${conn.from}-${conn.to}`);
if (path) {
path.classList.add('active');
path.style.stroke = 'var(--neon-cyan)';
path.style.strokeWidth = '3';
}
}
});
}
window.addEventListener('resize', drawConnections);
window.addEventListener('load', () => {
setTimeout(drawConnections, 200);
});
// ------------------ 引脚配置交互数据 ------------------
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=0x40Timer1 中断中以 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=0x08Timer1 中断检测 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 码脉冲。" }
};
function selectPin(pinNum) {
// 清理旧高亮
document.querySelectorAll('.pin-lead').forEach(lead => lead.classList.remove('active-pin'));
// 设为新高亮
const el = document.querySelector(`.pin-lead[onclick="selectPin('${pinNum}')"]`);
if (el) el.classList.add('active-pin');
const info = pinsInfo[pinNum];
if (info) {
document.getElementById('pin-num-val').innerText = "Pin " + pinNum;
document.getElementById('pin-mcu-val').innerText = info.mcu;
document.getElementById('pin-net-val').innerText = info.net;
document.getElementById('pin-mode-val').innerText = info.mode;
document.getElementById('pin-hw-desc').innerText = info.hw;
document.getElementById('pin-sw-desc').innerText = info.sw;
document.getElementById('pin-desc').style.display = 'none';
document.getElementById('pin-details').style.display = 'flex';
} else {
document.getElementById('pin-num-val').innerText = "Pin " + pinNum;
document.getElementById('pin-mcu-val').innerText = "N/A";
document.getElementById('pin-net-val').innerText = "NC (悬空未连接)";
document.getElementById('pin-mode-val').innerText = "高阻抗模式";
document.getElementById('pin-hw-desc').innerText = "该引脚在原理图中属于 NC 状态,无任何物理走线,配置为高阻输入以防引入寄生耦合和杂散电流漏电。";
document.getElementById('pin-sw-desc').innerText = "N/A";
document.getElementById('pin-desc').style.display = 'none';
document.getElementById('pin-details').style.display = 'flex';
}
}
// ------------------ 业务流仿真器逻辑 ------------------
let simInterval = null;
function appendConsole(text) {
const consoleBox = document.getElementById('sim-console');
consoleBox.innerHTML += `<br>[EVENT BUS] ${text}`;
consoleBox.scrollTop = consoleBox.scrollHeight;
}
function clearConsole() {
document.getElementById('sim-console').innerHTML = '[EVENT BUS] 物理输入事件已捕获,进入事件流周期...';
}
function showStep(text) {
const stepBox = document.getElementById('sim-step-box');
stepBox.style.display = 'block';
stepBox.innerText = text;
}
function stopSimulationVisuals() {
if (simInterval) clearInterval(simInterval);
document.getElementById('sim-led-1').className = 'bracelet-led';
document.getElementById('sim-led-2').className = 'bracelet-led';
document.getElementById('sim-screen').style.background = '#000';
document.getElementById('screen-text').innerText = "STANDBY";
document.getElementById('screen-text').style.color = '#777';
document.getElementById('sim-step-box').style.display = 'none';
document.querySelectorAll('.sim-btn').forEach(b => b.classList.remove('running'));
}
function startSimulation(type) {
stopSimulationVisuals();
clearConsole();
// 标记运行按钮
event.currentTarget.classList.add('running');
let step = 0;
if (type === 'sos') {
appendConsole("物理源Pin 24 (KEY_SOS) 瞬间拉低。");
simInterval = setInterval(() => {
step++;
if (step === 1) {
showStep("1. [Drivers Layer] KEY 定时器扫描:检测到 P2.3 低电平,移位判定消抖成立。");
appendConsole("驱动层:检测到 SOS 按下。封包 KeyEvent = KEY_SOS_ACTIVE。");
} else if (step === 2) {
showStep("2. [Event Layer] 事件总线:将 KEY_SOS_ACTIVE 压入 4 级 EventQueue 环形缓冲区。");
appendConsole("事件层:调用 Key_Push_Event 将事件压入 EventQueue尾指针 tail 偏移。");
} else if (step === 3) {
showStep("3. [APP Management] 应用管理器:主循环读出该事件,判断属于最高优先级强占。");
appendConsole("管理层Pop 读出 SOS 求救。执行 StartApp(APP_SOS)。当前 App 强制调用 onClose()。");
} else if (step === 4) {
showStep("4. [Applications] 活跃应用切换SOS 报警应用切入前台,触发 OnStart() 接口。");
document.getElementById('sim-screen').style.background = '#ff007f';
document.getElementById('screen-text').innerText = "SOS EMIS\n(ACTIVE APP)";
document.getElementById('screen-text').style.color = '#fff';
appendConsole("业务层APP_SOS 前台运行,调用 LCD、WS2812B 驱动及马达异步长震指令。");
} else if (step === 5) {
showStep("5. [Drivers -> HW] 驱动执行与物理输出RF 发射 Factory ID 载波WS2812B 交替闪烁。");
// 闪烁彩灯
let flashCount = 0;
const flashInterval = setInterval(() => {
if (flashCount > 8) {
clearInterval(flashInterval);
return;
}
const led1 = document.getElementById('sim-led-1');
const led2 = document.getElementById('sim-led-2');
if (flashCount % 2 === 0) {
led1.className = 'bracelet-led led-red';
led2.className = 'bracelet-led';
} else {
led1.className = 'bracelet-led';
led2.className = 'bracelet-led led-red';
}
flashCount++;
}, 200);
appendConsole("驱动物理输出:开启 P0.1 发射P0.3 数据翻转WS2812 发送前关中断防马达杂讯干扰。");
} else if (step === 6) {
showStep("6. [Loop Phase] 异步轮询APP_SOS 维持在前台。射频每 2s 周期发射求救包,直至侧边按键退出。");
appendConsole("周期流转:系统处于 APP_SOS 的 onRun 状态轮询,等待事件队列接收按键复位。");
clearInterval(simInterval);
document.querySelectorAll('.sim-btn').forEach(b => b.classList.remove('running'));
}
}, 1500);
} else if (type === 'intrusion') {
appendConsole("物理源:天线捕获 433MHz 载波沿Pin 29 (RF_RX_DATA) 触发中断。");
simInterval = setInterval(() => {
step++;
if (step === 1) {
showStep("1. [Drivers Layer] INT2 外部沿中断触发RF 解调驱动实时自适应比值还原 24 位地址与状态。");
appendConsole("驱动层INT2 中断触发。自适应解出 EV1527 地址: 0xA3F21B, 状态: 0x01 (门磁动作)。");
} else if (step === 2) {
showStep("2. [Event Layer] 事件分发:解调算法验证通过,将 RF_ALARM_EVENT 事件派送给后台监测应用。");
appendConsole("事件层:将包含匹配信息的射频事件路由发送至后台监测应用 BgApp。");
} else if (step === 3) {
showStep("3. [Applications] 后台应用比对BgApp 读出地址,比对 Flash 数据库匹配为配对槽位,处于布防。");
appendConsole("业务层BgApp 匹配 IAP 扇区 Slot0 (PORTE)。检测到布防状态,调用 AppManager 启动报警。");
} else if (step === 4) {
showStep("4. [APP Management] 应用管理器强占AppManager 挂起当前活跃应用,调用 StartApp(APP_ALARM)。");
appendConsole("管理层StartApp 运行。旧 App onClose新 App (APP_ALARM) 调用 OnStart()。");
} else if (step === 5) {
showStep("5. [Applications -> Drivers] 报警应用前台亮屏,渲染门磁入侵字样;调度 LED 专属颜色及马达差异震动。");
document.getElementById('sim-led-1').className = 'bracelet-led led-green';
document.getElementById('sim-led-2').className = 'bracelet-led led-green';
document.getElementById('sim-screen').style.background = '#0f172a';
document.getElementById('screen-text').innerText = "PORTE 01\nINTRUSION!";
document.getElementById('screen-text').style.color = '#ff007f';
appendConsole("业务层APP_ALARM 重绘屏幕LCD 执行 X+4 窗口偏置Timer1 中断在后台自减计时器驱动马达短震。");
} else if (step === 6) {
showStep("6. [Loop Phase] 系统挂起警告:报警状态处于当前活跃状态,主循环周期轮询 onRun声光异步时序运转。");
appendConsole("周期流转:系统处于 APP_ALARM 活跃状态等待处理。");
clearInterval(simInterval);
document.querySelectorAll('.sim-btn').forEach(b => b.classList.remove('running'));
}
}, 1500);
} else if (type === 'sleep') {
appendConsole("物理状态待机正常无按键无线天线无信号inactivity_timer 累加。");
simInterval = setInterval(() => {
step++;
if (step === 1) {
showStep("1. [Applications Layer] 自动休眠判定ActiveApp 在 onRun 轮询中检查发现闲置已满 1000 滴答。");
appendConsole("业务层:时钟应用闲置满 10 秒。主动向系统投递休眠请求事件 AUTO_SLEEP_EVENT。");
} else if (step === 2) {
showStep("2. [APP Management] 关闭活跃 AppAppManager 触发当前时钟应用的 onClose() 接口,清空显示。");
document.getElementById('sim-screen').style.background = '#000';
document.getElementById('screen-text').innerText = "";
document.getElementById('sim-led-1').className = 'bracelet-led';
document.getElementById('sim-led-2').className = 'bracelet-led';
appendConsole("管理层AppManager 执行 active_app->onClose(),关断屏幕 GRAM 写入。");
} else if (step === 3) {
showStep("3. [Drivers -> HW] 切断 PMIC 双电源PM 驱动拉低 P2.7 (SHUT=0),完全断开 SGM3833 电源。");
appendConsole("驱动层PM 写入 P2.7=0SGM3833 关闭,彻底消除 Truly AMOLED 暗漏电流。");
} else if (step === 4) {
showStep("4. [HW Layer] 停机休眠:配置 GPIO 按键沿及无线接收引脚为唤醒源,写入 PCON |= 0x02 进入深度睡眠。");
appendConsole("硬件层MCU 核心挂起,系统晶振停振,全系统耗电降至微安级。");
} else if (step === 5) {
showStep("5. [Wakeup sequence] 外部唤醒与安全上电按键按下触发外部中断唤醒系统PM 优先拉高 SHUT=1。");
appendConsole("硬件层唤醒PM 拉高 P2.7 (SHUT=1) 开启 SGM3833 供电。");
} else if (step === 6) {
showStep("6. [HW -> Drivers -> Apps] 强延时 50ms 避浪涌:强行阻塞延时稳压,重配置 RM69310 亮起时钟应用。");
document.getElementById('sim-screen').style.background = '#0f172a';
document.getElementById('screen-text').innerText = "10:35\nRESTORED";
document.getElementById('screen-text').style.color = '#00f2fe';
appendConsole("唤醒链条:强延时 50ms 避开冲击浪涌 -> 重调 LCD_Init 写入指令 -> StartApp(APP_CLOCK) 恢复大字时钟。");
clearInterval(simInterval);
document.querySelectorAll('.sim-btn').forEach(b => b.classList.remove('running'));
}
}, 1500);
}
}
</script>
</body>
</html>