超詳細教程!自制一個Arduino NES(紅白機)遊戲機!

目前大多數NES模擬器需要使用某種C編譯器(例如esp-idf)手動進行命令行構建,這對於初學者來說是一個很大的障礙。

這周就和大傢分享如何使用Arduino IDE做一個便攜式NES(紅白機)遊戲機。

https://www.zhihu.com/video/1622200604637495296

材料清單

  • 4.0 英寸 ST7796S SPI LCD 模塊
  • 四個 400 孔面包板
  • TTGO T8 v1.7 ESP32 開發板
  • MAX98357 I2S 放大器模塊
  • PCB安裝迷你喇叭
  • PSP模擬搖桿模塊
  • 六個按鈕模塊

步驟1:Nofrendo是什麼?

Nofrendo是一個很好的NES模擬器,它可以在較老的奔騰系統上全速運行,具有不錯的聲音支持和良好的兼容性。

Nofrendo是由Matthew Conte在上個世紀開發的,它可以在Windows、Unix和BeOS上運行。由於實現已經泛化以支持不同的平臺,許多開發人員開始基於它開發其他平臺的NES模擬器。

參考資料:

http://www.baisoku.org

https://www.zophar.net/nes/nofrendo.html

https://github.com/adafruit/nofrendo_arcada

https://github.com/espressif/esp32-nesemu

步驟2:Arduino-nofrendo

Github用戶rickyzhang82在2018年將Nofrendo原始源代碼推送到Github。我已經fork瞭該倉庫,並將其轉換為兼容Arduino庫的佈局。隻需實現osd.h中聲明的所有函數即可使其工作。

理論上,如果有足夠的RAM和處理能力,這個庫可以在任何Arduino平臺上使用。由於Espressif已經證明ESP32可以運行Nofrendo,所以我基於他們的示例代碼,在examples文件夾下開發瞭一個esp32-nofrendo示例。

參考資料:

https://github.com/rickyzhang82/nofrendo

https://github.com/moononournation/arduino-nofrendo

步驟3:顯示選項

為瞭支持盡可能多的顯示變化,我將顯示實現更改為使用Arduino_GFX。現在甚至支持像ST7796這樣的大型4英寸320×480顯示屏。

以下是Arduino_GFX支持的可以適用於Nofrendo分辨率的顯示變化:

  • HX8347C 240 x 320
  • HX8347D 240 x 320
  • HX8352C 240 x 400 (16:9)
  • HX8357B 320 x 480
  • ILI9341 240 x 320
  • ILI9481 320 x 480 18位色彩
  • ILI9486 320 x 480 18位色彩
  • ILI9488 320 x480 18位色彩
  • M5Stack 240 x 320
  • R61529 320 x 480
  • ST7789 240 x 320
  • ST7789 240 x 240
  • ST7796 320 x 480

註意:

320 x 480顯示需要將原始256 x 240分辨率裁剪為240 x 214,然後放大到480 x 320。

寬度放大兩倍,高度放大1.5倍,每2個原始線條繪制3條線。第三條線可以重復第二條線,也可以簡單地保留第三條線的背景色。

詳細實現可在display.cpp中找到。

步驟4:音頻選項

目前arduino-nofrendo支持(實際上是arduino-esp32支持)2種音頻輸出方法:

  • 內置DAC – ESP32具有兩個8位DAC(數字模擬轉換器)通道,分別連接到GPIO25(通道1)和GPIO26(通道2),由於輸出非常弱,因此仍需要額外的音頻放大器用於揚聲器輸出。
  • 外部I2S DAC模塊 – 隻需連接3個信號線和電源到I2S放大器模塊,它可以在同一個模塊中完成DAC和音頻放大器的工作。

註意:

內置DAC僅具有8位分辨率,並且存在過多的靜態噪聲(雜音),通過使用外部的 I2S 放大模塊可以降低這種靜態噪聲的影響(因為外部模塊可以提供更好的信噪比和動態范圍。)

步驟5:控制器選項

https://www.zhihu.com/video/1622200706483658752

目前arduino-nofrendo支持3種類型的控制器:

  • GPIO輸入 – 簡單地將每個控制器按鈕映射到一個GPIO,箭頭鍵也有一個選項映射到一個二軸模擬搖桿
  • I2C M5Stack CardKB 迷你鍵盤 https://m5stack.com/products/cardkb-mini-keyboard
  • I2C BBQ10鍵盤 https://github.com/arturo182/BBQ10KBD

即將支持:

  • 更多I2C設備,例如I2C遊戲手柄
  • 藍牙設備,例如藍牙遊戲手柄和藍牙鍵盤

註意:

默認的arduino-esp32 I2C接口連接到GPIO 21(SDA)和22(SCL)。

步驟6:文件系統選項

Nofrendo在文件系統中存儲3種類型的文件:

  • ROM文件*.nes – 遊戲
  • 遊戲存檔文件*.sav – 當你在遊戲中保存時,數據備份到此文件
  • 狀態文件*.ss[0-9] – 當你使用Nofrendo保存狀態功能時,數據存儲在這些文件中

目前arduino-nofrendo支持(實際上是arduino-esp32支持)3種類型的文件系統:

  • SPIFFS – 通常是ESP32閃存的最後一個分區
  • SD – Arduino標準SPI模式SD卡接口
  • SD_MMC – 原生1位或4位SD模式SD卡接口

註意:

選SPIFFS測試是最簡單的方法,但在SPIFFS中備份存檔和狀態文件比較困難,SD或SD_MMC更適合長期使用。另外,如上面視頻演示,你可以將SD卡當作遊戲卡,隻需更換SD卡即可更換遊戲。

步驟7:軟件準備

Arduino IDE

如果你尚未安裝Arduino IDE,請下載並安裝:

https://www.arduino.cc/en/main/software

ESP32支持

按照安裝說明添加ESP32支持,如果尚未安裝:

https://github.com/espressif/arduino-esp32

註意:請使用arduino-esp32版本1.0.6進行此項目,較新版本可能無法成功編譯

Arduino ESP32 filesystem uploader

按照安裝步驟安裝Arduino ESP32 filesystem uploader,如果沒有安裝的話:

https://github.com/me-no-dev/arduino-esp32fs-plugin

Arduino_GFX庫

下載最新的Arduino_GFX庫:(點“Clone or Download”->“Download ZIP”)

https://github.com/moononournation/Arduino_GFX

在Arduino IDE中導入庫。(Arduino IDE“項目”菜單->“包含庫”->“添加.ZIP庫”->選擇下載的ZIP文件)

Arduino Nofrendo庫

下載最新的Arduino Nofrendo庫:(點“Clone or Download”->“Download ZIP”)

https://github.com/moononournation/arduino-nofrendo

同樣在Arduino IDE中導入庫。(Arduino IDE“項目”菜單->“包含庫”->“添加.ZIP庫”->選擇下載的ZIP文件)

步驟8:面包板原型

在制作你自己的便攜式Arduino NES控制臺最終版本之前,讓我們先用面包板原型進行一個PoC(概念驗證)。

步驟9:面包板改造

4寸LCD是一個比較大的尺寸,我們需要把四個400孔面包板組合在一起。不過,8個電源總線太多瞭,我們去掉其中的6個,隻保留2個就足夠瞭。

步驟10:TTGO T8 V1.7改造

將四個400孔面包板組合在一起可以放下4寸LCD,但仍然沒有足夠的剩餘空間來放一塊ESP32開發板。因此,我們需要將ESP32開發板的一部分隱藏在LCD下方。同時,將線路也隱藏在LCD下方使其更整潔。

但我發現TTGO T8 V1.7的3D天線無法放LCD下方。由於NES控制臺不需要互聯網接入,我就直接把它拆瞭……

註意:

  • 以後仍然可以通過IPEX連接器將WiFi信號引導到外部天線
  • 藍牙設備連接也需要天線

步驟11:LCD改造

  • 焊接SD引腳接頭
  • 可選操作:重新焊接所有LCD引腳,使引腳稍微伸長到面包板
  • 插入額外的塑料隔離片,在面包板和LCD之間預留更多空間

步驟12:固定模擬搖桿

帶有引腳的模擬搖桿一側可以非常好地固定在面包板上,但另一側需要一些額外的引腳才能固定在面包板上。

步驟13:I2S放大器模塊改造

I2S放大器模塊的揚聲器連接器不是2.54毫米間距(面包板孔的間距大小),需要稍微彎曲引腳接頭以方便焊接。

步驟14:佈局設計

在實際的面包板佈線之前,我們首先先設計所有組件的佈局,並仔細檢查所有組件的位置是否與LCD沖突。

步驟15:引腳映射設計

這一步是可選的,隻是為瞭使線路更加整潔(由於所有的線路都隱藏在LCD後面,這並不是必要的)。

大多數ESP32接口可以重新映射到任何GPIO引腳,除瞭SD_MMC。由於TTGO T8 v1.7已經內置瞭與SD_MMC接口連接的SD卡插槽,我想重用那些引腳連接到LCD SD卡插槽。

我在開發板下方使用瞭一些面包板線將一些GPIO重定向到其他面包板條,讓整個佈局看起來更加整潔:

  • 模擬搖桿引腳GPIO 34和35至左下角
  • SD_MMC引腳GPIO 13、15、2和14至右上角
  • 開始和選擇按鈕引腳GPIO 26和27至右下角
  • 3v3連接至2個電源條
  • GND連接至電源條
  • 模擬搖桿引腳 GPIO 34 和 35 連接到左下方
  • SD_MMC 引腳 GPIO 13、15、2 和 14 連接到右上角
  • 開始和選擇按鈕引腳 GPIO 26 和 27 連接到右下角
  • 3v3 連接到兩個電源插頭
  • GND 連接到電源插頭

註意:

SPI顯示器通常需要連接7個GPIO引腳,它們是CS、RESET、D/C、SCK、MOSI、MISO和LED。為瞭把GPIO的使用次數減少到3次,進行瞭一些安排:

  • CS接地,表示始終使能
  • 復位連接到ESP32復位,LCD在ESP32復位時復位
  • MISO不連接,無需從LCD讀取數據
  • LED連接至VCC,LCD背光始終100%開啟

步驟16:面包板佈線

以下是連接匯總:

ESP32
VCC -> LCD VCC & LED, I2S放大器模塊VCC,搖桿VCC
GND -> LCD GND & CS, I2S放大器模塊GND,搖桿GND,所有按鈕GND
RST -> LCD RST
GPIO 34 -> 搖桿上下模擬
GPIO 35 -> 搖桿左右模擬
GPIO 32 -> LCD D/C
GPIO 33 -> LCD MOSI
GPIO 25 -> LCD SCK
GPIO 26 -> 按鈕開始
GPIO 27 -> 按鈕選擇
GPIO 23 -> 按鈕X
GPIO 18 -> 按鈕Y
GPIO 5 -> 按鈕A
GPIO 4 -> 按鈕B
GPIO 14 -> SD SCK
GPIO 13 -> SD CS
GPIO 15 -> SD MOSI
GPIO 2 -> SD MISO
GPIO 22 -> I2S放大器模塊BCLK
GPIO 21 -> I2S放大器模塊WCLK(或稱LRC)
GPIO 19 -> I2S放大器模塊DOUT(或稱DIN)
I2S放大器模塊GAIN -> 100歐姆電阻 -> GND(可選15 dB增益)
I2S放大器模塊+ve -> 揚聲器+ve
I2S放大器模塊-ve -> 揚聲器-ve

赞(0)