# 蓝桥杯单片机在线实验台

`lanqiao-mcu-lab`：面向蓝桥杯单片机赛项 CT107D 竞赛板的浏览器仿真实验台。

面向 CT107D / STC15F2K60S2 的浏览器功能仿真器。导入 Keil 生成的 Intel HEX，执行机器指令，通过虚拟按键、温度、电压、距离和串口观察程序行为。界面采用功能卡片，不复刻实体开发板；不包含 LCD 和电机接口。

这是可部署到 GitHub Pages 的纯静态项目，运行不依赖服务器、云 API、第三方脚本或浏览器内编译器。HEX 只在本机浏览器内读取，不上传。项目附带原创基础演示，没有打包课程中的私人源码、HEX 或原理图。

## 本地运行

安装 Node.js 18 或更新版本后，双击 `start.cmd`，或在项目目录运行：

```sh
node serve.cjs
```

浏览器打开 `http://127.0.0.1:8128`。无需 `npm install`，无需 build。关闭终端会停止本地服务；端口占用时可通过环境变量 `PORT` 指定其他端口。

不要直接双击 `site/index.html`：ES Modules 和 Web Worker 需要 HTTP/HTTPS。也可以用已有静态服务器托管 `site/`。

## 在线使用

直接打开 https://zuoliangyu.github.io/lanqiao-mcu-lab/ 。源码仓库：https://github.com/zuoliangyu/lanqiao-mcu-lab 。

## 部署 GitHub Pages

1. Fork 本仓库，或把项目根目录的文件上传到自己的 GitHub 仓库，保留 `.github/workflows/pages.yml` 和 `site/`。
2. 在仓库 Settings → Pages 中，将 Source 设为 GitHub Actions。
3. 推送到 `main` 且改动了 `site/` 时自动发布；也可在 Actions 中选择“发布单片机实验台”，点击 Run workflow。工作流只上传 `site/` 并发布，不安装依赖、不构建。
4. 完成后打开部署结果提供的 Pages 地址。项目使用相对资源地址，支持 `https://用户名.github.io/仓库名/` 子路径。

若使用其他静态托管平台，仅上传 `site/` 中的文件即可。

## 如何使用

- 点击“运行演示”：CPU 执行内置机器码，数码管显示 `2026  51`，S4～S7 控制 L4～L1。
- 载入或拖入 HEX，选择与固件下载配置一致的主频，再点击“运行”。默认 12 MHz；主频不同会影响扫描、串口、时隙和测距。
- 鼠标按住按键触发，右键或 Shift+点击锁定，支持组合按键。“全部松开”解除锁定。键盘数字 1～4 对应 S4～S7。独立模式仅启用 S4～S7。仿真器不替程序扫描按键，按键是行列之间的开关，扫描周期由固件决定。按下和松开带页面时间戳，换算到当时的仿真时刻并统一延后一批（16ms×倍率）生效，按住时长等于实际流逝的仿真时间，快速点击也不会丢。
- 拖动温度、电压、距离滑块，等待固件读取和处理；不会直接改写程序的显示变量。温度转换和固件滤波会产生延迟。
- 串口使用固件配置的 UART1 波特率。文本发送 `OK`，或开启 HEX 收发后输入 `4F 4B`。默认不追加 CRLF。
- 暂停同时停止 CPU 和外设仿真时间。倍率是目标速度；“实际倍率”表示当前电脑达到的速度，不保证所有程序实时运行。
- “寄存器与调试”提供十六进制地址断点和单步执行；没有 C 源码级调试。待处理中断可能使单步先进入中断服务。
- MCU 复位保留 EEPROM、RTC 等外设状态；断电重启保留 EEPROM，重新初始化其他器件。EEPROM 自动保存于该浏览器、该站点的 localStorage；清除站点数据或使用另一个站点地址不会共享数据。

## 已实现范围

| 层次 | 内容 |
| --- | --- |
| CPU | MCS-51 有效指令解释执行、STC Y5 指令时钟、IRAM/SFR/XRAM、寄存器组、位操作、栈、端口锁存与引脚读、MOVC/MOVX |
| 定时与中断 | Timer0/1 常用模式和 STC 模式0自动重装、1T/12T；Timer2；外部中断0/1；UART1；PCA计数及溢出 |
| 板级输出 | P0/P2 译码与锁存、8个 LED、8位共阳数码管扫描积分、蜂鸣器、继电器、J13 I/O / MOVX 选择 |
| 输入 | 独立/矩阵按键、组合键、P3.4/T0 方波输入、虚拟距离和无回波 |
| I²C | PCF8591 四路单端8bit ADC/DAC，AT24C02 256字节存储、页写回卷、写忙 NACK |
| 其他器件 | DS1302 BCD时钟/写保护/停止位，DS18B20 单总线时隙/CRC/分辨率与转换等待 |
| 页面 | HEX校验、运行/暂停/复位、串口、寄存器、地址断点、运行诊断、EEPROM本地保存 |

主要连接：LED/输出/位选/段选分别由 Y4/Y5/Y6/Y7 锁存；DS18B20 为 P1.4；DS1302 为 P1.3/P1.7/P2.3；I²C 为 P2.0/P2.1；超声波为 P1.0/P1.1。按原理图与驱动建立连接，并用现有二进制例程验证。

## 现有课程程序的兼容设置

1. **DS18B20 重复转换命令**：默认“忙时保持（兼容）”，在转换期间再次收到 44H 时保持原转换，仍等待对应分辨率要求的时间。现有模板频繁发出转换命令，因此提供这一兼容策略。重复命令的真实器件行为尚未实物核对；可切到“重新计时”比较，此时频繁触发可能导致一直读到85°C。设置在“环境与模拟输入 → 外接通道与温度兼容设置”。温度在转换结束时采样；写时隙在约30µs的典型采样点判定，被中断拉长到约25µs的写1仍按1接收。
2. **超声波**：模块测试例程使用默认“板载40 kHz脉冲串”；大模板的驱动发送单个短脉冲，应选择“单脉冲兼容模型”。这两种模型明确区分，单脉冲模式不代表原理图板载接收电路已支持该用法。板载模式要求连续8个高电平为5～50µs的脉冲，允许中断偶尔拉长个别半周期。
3. **PCF8591**：读回的首字节是上一转换值。现有例程只读首字节，会表现为两路值交错；本仿真保留该行为，不替程序丢弃首字节。
4. **大模板测频**：频率输入范围为100～38,000Hz，可手动输入整数频率或拖动滑块，两者以1Hz精度同步；需勾选“接入 P3.4/T0”。该引脚与矩阵键盘第四列互斥：接入频率时自动释放并禁用S16～S19，其他列仍可用；断开频率后恢复该列，旧的按下状态不会恢复。例程的200ms计数窗存在量化，如1234Hz显示1230。T0计数按引脚电平：程序向P3.4写0会拉低引脚并产生下降沿，因此键盘扫描写 `P34=0` 的程序测得的频率会偏高；仿真按单片机拉低优先处理，与555输出冲突时的实物结果未核对。
5. **大模板界面切换**：已提供源码使用 `%7`，距离页面的 `case 7` 无法通过正常切换进入。这是模板逻辑限制；没有改写原程序。验证针对已有HEX，不保证重新编译不同源码得到相同行为。

## 边界

这是用于课程调试的功能仿真首版，不是全芯片、电气级或经实物校准的时序仿真。未实现完整的看门狗、SPI、内部ADC、IAP、UART2、PCA捕获/PWM、低功耗行为、Timer0/1模式3、PCF8591差分转换、全部STC扩展寄存器和优先级配置。未建模模拟放大电路、电气噪声、驱动电流、按键机械抖动和器件容差；蜂鸣器声音仅作为状态提示。

部分不支持的配置会在“运行诊断”提示，但诊断没有覆盖所有情况。没有提示不等于任意HEX都兼容。指令周期、设备状态机及所列例程已做针对性验证，不能替代完整指令一致性测试或真实开发板验收。

## 结构与验证

```text
site/cpu.js       指令执行、内存、中断
site/machine.js   STC定时器、端口、板级连接、仿真时间
site/devices.js   I²C、RTC、单总线器件
site/worker.js    Worker调度、控制消息
site/hex.js       Intel HEX解析与校验
site/demo.js      原创机器码演示
site/app.js       交互、状态渲染、本地保存
tests/           轻量核心验证、用户固件回归入口
```

核心检查：`node tests/core.mjs`。已有固件验证：

```sh
node tests/firmware.mjs "全模块测试例程目录" "大模板HEX文件完整路径"
```

测试直接加载你自己的文件，交付包不包含它们。验证详情、固件SHA256与未验证项见 [VALIDATION.md](VALIDATION.md)。运行时无第三方依赖，参考资料见 [THIRD_PARTY.md](THIRD_PARTY.md)。新实现使用 MIT 许可证。

## 作者

左岚 · [哔哩哔哩](https://space.bilibili.com/27619688) · 姊妹项目：[蓝桥杯嵌入式在线实验台](https://github.com/zuoliangyu/lanqiao-embedded-lab)
