Files
stc32g128k/Docs/30_architecture/wristband_architecture.html

1523 lines
74 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 手环核心系统架构设计交互分析器</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: 2rem 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: 1rem 0;
border-radius: 0.75rem;
background: rgba(255, 255, 255, 0.01);
border: 1px dashed rgba(255, 255, 255, 0.03);
}
.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.app-layer .layer-title-tag { color: var(--neon-cyan); border-color: rgba(0, 242, 254, 0.2); }
.layer-row.drv-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.75rem 1.25rem;
width: 9rem;
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.app-node { border-left: 3px solid var(--neon-cyan); }
.module-card.drv-node { border-left: 3px solid var(--neon-purple); }
.module-card.hw-node { border-left: 3px solid var(--neon-gold); }
.module-title {
font-size: 0.85rem;
font-weight: 700;
margin-bottom: 0.2rem;
}
.module-tag {
font-size: 0.65rem;
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.8);
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手环系统核心架构交互分析器</h1>
<p>Architect-Level Interactive Architecture Analyzer</p>
</div>
</div>
<div class="tab-menu">
<button class="tab-btn active" onclick="switchTab('topology')">层级拓扑关系</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: 架构拓扑面板 -->
<div id="panel-topology" class="content-panel active-panel">
<div class="diagram-container">
<svg id="svg-connections" class="canvas-svg"></svg>
<!-- APP 逻辑层 -->
<div class="layer-row app-layer" id="layer-app-row">
<span class="layer-title-tag">应用逻辑层 (APP Layer) - 事件循环与状态流转</span>
<div class="module-card app-node" id="MainScheduler" onclick="selectModule('MainScheduler')">
<div class="module-title">MainScheduler</div>
<div class="module-tag">主循环调度</div>
</div>
<div class="module-card app-node" id="SysStateMachine" onclick="selectModule('SysStateMachine')">
<div class="module-title">SysStateMachine</div>
<div class="module-tag">核心业务状态机</div>
</div>
<div class="module-card app-node" id="SoftRTC" onclick="selectModule('SoftRTC')">
<div class="module-title">SoftRTC</div>
<div class="module-tag">软件计时器</div>
</div>
</div>
<!-- DRV 外设驱动层 -->
<div class="layer-row drv-layer" id="layer-drv-row">
<span class="layer-title-tag">外设驱动层 (DRV Layer) - 底层驱动与硬件隔离</span>
<div class="module-card drv-node" id="KEY" onclick="selectModule('KEY')">
<div class="module-title">KEY</div>
<div class="module-tag">消抖与事件队列</div>
</div>
<div class="module-card drv-node" id="RF" onclick="selectModule('RF')">
<div class="module-title">RF</div>
<div class="module-tag">LR690L 编解码</div>
</div>
<div class="module-card drv-node" id="PM" onclick="selectModule('PM')">
<div class="module-title">PM</div>
<div class="module-tag">极低功耗管理</div>
</div>
<div class="module-card drv-node" id="AMOLED" onclick="selectModule('AMOLED')">
<div class="module-title">AMOLED</div>
<div class="module-tag">Truly 屏幕渲染</div>
</div>
<div class="module-card drv-node" id="LED" onclick="selectModule('LED')">
<div class="module-title">LED</div>
<div class="module-tag">WS2812B 幻彩</div>
</div>
<div class="module-card drv-node" id="MOTOR" onclick="selectModule('MOTOR')">
<div class="module-title">MOTOR</div>
<div class="module-tag">马达异步震动</div>
</div>
</div>
<!-- HW 硬件抽象层 -->
<div class="layer-row hw-layer" id="layer-hw-row">
<span class="layer-title-tag">硬件抽象与时基层 (HW Layer) - 底层外设控制器</span>
<div class="module-card hw-node" id="Timer1" onclick="selectModule('Timer1')">
<div class="module-title">Timer1</div>
<div class="module-tag">1ms 中断时基</div>
</div>
<div class="module-card hw-node" id="GPIO" onclick="selectModule('GPIO')">
<div class="module-title">GPIO</div>
<div class="module-tag">数字输入输出</div>
</div>
<div class="module-card hw-node" id="ADC" onclick="selectModule('ADC')">
<div class="module-title">ADC</div>
<div class="module-tag">12位电压采集</div>
</div>
<div class="module-card hw-node" id="Flash" onclick="selectModule('Flash')">
<div class="module-title">Flash</div>
<div class="module-tag">IAP 扇区存取</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;">
点击左侧架构卡片,查看模块的输入/输出关系、底层引脚映射、驱动代码位置及架构原理解释。
</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">P0.0</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>
上部紧急按键触发 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>
已配对防区传感器入侵报警
</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>
无按键 10 秒超时自动休眠
</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">
[SYSTEM] 模拟器就绪,等待触发...
</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>
<!-- 引脚布局 (32引脚 + EP) -->
<!-- 左侧: 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">
点击芯片封装上的物理引脚号,可查询对应的 STC32G 引脚名、PCB 原理图网络标号、所连接的硬件模块及关联的代码控制位置。
</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">芯片引脚名称:</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. 核心架构设计思想:单向依赖与分层抽象</h2>
<p>
手环固件基于经典的 **三层单向依赖架构**APP层 -> DRV层 -> HW层进行设计
</p>
<ul>
<li><strong>硬件隔离</strong>:不允许应用层代码绕过驱动去改变硬件寄存器。所有的引脚操作都封装在 DRV 层内。这为手环的软硬件升级(如屏幕升级、传感器类型增加)提供了极佳的移植性。</li>
<li><strong>单向无环依赖</strong>:数据的向上汇报只能通过全局变量/事件队列异步进行,应用层向下发起硬件动作通过高级函数 API 进行,避免了组件之间的紧耦合与死锁。</li>
</ul>
</div>
<div class="report-section">
<h2>2. 高可靠性按键环形事件缓冲队列 (Ring Buffer)</h2>
<p>
为了避免用户在快速点击或同时按下多个按键时发生丢键KEY 驱动中建立了一个深度为 4 级的环形事件队列。
</p>
<div class="code-box">
#define KEY_BUF_SIZE 4
volatile KeyEvent key_event_buf[KEY_BUF_SIZE];
volatile u8 key_buf_head = 0;
volatile u8 key_buf_tail = 0;
bit Key_Push_Event(KeyEvent evt) {
u8 next = (key_buf_head + 1) % KEY_BUF_SIZE;
if (next != key_buf_tail) { // 队列未满
key_event_buf[key_buf_head] = evt;
key_buf_head = next;
return 1;
}
return 0; // 溢出丢弃
}</div>
<p>
Timer 1 中断(每 10ms 扫描消抖一次)把有效的短按、长按事件直接 `Push` 进入队列;主循环在空闲时通过 `Pop` 处理并重置队列,从而彻底消除了阻塞死等消抖(如 `while(key==0)`)的低效设计。
</p>
</div>
<div class="report-section">
<h2>3. 报警指示非阻塞异步时序设计</h2>
<p>
由于马达震动(例如 300ms和 LED 闪烁是长达数百毫秒的时序动作,如果采用软件阻塞延时(如 `delay_ms(300)`),主循环将完全卡死,无法处理 LR690L 433MHz 高频射频接收。
</p>
<p>
手环将马达和 LED 动作拆分为多个维持电平段,在 Timer1 的时钟中断中不断自减维持时间,当计数归零时自动切换引脚状态:
</p>
<div class="code-box">
// MOTOR 异步闪烁时序示例 (在 10ms 中断服务中调用)
void Motor_Pulse_Process(void) {
if (motor_timer > 0) {
motor_timer--;
if (motor_timer == 0) {
// 切换马达引脚电平,进入下一阶段
MOTOR_PIN = !MOTOR_PIN;
// 根据特定的震动波形重新装填 motor_timer
}
}
}</div>
</div>
<div class="report-section">
<h2>4. 安全唤醒重初始化时序</h2>
<p>
手环在低功耗休眠时,为了消除 Truly AMOLED 屏幕的暗漏电流,使用 `P2.7`SGM3833 PMIC 使能脚)切断了 OLED 屏幕的逻辑及负压电源供电。
</p>
<p>
在被外部中断(按键按下或 LR690L 接收沿)瞬间唤醒后,由于电源滤波电容充电需要时间,电网在最初的几十毫秒是不稳定的。因此,唤醒后**严禁立即进行写屏操作**,必须遵循严格的唤醒初始化序列:
</p>
<ul>
<li>1. 唤醒 CPU立即拉高 `SHUT = 1` 使能 SGM3833 启动。</li>
<li>2. **软件强行阻塞延时延时 50ms**,保证电压完全稳定并避开浪涌冲击电流。</li>
<li>3. 重新对 RM69310 屏幕控制器写入全套初始化指令配置(建立 SPI 像素写通道)。</li>
<li>4. 触发屏幕重绘,亮起时钟页。</li>
</ul>
</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);
}
}
// 模块细节定义 (数据驱动)
const modulesData = {
MainScheduler: {
title: "MainScheduler (主循环调度器)",
pin: "无物理引脚 (软件纯逻辑)",
level: "N/A",
hwsource: "CPU 核心控制器",
file: "App/main.c",
inputs: ["KEY (环形事件队列)", "RF (433MHz数据包)"],
outputs: ["SysStateMachine (事件分发)", "GPIO (定时喂看门狗)"],
theory: "主程序采用解耦的时间片轮询结构。主循环是非阻塞的,主要任务是周期性读取按键队列、射频解码状态,当有事件到达时调用状态机。其余时间喂狗防卡死。"
},
SysStateMachine: {
title: "SysStateMachine (业务状态机)",
pin: "无物理引脚 (软件状态变量)",
level: "N/A",
hwsource: "系统内存状态变量",
file: "App/main.c",
inputs: ["MainScheduler (分配出的KeyEvent/RFEvent)"],
outputs: ["AMOLED (触发重绘)", "LED (彩灯警示)", "MOTOR (马达震动)", "PM (睡眠判定)", "Flash (对码保存)", "RF (发射求救/对码)"],
theory: "驱动核心 10 个 SystemState 状态迁移,是系统业务大脑。根据当前状态和输入事件,决定外设输出动作,并管理 IAP Flash 存储读写请求。"
},
SoftRTC: {
title: "SoftRTC (软件时钟计时器)",
pin: "无物理引脚",
level: "N/A",
hwsource: "Timer1 时钟分频器",
file: "App/main.c",
inputs: ["Timer1 (秒分频中断)"],
outputs: ["AMOLED (待机大字时钟渲染)"],
theory: "基于 Timer 1 中断分频得到的高可靠时钟累加器,维护时、分、秒、年、月、日。常态待机下提供大字时钟及日期的文字渲染源。"
},
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: ["GPIO (引脚电平电平扫描)"],
outputs: ["MainScheduler (通过环形队列写入)"],
theory: "由 Timer1 (10ms) 定时触发消抖扫描。通过移位寄存器滤波3次结果一致才有效。支持双 SOS 键的并联电气逻辑。支持按键的长短按检测,并将 KeyEvent 压入环形队列防丢。"
},
RF: {
title: "RF (LR690L 433MHz 编解码)",
pin: "Pin 29 (P0.0), Pin 30 (P0.1), Pin 31 (P0.2), Pin 32 (P0.3)",
level: "P0.0中断输入 / 其余IO输出",
hwsource: "LR690L 射频前端芯片",
file: "Drivers/rf.c, Drivers/rf.h",
inputs: ["GPIO (INT2 沿中断捕获同步头)"],
outputs: ["MainScheduler (被动接收报警)", "GPIO (主动发射数据线)"],
theory: "自适应时间比值解调机制:首先利用计数过滤 >1500us 的同步低电平前导头,计算时钟基准 T=low_time/31。按 1:3 对应 0 码3:1 对应 1 码自适应解出 24 位 EV1527 载波。主动发射时,重复发射 5 遍防止射频碰撞。"
},
PM: {
title: "PM (极低功耗电源管理)",
pin: "Pin 28 (P2.7 / SHUT 控制脚)",
level: "推挽输出",
hwsource: "SGM3833 AMOLED PMIC 供电使能",
file: "App/main.c (Low_Power_Sleep)",
inputs: ["SysStateMachine (休眠判定)"],
outputs: ["GPIO (控制 SHUT=0 关闭电源 / PCON|=0x02 进入深度睡眠)"],
theory: "在连续 10 秒无操作后PM 先向屏幕发送关闭指令,随后将 P2.7 (SHUT) 拉低,彻底切断 Truly OLED 显示供电,避免负压漏电。最后开启 GPIO 口变化中断,将 MCU 挂起Power-Down 极低功耗模式)。"
},
AMOLED: {
title: "AMOLED (屏幕局部绘制驱动)",
pin: "Pin 9-14 (P5.4-P3.1 SPI控制总线)",
level: "推挽输出",
hwsource: "Truly 0.95寸 120x240 AMOLED 屏 (RM69310)",
file: "Drivers/lcd.c, Drivers/lcd.h",
inputs: ["SysStateMachine (重绘渲染请求)"],
outputs: ["GPIO (SPI 控制线像素刷写)"],
theory: "提供高效 SPI 屏刷指令。核心在于 X 坐标 +4 像素物理偏置修正(物理 GRAM 起始偏置。并实现了无障碍大字号32x64px时钟、大图标渲染以及水平居中排版公式。"
},
LED: {
title: "LED (WS2812B RGB 灯珠时序)",
pin: "Pin 27 (P2.6 / LED_RGB 控制脚)",
level: "SPI MOSI 硬件复用输出",
hwsource: "WS2812B 级联双彩灯珠",
file: "App/main.c (LED_Flash_Process)",
inputs: ["Timer1 (闪烁定时)", "SysStateMachine (设置颜色请求)"],
outputs: ["GPIO (SPI_MOSI 硬件引脚数据流)"],
theory: "利用硬件 SPI 控制 WS2812B 单线纳秒级数据时序。为了防止马达动作引入高频地线杂讯影响灯时序,每次写灯前将临时执行关全局中断 (EA=0) 并切换马达脚为高阻输入以隔离干扰。"
},
MOTOR: {
title: "MOTOR (马达非阻塞震动控制)",
pin: "Pin 25 (P2.4 / MOTOR_PWM 脚)",
level: "推挽输出",
hwsource: "振动马达驱动电路",
file: "App/main.c (Motor_Pulse_Process)",
inputs: ["Timer1 (时序递减分频)", "SysStateMachine (加载震动类型)"],
outputs: ["GPIO (P2.4 高低电平输出)"],
theory: "完全非阻塞异步设计。报警的长振或多脉冲震动,全部分解为在 1ms 中断里递减的毫秒计数值。APP 层在加载震动模式后立即退出,绝不卡死 CPU实现高效并发运行。"
},
Timer1: {
title: "Timer1 (1ms 定时中断时基)",
pin: "芯片内部硬件定时器 1",
level: "N/A",
hwsource: "24MHz 主时钟分频",
file: "App/main.c (Timer1_Isr)",
inputs: ["GPIO (系统主时钟时源)"],
outputs: ["KEY (10ms触发)", "MOTOR (脉冲递减)", "LED (闪烁更新)", "SoftRTC (秒累加)"],
theory: "系统最底层的心跳时基。通过配置 STC 内部寄存器,每 1ms 产生一次定时器 3 中断。是马达异步波形、彩灯闪烁、按键移位消抖和软件 RTC 时钟生存的绝对基础。"
},
GPIO: {
title: "GPIO (数字输入输出端口)",
pin: "QFN-32 引脚 1-32",
level: "推挽输出 / 高阻输入等可配置模式",
hwsource: "单片机物理引脚控制寄存器",
file: "Drivers/stc32g.h (硬件寄存器映射)",
inputs: ["物理输入电平沿变化 (按键/射频沿)"],
outputs: ["外设物理驱动信号"],
theory: "硬件最底层通道。STC32G 每个引脚都支持四种模式(准双向、推挽输出、高阻输入、开漏)。配置 GPIO 能够控制电路通断、输出通信数据流,并充当停机模式下的中断唤醒源。"
},
ADC: {
title: "ADC (12位电量电压采样)",
pin: "Pin 22 (P2.1 / ADC9通道)",
level: "模拟输入",
hwsource: "手环电池分压监测线",
file: "App/main.c (Read_Battery_Percent)",
inputs: ["GPIO (外部电压模拟输入)"],
outputs: ["SysStateMachine (返回0-100%电量数据)"],
theory: "利用单片机内部 12 位高速逐次逼近型 ADC。对电池采样引脚进行多次读取并取均值滤波。匹配 1.03V 到 1.31V 物理输入线性映射为电池 0%~100% 格式百分比输出。"
},
Flash: {
title: "Flash (IAP 内部数据保存)",
pin: "芯片内置 Flash 空间 (第 254 扇区)",
level: "N/A",
hwsource: "0xFE0000 扇区物理闪存",
file: "App/main.c (IAP_Write / Save_Database)",
inputs: ["SysStateMachine (保存对码防区请求)"],
outputs: ["SysStateMachine (上电载入 16 组传感器配置)"],
theory: "利用 STC 内部 IAP (In-Application Programming) 功能在程序运行中擦写 Flash。将已配对的 24 位传感器地址、传感器类型、防区类别及法语前缀序号持久化,掉电不丢失。"
}
};
// 选中某个模块卡片
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 连接配置关系
const connections = [
{ from: 'Timer1', to: 'KEY', label: '10ms', color: 'cyan' },
{ from: 'Timer1', to: 'MOTOR', label: 'PWM', color: 'cyan' },
{ from: 'Timer1', to: 'LED', label: '闪烁', color: 'cyan' },
{ from: 'Timer1', to: 'SoftRTC', label: '秒递增', color: 'cyan' },
{ from: 'GPIO', to: 'KEY', label: '引脚', color: 'purple' },
{ from: 'GPIO', to: 'RF', label: '沿', color: 'purple' },
{ from: 'KEY', to: 'MainScheduler', label: '读', color: 'cyan' },
{ from: 'RF', to: 'MainScheduler', label: '读', color: 'cyan' },
{ from: 'MainScheduler', to: 'SysStateMachine', label: '流', color: 'cyan' },
{ from: 'SysStateMachine', to: 'AMOLED', label: '控', color: 'purple' },
{ from: 'SysStateMachine', to: 'LED', label: '控', color: 'purple' },
{ from: 'SysStateMachine', to: 'MOTOR', label: '控', color: 'purple' },
{ from: 'SysStateMachine', to: 'PM', label: '控', color: 'purple' },
{ from: 'SysStateMachine', to: 'Flash', label: '读写', color: 'purple' },
{ from: 'SysStateMachine', to: 'ADC', label: '读', color: 'purple' },
{ from: 'AMOLED', to: 'GPIO', label: 'SPI', color: 'gold' },
{ from: 'LED', to: 'GPIO', label: 'P2.6', color: 'gold' },
{ from: 'MOTOR', to: 'GPIO', label: 'P2.4', color: 'gold' },
{ from: 'PM', to: 'GPIO', label: '断电', color: 'gold' }
];
// 动态绘制连接线 (SVG)
function drawConnections() {
const svg = document.getElementById('svg-connections');
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.4 : -dy * 0.4);
const controlY2 = y2 - (y2 > y1 ? dy * 0.4 : -dy * 0.4);
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 === '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('Timer1') || p.id.includes('KEY') || p.id.includes('RF')) {
p.style.stroke = 'rgba(0, 242, 254, 0.15)';
} else {
p.style.stroke = 'rgba(139, 92, 246, 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 / ADC0 / RXD2", net: "TXD", mode: "推挽输出", hw: "连到串口下载口及外部调试串口,用于固件下载及仿真打印输出。", sw: "通过 UART1 初始化函数及 printf 函数操作 SBUF 寄存器。" },
'2': { mcu: "P1.1 / ADC1 / TXD2", net: "RXD", mode: "高阻输入", hw: "外部调试串口输入接收,可在免焊测试阶段注入仿真串口指令。", sw: "UART1 串口接收中断 ISR 实时读入 SBUF 并解析状态指令。" },
'4': { mcu: "P1.5 / SCL / S2SCLK / ADC5", net: "+3.3V", mode: "电源 / 逻辑供电", hw: "Truly AMOLED 显示屏的 3.3V 逻辑电源引脚,以及外部上拉供电路径。", sw: "无操作,硬件电源层直接接入。" },
'5': { mcu: "P1.6 / XTALO / PWM4P", net: "+3.3V", mode: "电源 / 逻辑供电", hw: "Truly AMOLED 显示屏的 3.3V 逻辑电源引脚并联引线。", sw: "无操作,硬件电源层直接接入。" },
'6': { mcu: "P1.7 / XTALI / PWM4N", net: "TP_RST", mode: "推挽输出", hw: "触摸屏 TP 重置引脚(在当前无触摸功能的手环上作为悬空扩展引脚)。", sw: "GPIO 初始化配置为高电平输出悬空。" },
'8': { mcu: "UCAP", net: "TP_INT", mode: "输入中断", hw: "触摸屏 TP 中断脚(在当前版本中悬空未接入电平)。", sw: "N/A" },
'9': { mcu: "P5.4 / RST / SS", net: "SPI_SDO", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 MISO 引脚,用于读回屏幕控制器寄存器数据(在单向刷屏中常处于高阻悬空)。", sw: "初始化为复用 SPI 功能,通过 SPI 数据寄存器 SPDAT 进行串行写操作。" },
'10': { mcu: "Vcc / AVcc", net: "SPI_CS", mode: "推挽输出", hw: "Truly AMOLED 屏幕的片选信号引脚,低电平使能对屏幕控制器的 SPI 写操作。", sw: "写屏幕像素或控制命令时,通过 GPIO 驱动该脚拉低;写完后拉高。" },
'11': { mcu: "VREF+", net: "SPI_CLK", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 时钟控制引脚 (SCL)。", sw: "SPI 控制器内部自动产生移位时钟脉冲信号。" },
'12': { mcu: "GND / AGND / VREF-", net: "SPI_SDI", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 串行像素数据输入引脚 (SDA/MOSI)。", sw: "SPI 发送寄存器 SPDAT 自动将字节转换为串行比特流输出至此引脚。" },
'13': { mcu: "P3.0 / RxD / INT4", net: "SPI_DCX", mode: "推挽输出", hw: "Truly AMOLED 屏幕的 SPI 数据/命令选择引脚。高电平时发送的是像素色彩数据,低电平是控制命令。", sw: "在 lcd.c 的写数据/写命令底层函数中直接通过 GPIO 拉高或拉低。" },
'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 变化中断瞬间唤醒系统。", sw: "在 KEY 初始化中设置 P3PU=0x40Timer1 中断中定时读取 P3.6 端口电平进行移位滤波。" },
'20': { mcu: "P3.7 / INT3", net: "KEY_CONFIRM", mode: "高阻输入 + 使能内部上拉", hw: "侧边按键 ■(确认键/长按菜单键),按下为低电平;在休眠下支持中断唤醒。", sw: "KEY 初始化设置 P3PU=0x80中断中定时扫描 P3.7 电平以检测 3s 长按动作。" },
'21': { mcu: "P2.0 / A8 / PWM5", net: "KEY_UP", mode: "高阻输入 + 使能内部上拉", hw: "侧边按键 ▲(上移键),按下为低电平;在休眠下支持中断唤醒系统。", sw: "KEY 初始化设置 P2PU=0x01中断中扫描 P2.0 累加计数消抖。" },
'22': { mcu: "P2.1 / A9 / PWM6", net: "BAT_ADC", mode: "模拟输入", hw: "连接电池分压电阻网络,输入 0 到 1.31V 之间的模拟电压作为电量检测源。", sw: "开启 ADC 模块,配置通道 9 转换。计算多次采集的平均值并线性转换为电量百分比。" },
'23': { mcu: "P2.2 / A10 / SS_2", net: "DET", mode: "高阻输入", hw: "USB 充电检测端口。当手环插入充电底座时,该脚被拉为高电平;未充电时为低电平。", sw: "主循环待机页渲染中,实时读取 P2.2 的引脚电平,更新百分比后面的充电加号显示。" },
'24': { mcu: "P2.3 / A11 / MOSI_2", net: "KEY_SOS", mode: "高阻输入 + 使能内部上拉", hw: "上部并联物理按键 SOS1 与 SOS2 的硬件接入脚。两键物理并联,按下任何一个均将该脚拉低触发求救。", sw: "KEY 初始化设置 P2PU=0x08Timer1 中断扫描 P2.3 低电平,一旦满足消抖立刻触发主动 SOS。" },
'25': { mcu: "P2.4 / MISO_2", net: "MOTOR_PWM", mode: "推挽输出", hw: "连接振动马达驱动 MOS 晶体管栅极。高电平导通,马达震动;低电平关断,马达静止。", sw: "Motor 控制模块中通过 GPIO 写入 P2.4 电平。结合 Timer1 中断时间片实现异步长短脉冲震动波形。" },
'27': { mcu: "P2.6 / SCLK_2", net: "LED_RGB", mode: "SPI MOSI 硬件复用输出", hw: "连接手环上灯及下灯级联 WS2812B 灯珠的数据输入 (DIN) 脚,发送纳秒时序数据流。", sw: "复用单片机 SPI 的 MOSI 引脚。通过 SPDAT 高速发字节,将二进制 0/1 扩展为纳秒占空比波形。" },
'28': { mcu: "P2.7 / SS_2", net: "SHUT", mode: "推挽输出", hw: "OLED 升压负压 PMIC SGM3833 芯片的使能控制引脚。高电平开启供电;低电平彻底关断电路,消灭暗漏电流。", sw: "在休眠函数中直接拉低 P2.7=0在安全唤醒中拉高 P2.7=1 并强阻塞等待 50ms。" },
'29': { mcu: "P0.0 / ADC8 / AD0", net: "RF_RX_DATA", mode: "输入中断 (INT0/INT2)", hw: "LR690L 433MHz 无线接收芯片的数据信号输出线,接收到 RF 载波信号时输出脉冲沿,唤醒挂起的 CPU。", sw: "休眠前配置该脚的中断沿使能。唤醒后,主循环软件轮询算法计算高低电平比值并还原 24 位 EV1527 信号。" },
'30': { mcu: "P0.1 / ADC9 / AD1", net: "RF_TX", mode: "推挽输出", hw: "LR690L 射频前端芯片的发射电路电源/逻辑使能控制管脚。拉高后射频芯片开始向天线推送能量信号。", sw: "在调用 EV1527_Transmit 主动发送对码或求救载波时,由 GPIO 接口拉高该引脚开启发射。" },
'31': { mcu: "P0.2 / ADC10 / AD2", net: "RF_RX", mode: "推挽输出", hw: "LR690L 射频前端芯片的接收电路电源使能控制管脚。拉高芯片处于被动监听电磁波状态。", sw: "系统在进入 STATE_CLOCK 和等待对码状态下GPIO 默认拉高该引脚保持持续射频监听状态。" },
'32': { mcu: "P0.3 / ADC11 / AD3", net: "RF_TX_DAT", mode: "推挽输出", hw: "LR690L 射频前端芯片的发射调制数据输入引脚。按特定时间宽度输出脉冲以发射对应二进制码包。", sw: "主动发射时,利用 GPIO 高速翻转 P0.3 引脚的电平发送同步码头、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>[SYSTEM] ${text}`;
consoleBox.scrollTop = consoleBox.scrollHeight;
}
function clearConsole() {
document.getElementById('sim-console').innerHTML = '[SYSTEM] 仿真开始运行...';
}
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-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("触发:按下上部 SOS 紧急求救按键。");
simInterval = setInterval(() => {
step++;
if (step === 1) {
showStep("1. 按下 SOS 键 -> 硬件检测 P2.3 引脚电平被拉低为 0V。");
appendConsole("硬件检测到 Pin 24 (P2.3) 低电平。");
} else if (step === 2) {
showStep("2. Timer1 10ms 中断检测到低电平,消抖完毕,压入环形队列 'KEY_SOS_ACTIVE'。");
appendConsole("Timer1 ISR 移位消抖完成。入队 KEY_SOS_ACTIVE。");
} else if (step === 3) {
showStep("3. 主循环 Pop 出按键事件,分发至业务状态机。");
appendConsole("主循环调度,状态机跳转 STATE_SOS_EMITTED并设置重绘标志 Redraw=1。");
} else if (step === 4) {
showStep("4. 状态机指示 AMOLED 重绘大图标;同时调度 LED 和 MOTOR 开始报警。");
document.getElementById('sim-screen').style.background = '#ff007f';
document.getElementById('screen-text').innerText = "SOS EMIS\nEMERGENCY";
document.getElementById('screen-text').style.color = '#fff';
appendConsole("状态机调用WS2812_WriteRGB、Motor_Start_Pattern。");
} else if (step === 5) {
showStep("5. 射频层通过 P0.3 串行输出 EV1527 数据,发射 0x08 SOS 求救码,红灯高速交替闪烁,马达长震。");
// 闪烁彩灯
let flashCount = 0;
const flashInterval = setInterval(() => {
if (flashCount > 10) {
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("RF 驱动使能 P0.1(RF_TX),并通过 P0.3 (RF_TX_DAT) 发送 Factory ID + 0x08。");
} else if (step === 6) {
showStep("6. 紧急呼救包Factory ID发射完毕。进入报警状态挂起。按任意侧边键可清除报警。");
appendConsole("发射完毕。系统处于 STATE_SOS_EMITTED 循环挂起监听。");
clearInterval(simInterval);
document.querySelectorAll('.sim-btn').forEach(b => b.classList.remove('running'));
}
}, 1500);
} else if (type === 'intrusion') {
appendConsole("触发LR690L 被动接收到门磁传感器 (PORTE 01) 发送的 433MHz 入侵信号。");
simInterval = setInterval(() => {
step++;
if (step === 1) {
showStep("1. LR690L 射频前端引脚 P0.0 检测到沿变化,产生 INT2 沿中断唤醒系统。");
appendConsole("INT2 中断触发唤醒。CPU 开始监听接收脚脉冲。");
} else if (step === 2) {
showStep("2. 射频驱动开始自适应解密前导头低电平宽,反算出时基 T 并还原 24-bit 码字。");
appendConsole("解出 EV1527 地址: 0xA3F21B, 数据码: 0x01 (门磁动作)。");
} else if (step === 3) {
showStep("3. 主循环将地址码与 Flash 数据库进行匹配,确认为已配对的 'PORTE 01' 防区。");
appendConsole("检索 IAP Flash 第 254 扇区成功。匹配 Slot 0: PORTE 01防区类别为 0 (24小时布防防区)。");
} else if (step === 4) {
showStep("4. 状态机切入 STATE_ALARMING 警报状态LED 绿色指示闪烁,马达开启短震 (300ms)。");
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("状态机调用LED闪烁控制字启动 MOTOR P2.4 短振。");
} else if (step === 5) {
showStep("5. 屏幕红边框亮起并显示报警防区名称,声光震动同步提示。按侧边键可解除。");
appendConsole("屏幕渲染完毕。系统进入 STATE_ALARMING 被动警报等待处理。");
clearInterval(simInterval);
document.querySelectorAll('.sim-btn').forEach(b => b.classList.remove('running'));
}
}, 1500);
} else if (type === 'sleep') {
appendConsole("触发:待机常态,无任何按键或无线射频信号到达。");
simInterval = setInterval(() => {
step++;
if (step === 1) {
showStep("1. inactivity_timer 计时器开自增,计满 1000 (10秒无任何输入事件)。");
appendConsole("inactivity_timer 累加至 1000。触发低功耗判定。");
} else if (step === 2) {
showStep("2. 主循环调度进入休眠,状态机切入 STATE_SLEEP 状态,关闭 AMOLED 屏幕写入指令。");
appendConsole("状态机进入 STATE_SLEEP。AMOLED 发送 Register 0x28 (Display OFF) 关屏指令。");
} else if (step === 3) {
showStep("3. 电源 PM 驱动执行断电:将 P2.7 (SHUT) 拉为低电平 (0V),完全切断 SGM3833 供电消除漏电。");
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("PM拉低 Pin 28 (SHUT=0)。Truly 屏幕 PMIC 完全断电。");
} else if (step === 4) {
showStep("4. 配置 GPIO 的 Pin 19-24 为电平沿唤醒中断,配置 Pin 29 (RF) 为沿唤醒。");
appendConsole("使能 P3.6, P3.7, P2.0, P2.3 端口电平变化中断及 INT2。");
} else if (step === 5) {
showStep("5. 写入 PCON |= 0x02 使 STC32G 进入 Power-Down 极低功耗挂起模式,全板电流微安级。");
appendConsole("CPU 执行 PCON |= 0x02。主时钟停止全系统进入停机深度休眠。");
clearInterval(simInterval);
document.querySelectorAll('.sim-btn').forEach(b => b.classList.remove('running'));
}
}, 1500);
}
}
</script>
</body>
</html>