把小喵掌机(学而思 ESP32 编程掌机)改造成 NES 红白机模拟器,支持 SD 卡读取 ROM、WiFi Web 文件管理、菜单式双槽位存档/读档,还能在浏览器里上传游戏!

🎯 项目简介
本项目基于 arduino-nofrendo 改造,适配学而思 ESP32 小喵掌机 ESP32 + ST7735 160×128 屏幕,围绕 SPI2 总线冲突修复、内存中转存档等关键技术难题,实现了完整的 NES 模拟体验。
✨ 核心特性
- 🖥️ ST7735 160×128 显示,NES 256×240 缩小适配全屏
- 💾 SD 卡读取 ROM,从
/rom/目录加载.nes文件,开机选档菜单 - 📀 菜单式双槽位存档/读档,弹出菜单含存档时间,上下选槽位 A 确认
- 📡 WiFi Web 文件管理,浏览器上传 ROM、下载存档、删除/改名文件
- 🎮 掌机 6 键 + 串口键盘备用控制
- 🔊 蜂鸣器 PWM 音频(可开关)
🔧 硬件接线(小喵掌机)
| TFT 引脚 | ESP32 GPIO | 说明 |
|---|---|---|
| VCC | 3V3 | 电源 |
| GND | GND | 接地 |
| SCK | GPIO 18 | SPI SCLK(与 SD 卡共享) |
| SDA(MOSI) | GPIO 23 | SPI MOSI(与 SD 卡共享) |
| CS | GPIO 5 | 片选 |
| DC | GPIO 4 | 数据/命令 |
| RES | GPIO 19 | 与 SD 卡 MISO 共享 |
| BLK | GPIO 5 | 背光 |
TFT 与 SD 卡共用 SPI2 总线(GPIO18/23/19),通过各自 CS 分时复用。
💡 技术亮点
1. SPI2 总线冲突修复(关键)
TFT 与 SD 卡共享 SPI2 总线。旧版菜单式存读档崩溃由两层因素叠加导致:
nofrendo_pause_timer()只停止定时器递增,但nes_emulate()主循环仍可能在帧需渲染时调vid_flush继续写屏(SPI2);sdTask在同一窗口内操作 SD 卡(SPI2 DMA)→ 两条路径争抢 SPI2 → ESP32 Guru Meditation 崩溃。
修复方案:新增 volatile bool g_emulation_suspended 标志,pause 时置 true 跳过渲染循环,让 SPI2 空闲给 sdTask。
2. 内存中转存档:零竞态条件
NES 状态保存/恢复在定时器回调内同步完成(纯内存操作,约 31KB blob),SD 卡写入在独立任务中异步完成。操作 SD 卡前通过 g_emulation_suspended 挂起 nes_emulate(),确保 displayTask 不再争抢 SPI2。
3. 双槽位存档(取代 .bak 备份)
采用 sa1 / sa2 两个独立槽位,存档菜单显示各自时间戳(YYYY-MM-DD HH:MM),由 SNTP 同步后格式化。历史保护由双槽位本身提供,不再需要额外的备份文件。
4. GPIO19 复用
GPIO19 同时是 TFT RES 和 SD MISO。解决方案:TFT 使用软件复位命令(RST = -1),不占用 GPIO19;GFX bus 的 MISO 设为 19;display_begin() 后再调一次 sdSpi.begin() 确保 SPI 路由正确。
5. WiFi 内存管理
WiFi 仅在选档菜单期间运行,进入 NES 模拟器前停止 Web 服务器并释放内存,避免 WiFi 占用过多 RAM 导致游戏崩溃。进游戏后 WiFi 进入省电模式减少后台中断对 SD 卡 SPI 的干扰。
🎮 按键映射
| 掌机按键 | NES 功能 |
|---|---|
| 方向键 | 方向键 |
| A (GPIO34) | A 键 |
| B (GPIO12) | B 键 |
| 上+下+B | SELECT |
| 上+下+A | START |
| 左+右+B | 💾 弹出存档菜单(2 槽位) |
| 左+右+A | 📂 弹出读档菜单(2 槽位) |
| 左+上+右+A | 🔊 蜂鸣器开关 |
📡 WiFi 文件管理
选档菜单期间,浏览器访问屏幕显示的 IP 地址即可:
- 浏览
/rom和/save目录 - 上传 ROM 文件到 SD 卡
- 下载存档文件(
.sa1/.sa2)到电脑 - 删除/改名文件


🚀 快速开始
- SD 卡格式化为 FAT32,根目录建
rom文件夹,放入.nesROM 文件 - Arduino IDE 安装
Arduino_GFX库(不要装 nofrendo 库,项目自带源码) - 开发板选 ESP32 Dev Module,分区方案 Default 4MB with SPIFFS,PSRAM Enabled
- ESP32 开发板库版本 2.0.9(其他版本可能无法点亮屏幕)
- 编译烧录 → 上电 → 连接 WiFi → 浏览器上传 ROM → 选游戏开玩!
⚠️ 踩过的坑
- 不要装 Arduino IDE 的 nofrendo 库:项目自带
src/目录包含完整源码,重复会冲突 - TFT 与 SD 卡共用 SPI2 总线:已通过
g_emulation_suspended互斥机制修复,选档/存读档期间自动暂停 NES 渲染 - WiFi 在游戏内不可用:非 bug,进游戏后停止 Web 服务器释放内存,按 B 退回选档菜单即可恢复
- 无 SD 卡也能玩:固件自动回退到 SPIFFS 分区 ROM(需先烧录)
📚 致谢
- arduino-nofrendo — 原始 NES 模拟器库
- Arduino_GFX — TFT 屏幕驱动库
- 学而思小喵掌机 — 硬件参考
欢迎到 GitHub 给项目点个 ⭐!有问题或者改进建议都可以提 Issue~