FEATURED · 精选文章

STM32打地鼠游戏机实战:从硬件设计到软件开发的嵌入式综合项目

发布时间 / 2026/9/2 8:20:49
来源 / 创域科博编辑部
栏目 / 资讯中心
STM32打地鼠游戏机实战:从硬件设计到软件开发的嵌入式综合项目 简介这是一套面向嵌入式初学者与毕业设计学生的STM32实战项目资源聚焦趣味性与工程性结合的打地鼠掌机开发完整覆盖硬件驱动、人机交互与音视频反馈等核心能力训练。资源包含103个文件以42个.h头文件和36个.c源文件为主体涵盖STM32F10x系列标准外设库如TIM、RCC、USART、I2C、ADC等模块驱动辅以OLED显示驱动、蜂鸣器音乐播放逻辑及游戏状态机实现另有原理图.schdoc、PCB设计.pcbdoc、Keil工程.uvprojx及可直接烧录的.hex文件压缩包仅4.61MB结构清晰、模块解耦度高。已有225人学习下载适用于课程设计、毕设选题、电子竞赛原型开发及单片机进阶练手。用户获取后无需PCB制板按引脚定义用面包板模块即可快速搭建硬件平台配合说明文档与成熟源码能高效复现完整功能并支持二次扩展。1. 项目概述一个完整的嵌入式游戏机实战最近在整理过去的项目资料翻出来一个挺有意思的玩意儿——一个基于STM32的“打地鼠”掌上游戏机。这可不是一个简单的玩具它麻雀虽小五脏俱全从硬件电路设计、PCB打样焊接到嵌入式软件编程、游戏逻辑实现再到人机交互OLED显示、蜂鸣器音效全部由自己一手包办。对于想从单片机点灯进阶到综合性项目实战的朋友来说这个项目是一个绝佳的练手选择。它融合了GPIO控制、定时器、中断、OLED驱动、蜂鸣器驱动以及状态机编程等多个核心知识点最终呈现为一个可玩性高、完成度高的作品。无论你是电子爱好者、嵌入式专业的学生还是想巩固STM32开发技能的工程师跟着这个项目走一遍都能获得从原理到实操的完整提升。2. 核心硬件设计与选型解析2.1 主控芯片为什么是STM32F103C8T6在这个项目中我选择了经典的STM32F103C8T6也就是大家常说的“蓝桥杯”或“最小系统板”核心芯片。选择它主要基于以下几点考量性能与资源平衡Cortex-M3内核72MHz主频对于处理游戏逻辑、刷新OLED屏幕、产生PWM驱动蜂鸣器来说绰绰有余。64KB Flash和20KB RAM也完全能满足代码和变量存储需求。丰富的IO与定时器打地鼠需要多个按键对应“锤子”、多个LED对应“地鼠洞”STM32F103C8T6提供了足够数量的GPIO。同时其高级定时器TIM1和通用定时器TIM2/3/4可以完美地用于产生精确的延时、驱动无源蜂鸣器播放音乐以及为OLED的I2C通信提供时序。开发生态成熟无论是标准库Standard Peripheral Library还是HAL库Hardware Abstraction Layer资料和社区支持都非常完善。使用STM32CubeMX进行图形化初始化配置能极大提升开发效率减少底层寄存器配置的出错概率。成本与可获得性这款芯片及其开发板价格亲民极易获取降低了项目的入门门槛。注意虽然STM32F103系列已不是最新但其在教育和中等复杂度项目中的地位依然稳固。新手不必盲目追求最新型号熟练掌握一款经典芯片的方方面面更为重要。2.2 人机交互模块OLED与蜂鸣器OLED显示模块SSD1306驱动0.96寸I2C接口选择OLED而非LCD主要看中其自发光、高对比度、响应速度快和功耗相对较低的特点非常适合便携设备。接口选择I2C接口只需两根信号线SCL SDA比SPI接口节省IO布线简单虽然刷新速度稍慢但对于游戏菜单、分数、地鼠图案的显示完全足够。驱动要点需要编写或移植SSD1306的驱动代码核心是实现基本的画点、画线、显示字符和图片函数。游戏中需要动态更新分数、倒计时和地鼠图案这就要求驱动具备局部刷新或全屏刷新的能力并注意刷新速率以避免闪烁。蜂鸣器模块有源 vs 无源这是项目中的一个关键选择直接影响游戏音效的丰富程度。有源蜂鸣器内部自带振荡电路通电即响声音频率固定。只能通过通断时间来控制“嘀嘀”声的长短无法播放旋律。优点是驱动简单一个GPIO口控制高低电平即可。无源蜂鸣器相当于一个微型喇叭内部没有振荡源。需要外部输入特定频率的方波PWM信号才能发声改变PWM频率就能改变音调从而演奏乐曲。本项目选择为了给打地鼠游戏增加背景音乐和击打音效我选择了无源蜂鸣器。通过STM32的定时器输出PWM波可以轻松实现《超级玛丽》、《欢乐颂》等简单旋律作为背景音乐以及不同音调的“击中”、“错过”音效极大增强游戏体验。2.3 游戏输入与输出按键与LED阵列“地鼠洞”输出使用多个LED灯例如6个或9个模拟地鼠洞。LED的亮灭代表地鼠的出现与消失。每个LED通过一个限流电阻连接到STM32的GPIO口。为了增加驱动能力尤其是当LED数量较多时可以考虑使用74HC595这样的串行转并行移位寄存器来节省IO口或者直接使用GPIO口前提是计算好总电流不超过单片机的驱动能力。“锤子”输入使用独立按键或矩阵键盘。每个按键对应一个或一组“地鼠洞”。当某个LED地鼠亮起时玩家需要在规定时间内按下对应的按键模拟“敲击”动作。按键需要配置上拉电阻内部或外部并启用外部中断或进行轮询扫描以实现快速响应。3. 软件架构与游戏逻辑实现3.1 系统初始化与驱动层封装一个好的项目从清晰的代码结构开始。我采用了分层设计硬件抽象层HAL利用STM32CubeMX生成初始化代码配置系统时钟、GPIOLED、按键、定时器用于延时、PWM、I2C用于OLED。设备驱动层oled.c/.h: 封装SSD1306的所有操作提供OLED_ShowString,OLED_ShowNum,OLED_DrawBMP等API。buzzer.c/.h: 封装蜂鸣器控制提供Buzzer_PlayTone(播放单音),Buzzer_PlayMusic(播放乐曲数组)等API。乐曲数据通常是一个包含音符频率和时长的数组。led.c/.h和key.c/.h: 封装LED和按键的扫描与控制函数。应用层实现核心的游戏逻辑。3.2 核心游戏逻辑状态机与定时器打地鼠游戏的核心是一个多任务、实时性的系统。我使用一个状态机State Machine来管理游戏的整体流程如“菜单”、“准备”、“游戏进行”、“结算”等状态。游戏进行中的核心逻辑则依靠定时器中断来驱动地鼠生成逻辑设置一个定时器如TIM2每间隔一个随机时间例如0.5s~2s产生一次中断。在中断服务函数中随机选择一个LED点亮地鼠冒出并记录该地鼠的“存活”开始时间。同时在另一个变量中标记该地鼠为“待击打”状态。地鼠消失逻辑每个被点亮的地鼠都有一个“存活时长”如1秒。在主循环或另一个定时器中需要不断检查当前所有“存活”地鼠的计时一旦超时则熄灭对应的LED并标记为“错过”扣分。按键检测与响应在定时器中断或主循环中扫描按键。一旦检测到按键按下立即检查是否有地鼠在对应的位置处于“存活”状态。如果有则熄灭LED播放击中音效加分并清除该地鼠的状态标记。游戏节奏控制地鼠出现的平均间隔、存活时间可以随着游戏关卡提升而缩短从而增加难度。// 伪代码示例游戏主循环核心片段 while(1) { switch(game_state) { case GAME_MENU: OLED_ShowMenu(); if(Key_Enter_Pressed()) game_state GAME_PLAYING; break; case GAME_PLAYING: // 检查并更新地鼠状态消失、计分 CheckMolesStatus(); // 扫描按键并处理击中事件 ScanKeysAndProcessHit(); // 刷新显示分数、时间 OLED_RefreshGameInfo(score, time_left); // 检查游戏是否结束时间到 if(time_left 0) game_state GAME_OVER; break; case GAME_OVER: OLED_ShowScore(score); Buzzer_PlayGameOverMusic(); break; } // 处理其他后台任务如蜂鸣器音乐播放非阻塞式 Buzzer_Update(); }3.3 OLED界面动态显示界面设计追求简洁明了菜单界面显示游戏名称、开始选项。游戏界面顶部区域显示当前分数Score和倒计时Time。中间区域用图形或字符模拟地鼠洞的布局LED的亮灭对应图形变化。可以设计简单的地鼠像素图案当地鼠出现时在对应位置显示该图案。结算界面显示本次游戏最终得分、历史最高分并提示重新开始。刷新优化避免频繁全屏刷新导致OLED寿命缩短和闪烁。可以只刷新分数、时间等变化区域。对于地鼠图案可以采用“异或”画图模式在相同位置绘制两次即可实现“出现-消失”的效果无需清屏重画。3.4 蜂鸣器音乐与音效实现无源蜂鸣器播放音乐的原理是将乐曲简化为两个数组音符频率数组和节拍时长数组。定义音调根据十二平均律计算出中音CDo、DRe、EMi等各音符对应的频率值单位Hz定义为常量。编写乐谱将一首简单的曲子如《小星星》翻译成这两个数组。note_freq[] {NOTE_C5, NOTE_C5, NOTE_G5, NOTE_G5, ...}note_duration[] {4, 4, 4, 4, ...}4代表四分音符。定时器PWM输出使用一个定时器如TIM3的PWM输出模式连接到蜂鸣器。需要播放时根据note_freq[i]动态改变定时器的自动重装载值ARR来调整PWM频率从而改变音高。控制节拍根据note_duration[i]结合系统滴答定时器SysTick或另一个定时器控制该音符的持续时间。音效击中音效可以用一个短促的特定频率如1000Hz方波实现错过音效可以用一个下滑音快速改变频率实现。实操心得播放音乐时要采用非阻塞的方式。我的做法是在Buzzer_PlayMusic函数中设置一个播放索引和状态标志然后在主循环或一个低优先级定时器中断中调用Buzzer_Update函数来依次更新音符。这样就不会阻塞主循环导致游戏卡顿。4. 硬件电路设计与焊接调试4.1 原理图设计要点使用立创EDA或Altium Designer等工具进行设计。电源部分使用AMS1117-3.3V稳压芯片将USB或电池的5V输入转换为稳定的3.3V为STM32和所有外设供电。输入输出端务必靠近芯片放置滤波电容如10uF和0.1uF。STM32最小系统包括复位电路10K上拉电阻0.1uF电容到地、 boot选择电路BOOT0/1下拉、外部高速晶振8MHz并接两个20pF负载电容以及电源去耦每个VDD/VSS对附近放置一个0.1uF电容。OLED接口I2C接口的SCL和SDA线需要接上拉电阻通常4.7K或10K到3.3V。OLED模块本身一般自带电源滤波。蜂鸣器驱动电路无源蜂鸣器工作电流较大可达30mA不能直接用STM32的GPIO驱动。必须使用三极管如S8050或MOS管进行电流放大。一个典型的NPN三极管驱动电路是GPIO - 1K基极电阻 - 三极管基极蜂鸣器一端接VCC另一端接三极管集电极三极管发射极接地。GPIO输出高电平时三极管导通蜂鸣器发声。LED与按键电路LED串联330Ω-1KΩ的限流电阻。按键一端接地另一端接GPIO并在GPIO内部配置为上拉模式这样按键未按下时读到的就是高电平按下时为低电平。4.2 PCB布局与焊接布局遵循“模块化”布局。电源部分放在板子入口处MCU居中各外设模块围绕MCU放置相关电路尽量集中。晶振要靠近MCU引脚走线尽量短且粗。模拟部分如果有与数字部分分开。布线电源线和地线优先布线并尽量加粗。高速信号线如晶振线避免走长线且不要跨越分割的电源平面。I2C等低速信号线问题不大。焊接STM32芯片推荐使用热风枪和焊膏进行回流焊接或使用刀头烙铁拖焊。贴片电容电阻用烙铁焊接即可。焊接完成后务必先目视检查有无短路、虚焊再用万用表测量主要电源网络的对地电阻确认无短路后再上电。5. 系统调试与问题排查实录5.1 上电“不亮”或“冒烟”这是最吓人的情况。检查步骤断电万用表蜂鸣档仔细检查3.3V、5V与GND之间是否短路。重点检查稳压芯片、电容是否焊反或损坏。检查电源上电后测量AMS1117的输入应为5V左右、输出应为稳定的3.3V。如果不正常检查输入电源和芯片本身。检查晶振用示波器测量OSC_IN引脚是否有8MHz正弦波。如果没有检查晶振电路焊接和负载电容值。检查BOOT模式确保BOOT0和BOOT1被正确下拉通过电阻接地使芯片从主Flash启动。5.2 OLED屏幕不显示或显示乱码可能原因及排查供电问题测量OLED模块VCC脚电压是否为3.3V。I2C地址错误SSD1306的I2C地址通常是0x78写或0x7A读但有些模块是0x7A/0x7C。可以写一个I2C扫描程序遍历所有地址看看哪个有应答。初始化序列不全SSD1306上电后需要一段复杂的初始化命令序列才能正常工作。确保你的驱动代码完整包含了这些命令如关闭显示、设置时钟分频、复用率、对比度、扫描方向、充电泵开关等。时序问题检查I2C的时钟速度是否过快。STM32的I2C在标准模式下最高100kHz初始化时可以先用较低速度如50kHz稳定后再提高。检查上拉电阻是否已接。软件问题确认发送的是“命令0x00”还是“数据0x40”。初始化命令和显示数据的前缀字节不同。5.3 蜂鸣器不响或声音异常可能原因及排查驱动电路问题测量三极管基极电压当GPIO输出高电平时基极电压应在0.7V左右集电极电压应接近0V饱和导通。如果不对检查电阻值和三极管是否完好。PWM未输出用示波器测量连接蜂鸣器的GPIO引脚看是否有方波输出。检查定时器PWM通道是否配置正确是否使能了输出。频率问题播放音乐时如果音调完全不对检查音符频率表计算是否正确以及定时器ARR/PSC寄存器设置与系统时钟是否匹配。计算公式为输出频率 系统时钟 / ((PSC1)*(ARR1))。声音小或杂音可能是驱动电流不足尝试减小基极电阻或更换放大倍数更大的三极管。也可能是电源带载能力不足在蜂鸣器响时测量电源电压是否被拉低。5.4 游戏逻辑bug按键不灵、地鼠乱跳可能原因及排查按键消抖机械按键存在抖动必须在软件中处理。最简单的方法是检测到按键按下后延时10-20ms再次检测如果仍是按下状态才确认为有效按键。更优的方法是使用定时器中断进行周期扫描用状态机处理消抖。中断冲突如果按键和地鼠定时器都用了中断且中断服务函数执行时间过长可能导致系统响应异常。优化中断服务函数只做最必要的标志位设置复杂的处理放到主循环中。随机数质量地鼠出现的位置依赖随机数。如果随机数种子固定如每次上电都用srand(1)那么地鼠出现序列每次都会一样。应该在程序开始时用一个不固定的值做种子比如读取ADC悬空引脚的值或者结合定时器计数器的值。状态机逻辑错误这是最复杂的bug。建议使用调试器ST-Link IDE进行单步调试观察游戏状态变量、地鼠状态数组、定时器计数等关键数据的变化是否符合预期。或者在关键位置通过串口打印日志来辅助分析。完成这个项目后我最大的体会是嵌入式开发是一个系统工程硬件是骨架软件是灵魂而调试则是连接两者的桥梁。任何一个细微的疏忽无论是原理图上一个忘记的上拉电阻还是代码里一个越界的数组访问都可能导致整个系统行为异常。耐心、细致的调试和系统性的思维是做出稳定可靠作品的关键。这个打地鼠掌机虽然简单但它几乎涵盖了单片机应用的所有基础环节吃透它你就拿到了进入更广阔嵌入式世界的第一把钥匙。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻