24年12月1日晚记——在网上找项目学习的时候发现一个有意思的项目,准备靠这个应用一些STM32的高级功能。值得提醒的是——目的在于学习不可贪杯,注意效率
01 根据项目需求分析
为确保充分考虑每一个细节,并且让自己高效的完成项目制作,我的步骤是:
- 查看相关项目制作,分析难度与学习点
- 向GPT请教
- 学习立创开源教程
01 硬件部分
- 处理能力:一般选择STM32系列中的Cortex-M4或Cortex-M7内核较为适合。
考虑到只是学习,我还是采取最高效率的已有硬件条件
- 存储需求:NES游戏的ROM文件可能较大,因此需要SD卡
- 外设支持:需要支持一定的外设接口,如显示屏、音频输出、控制器输入等
1.显示屏选型
320x240分辨率的TFT LCD屏
SPI通讯的240*280像素的1.69寸IPS高清圆角屏幕,很不错适合DIY玩家
字体取模
图像取模
Image2Lcd图片取模软件-CSDN博客
2.DAC外设播放音频的实现
数字化声音记录以及播放的原理
1. 声音记录采集
麦克风:根据声音的强弱产生不同强弱的电信号,再经过运放的放大处理,最后通过固定周期模拟信号数字采集(ADC)处理了原始的音频数字信号。
- ADC的常见量化(bit)单位分为8bit,16bit,24bit。一般来说比特越高声音细节保留越完整。
- 信号的采集周期常见的分为:8000,11025,22500,44100。一般来说采集周期越高音频细节保留越完整,但人耳的听觉范围为20-2000Hz,过高的采样周期没有太多意义。
- 至于单声道和多声道,就是一个ADC或者多个ADC的区别了
2.声音的存储
分为 原始音频信号保存(常见的格式为WAV)和 压缩音频(常见的格式为MP3)
3. 声音的播放
数字音乐的播放无论是有无压缩,都通过数字信号模拟输出(DAC)输出,经过运放(功放)电路驱动喇叭形成的声音
单片机DAC外设及音频电路
(1)将音频转换为8bit
由于单片机的DAC只支持8/12位的数据输出,而单片机的存储器和数据处理能力是16位的,仍然使用16位的数据来处理音频会加大存储空间(DAC数据左对齐,即放置在16位寄存器的较高位,较低的4位则填充0,然后只取16位数据的高12位)
22000Hz
所以我们这里采用8位采样的音频数据,所以我们需要将电脑上面的音频文件转换一下
盘点8bit音频制作软件-CSDN博客
(2)音频文件转换成单片机数组或者移植文件操作系统
存储在电脑上的文件是基于文件系统的文件数据,在单片机上面想直接使用就必须移植文件系统,但是在我们的游戏机扩展项目中,我们只需要使用基本的音频数据即可,所以需要将音频文件转换成可以直接使用的数组即可。
单片机实现音频播放
DAC+定时器
理论上,原始数据处理好了之后,只需要将原始音频数据发送给数字信号模拟输出(DAC),然后DAC生成的电压信号经过功放就可以驱动喇叭发出声音了。
- 但是声音的采集时有固定的周期的,所以播放的时候也必须严格按照该周期将数据输出到DAC,否则声音输出时会因为周期的不同而变音。
- 另外还需考虑音频数据播放完了是否循环
3. 控制器输入
具体请看NES 模拟器开发教程 12 - 输入设备 - 简书
摇杆:
ADC读取摇杆=分(两个滑动变阻器)和(无接触式霍尔)或者(磁编码器)作为角度检测
八大按键:
- A
- B
- SELECT
- START
- UP
- DOWN
- LEFT
- RIGH
4. 震动效果
使用单片机的来控制震动电机的强弱
震动电机种类
震动电机是一种产生震动的元件,常见的是通过旋转偏心配重产生震动感,一般震动电机大,功率就大。通常使用于按摩椅,震动抛光机,游戏机手柄,手机内部
游戏机使用的震动电机——贴片的震动电机3610贴片马达
- 额定3.0V~85mA——使用电压在2.3~4.5V
- 三个引脚——外壳接地、+、-;
- 可以用IO控制震动开关,也可以用PWM控制震动强弱
5.电池管理电路
……
02 软件部分
花费了漫长的时间,我把大部分硬件部分下单了,但是关键部分依旧是下面这段代码的移植
为了与我自己的芯片(407VGT6)结合,我准备研究一下代码……
——12.4晚
1.NES模拟器代码移植过程
介绍:
NES游戏为任天堂公司红白机上面运行的一种游戏,CPU为6502芯片,所以NES模拟器需要模拟6502微处理器的行为。你可以考虑以下两种方式:
- 现成的NES模拟器库:可以查找一些开源的NES模拟器代码(如FCEUX、Nestopia等)并将其移植到STM32上。这种方式能显著加速开发过程。
- 从零开始开发:如果选择从头开发,需要实现/准备以下功能:
- 6502 CPU模拟:模拟CPU指令集,处理中断、内存管理等。
- PPU(Picture Processing Unit)模拟:模拟NES的图形处理单元,包括背景、精灵(Sprites)渲染等。
- APU(Audio Processing Unit)模拟:模拟音频生成和输出。
- 卡带(Cartridge)/ Mapper:包含 NES 程序和图像的信息,相当存储器等部分优化的硬件
- 内存:如RAM(掉电会丢失)
- ROM(掉电不丢失):存放了……用到再说
- 输入处理:读取控制器输入并转化为游戏操作。
网上开源的单片机端的NES模拟器主要有:info nes(龙元)stm32 nes(ye781205),stm32 nes(正点原子)。正点原子的nes是在ye781205开源的基础上进行优化处理
分析:
1.nes_apu.c文件
通常包含与NES音频处理单元(APU)相关的代码。APU是NES游戏机中的一个关键组件,负责生成游戏的声音和音乐。在模拟器开发中,nes_apu.c文件实现了对原始NES APU功能的模拟,使得模拟器能够播放出与原始硬件相同的声音效果。
nes_apu.c文件中的代码可能包括以下几个主要部分:
-
音频初始化:这部分代码负责设置音频输出的初始状态,包括采样率、缓冲区大小等参数。例如,代码中可能包含对音频设备的初始化,以及创建音频缓冲区。
-
音频处理:这部分代码模拟了NES APU的音频生成逻辑。它可能包括对不同音频通道(如方波通道、三角波通道、噪声通道等)的模拟,以及对这些通道的音量、频率等参数的调整。
-
音频输出:代码中可能包含将生成的音频数据输出到实际音频设备的函数。例如,
apu_soundoutput
函数可能负责将音频数据写入音频缓冲区,以便音频设备可以播放出来。1 -
音频中断处理:在NES中,APU可以产生中断,通知CPU音频相关事件的发生。在模拟器中,这部分代码可能模拟了这种中断处理逻辑,确保音频的适时更新和播放。
-
音频寄存器访问:NES APU通过一系列寄存器来控制音频生成。NES_apu.c中的代码可能提供了对这些寄存器的模拟,使得模拟器的CPU可以像操作真实硬件一样,通过读写这些寄存器来控制音频。
-
音频采样和播放:代码中可能包含对音频采样的处理,以及如何将采样数据转换为可以播放的音频流。这可能涉及到对音频数据的缓冲和处理,以确保音频的流畅播放。
-
音频同步:为了确保音频与游戏画面的同步,代码中可能包含与视频帧率同步的逻辑,确保音频和视频保持同步。
这些代码通常是用C或C++编写的,因为这些语言提供了对硬件的直接访问和控制能力,适合模拟器开发。在实际的项目中,NES_apu.c文件可能会根据具体的模拟器需求和设计有所不同,但上述功能是其常见的组成部分。
2.nes_crc32.c
文件
是STM32F407中NES模拟器的一个组成部分,它主要包含了用于计算循环冗余校验(CRC32)值的函数。CRC32是一种常用的数据校验算法,用于检测数据传输过程中的错误。
在NES模拟器中,nes_crc32.c
文件中的函数通常被用来校验NES游戏ROM文件(.nes文件)的完整性。NES游戏ROM文件在模拟器中运行之前,可能会通过CRC32算法进行校验,以确保文件没有被损坏或者篡改,从而保证游戏的正常运行。
具体来说,nes_crc32.c
文件可能包含以下功能:
-
CRC32计算函数:实现CRC32算法的核心功能,接收数据输入并返回计算出的CRC32值。
-
ROM文件校验:利用CRC32函数对NES游戏ROM文件进行计算,并与已知的正确CRC32值进行比较,以验证文件的完整性。
-
错误处理:如果校验失败,即文件损坏,可能会提供错误处理机制,如提示用户文件损坏或者尝试修复文件。
-
优化:考虑到STM32F407的处理能力,
nes_crc32.c
中的代码可能会进行优化,以提高计算速度和效率。
在实际应用中,nes_crc32.c
文件是NES模拟器中确保游戏ROM文件正确加载和运行的重要组件。通过校验,可以避免因文件损坏导致的游戏无法运行或运行异常的问题,提升了模拟器的稳定性和用户体验
3.nes_main.c文件
是STM32F407中NES模拟器的核心源代码文件,它包含了模拟器的主循环和主要功能实现。这个文件通常负责初始化模拟器环境、读取NES游戏ROM文件、模拟NES硬件行为以及处理用户输入和游戏输出。
在nes_main.c
中,你可能会看到以下几个主要部分:
-
初始化函数:这部分代码负责设置STM32F407的硬件资源,如定时器、中断、GPIO等,以便模拟器可以正常运行。
-
主循环:这是模拟器的核心部分,它不断地执行以下步骤:
- 读取用户输入(如按键操作)。
- 更新游戏状态(根据用户输入和游戏逻辑)。
- 渲染游戏画面到屏幕。
- 处理音频输出(如果模拟器支持声音)。
-
NES ROM加载和解析:这部分代码负责读取
.nes
格式的游戏ROM文件,并解析其中的游戏数据,以便模拟器可以理解和执行。 -
硬件模拟:
nes_main.c
中包含了模拟NES CPU、PPU(图像处理单元)和APU(音频处理单元)的代码。这些模拟代码尽可能地重现了原始NES硬件的行为,使得游戏可以在STM32F407上运行。 -
输入和输出处理:模拟器需要能够接收用户的输入(如按键操作),并将其转换为游戏可以理解的指令。同时,模拟器还需要将游戏的输出(如画面和声音)呈现给用户。
-
错误处理和调试信息:在实际开发中,
nes_main.c
可能还会包含一些错误处理代码和调试信息输出,以便开发者可以追踪和解决问题。
请注意,具体的nes_main.c
内容可能会根据不同的模拟器实现和作者的编程风格有所不同。如果你有特定的nes_main.c
文件想要分析,可以提供给我,我可以帮你解读其中的关键部分
4.nes_mapper.c文件
是NES模拟器的一个关键组成部分,它主要负责处理游戏卡带(Cartridge)的映射逻辑。在NES模拟器中,Mapper的作用是将CPU和PPU(Picture Processing Unit)的地址空间映射到游戏卡带上的不同区域,从而实现对游戏数据的访问。
具体来说,nes_mapper.c
文件通常包含以下内容:
-
Mapper初始化:在模拟器启动时,会根据游戏ROM的头部信息来初始化Mapper,设置正确的映射规则和内存布局。
-
内存映射:根据不同的Mapper类型,游戏ROM和图像数据可能被分割成多个内存块(banks)。
nes_mapper.c
负责管理这些内存块的映射,确保CPU和PPU能够正确地访问到所需的数据。 -
Bank切换:当游戏需要访问不同的内存块时,
nes_mapper.c
会处理Bank切换逻辑,更新映射关系,使得CPU和PPU能够访问到新的内存区域。 -
特殊功能:某些Mapper还可能包含特殊功能,如扩展RAM、电池备份RAM、水平镜像/垂直镜像等,
nes_mapper.c
需要实现这些特殊功能。 -
I/O处理:一些Mapper还可能包含I/O端口,用于与游戏卡带上的额外硬件(如额外的音频芯片)通信。
nes_mapper.c
需要处理这些I/O操作。
在实际应用中,nes_mapper.c
的实现会非常复杂,因为它需要支持多种不同的Mapper类型,每种类型可能有不同的映射规则和特殊功能。因此,nes_mapper.c
通常会包含大量的条件分支和状态机来处理这些不同的情况。
在STM32F407上运行的NES模拟器中,nes_mapper.c
的作用是将游戏ROM的数据正确地映射到STM32的内存空间中,并模拟NES的硬件行为,使得游戏能够在STM32上运行。通过这种方式,nes_mapper.c
使得模拟器能够支持各种不同的NES游戏,即使它们使用了不同的Mapper和内存布局
5.nes_ppu.c
文件
是STM32F407中NES模拟器的一个重要组成部分,它主要负责模拟Nintendo Entertainment System(NES)的Picture Processing Unit(PPU)。PPU是NES游戏机中的图形处理单元,负责将游戏中的图形数据转换为电视或显示器上的图像输出。
在nes_ppu.c
文件中,通常会包含以下内容和功能:
-
PPU的初始化:设置PPU的初始状态,包括寄存器值、图形模式、颜色映射等。
-
图形渲染:根据PPU的控制寄存器设置,解析不同的图形模式,如背景渲染、角色渲染和精灵渲染,并将图形数据转换为实际的像素点。
-
内存映射:将游戏ROM中的图形数据映射到PPU的内存中,以便进行图形渲染。
-
颜色映射:将图形数据中的颜色索引转换为实际的颜色值,以便在显示器上正确显示。
-
渲染循环:执行渲染循环,根据当前帧的显示需求,将图形数据转换为像素点,并输出到显示器。
-
时序模拟:模拟PPU的时序,确保图形渲染的正确性和稳定性。
-
与CPU的交互:模拟CPU与PPU之间的通信,包括数据传递和同步操作。
-
错误处理:处理模拟过程中可能出现的错误,如图形错误、声音问题或其他不兼容性问题。
在实际应用中,nes_ppu.c
文件可能会根据具体的模拟器实现和需求有所不同。例如,可能需要针对不同的硬件平台进行优化,或者添加特定的功能,如支持不同的图形模式、增加对更多映射器的支持等。
此外,nes_ppu.c
文件通常会与nes_cpu.c
(模拟CPU)、nes_apu.c
(模拟音频处理单元)等其他文件协同工作,共同完成NES游戏的模拟。通过这些文件的配合,模拟器能够在现代硬件上重现NES游戏的体验
6.6502.s文件
是STM32F407中NES模拟器的一部分,它包含了6502 CPU的汇编语言实现。6502 CPU是Nintendo Entertainment System(NES)游戏机的心脏,因此,在STM32F407上实现NES模拟器,就需要模拟6502 CPU的行为。
6502.s文件通常包含了一系列的汇编指令,这些指令用于模拟6502 CPU的各个功能,包括但不限于数据加载、存储、算术逻辑运算、跳转等。这个文件是模拟器的核心,因为它负责执行NES游戏ROM中的机器码,使得游戏能够在STM32F407这样的现代硬件上运行。
在实现NES模拟器时,6502.s文件可能会与其他的C或汇编语言文件一起工作,这些文件负责处理输入输出、图形渲染、音频播放等其他模拟器所需的功能。通过这种方式,模拟器能够在STM32F407上提供一个完整的NES游戏体验。
具体到6502.s文件的内容,它可能包括以下部分:
-
数据定义:定义了6502 CPU的寄存器、内存映射等数据结构。
-
初始化代码:初始化模拟器状态,设置CPU寄存器初始值等。
-
指令实现:一系列函数或宏,每个对应6502 CPU的一个指令,实现指令的具体功能。
-
中断处理:处理外部中断和内部异常。
-
辅助函数:用于模拟内存访问、输入输出操作等其他辅助功能。
在实际应用中,6502.s文件的具体内容和结构可能会根据不同的模拟器实现和优化需求有所不同。如果你对模拟器的实现细节感兴趣,可以查看相关的源代码或技术文档,以了解更多信息
7.cart.s文件
是NES模拟器项目中的一个关键组成部分,它代表了NES游戏卡带(Cartridge)的内容。在STM32F407微控制器上运行的NES模拟器中,cart.s文件通常包含了从原始NES游戏卡带中复制出的数字副本,也就是游戏的实际内容。
具体来说,cart.s文件包含了NES游戏的数据,包括代码、图形和音频数据。这些数据是模拟器能够运行游戏所必需的,因为模拟器需要模拟NES游戏机的硬件环境,包括CPU、PPU(图像处理单元)等,以便在STM32F407这样的现代硬件上重新创建游戏在原始NES系统上的运行经验。
在技术层面上,cart.s文件的结构通常包括头部、程序ROM、图形ROM和可选的附加块。头部部分包含了关于游戏如何从文件中加载的元数据,例如ROM的大小和类型、是否需要特定的映射器、游戏是否支持垂直镜像等。程序ROM部分包含了游戏的执行代码,而图形ROM则包含了游戏中使用的所有图像数据。1
在实际应用中,要运行NES模拟器,用户需要将cart.s文件与模拟器软件一起使用,通过模拟器加载文件,从而在STM32F407等硬件平台上体验NES游戏。由于涉及到版权问题,使用和分发NES游戏ROM文件(.nes文件)需要遵守相关法律法规,确保拥有合法授权
移植所修改部分:
NES代码量巨大似乎不是我能移植的,不过如果是只换外设接口的话应该可以试试……
但如果只是套用的话对自己能力的提升又不是很多,所有这个项目就暂时到此为止了准备换别的项目学习了,及时止损……
如果有大佬有什么好的学习建议或者移植NES的教程,那晚辈感激不尽
——12.7日
06 优化处理
屏幕显示使用BUF(内存)多次写入只刷新一次,再者可用DMA直接通讯