一.项目介绍
本项目基于Raspberry Pi Pico(RP2040芯片)为核心控制器,结合MPU6050姿态传感器、1.3英寸OLED显示屏、按键模块和蜂鸣器等元器件,通过MicroPython语言开发了一款创新性的重力感应迷宫游戏。玩家通过倾斜手中的游戏设备,利用重力感应原理控制迷宫中的红色小球进行上下左右的晃动。
根据任务要求:我们需要使用姿态传感器俯仰和横滚控制小球在迷宫中移动,并且在显示屏上显示出来,游戏总共有三个关卡,并且要配备关卡切换,关卡暂停和关卡重启这些功能,玩家也可在ui界面看到得分情况和游戏时长。
最终实物演示图如下:

二.硬件介绍
硬件资源组成概述
RP2040游戏机是一款专为嵌入式学习设计的开发平台,集成了丰富的输入输出外设,形成完整的“显示-输入-反馈”项目闭环。该板卡采用树莓派基金会自主研发的RP2040微控制器作为核心,搭配2MB外扩Flash存储器,并预刷MicroPython UF2固件,实现开箱即用。
rp2040芯片核心
RP2040是树莓派基金会推出的首款微控制器芯片,采用7×7mm QFN-56封装,基于40nm工艺制造,在低成本前提下实现了高性能与灵活I/O的平衡。
主要技术规格:
处理器架构:双核ARM Cortex-M0+,最高运行频率133MHz
内存配置:264KB片上SRAM,分为6个独立存储组,支持内核与DMA并行无冲突运行
存储扩展:通过专用QSPI总线支持最高16MB片外闪存
GPIO资源:30个多功能GPIO引脚,其中4个可用作12位精度模拟输入(最高采样率500Ksps)
通信接口:2个UART、2个SPI控制器、2个I2C控制器
PWM通道:16个独立PWM通道
USB支持:USB 1.1控制器和PHY,支持主机和设备模式
特色功能:8个可编程I/O(PIO)状态机,用于自定义外围设备支持;片内温度传感器;支持UF2的USB大容量存储启动模式
显示模块采用240×240 IPS彩屏(ST7789驱动),用于渲染游戏画面。输入系统包括四向摇杆、A/B/START/SELECT轻触按键,以及MMA7660三轴姿态传感器,共同实现方向控制、菜单操作与体感倾斜操控。音频反馈由PWM驱动的蜂鸣器提供,可发出碰撞提示与通关音效。此外,板载2MB Flash用于存储程序,并通过Type-C接口进行供电与程序下载。该硬件组合使开发者能专注于游戏逻辑与交互实现。
三.设计思路
3.1设计框图

重力小球迷宫实验采用模块化设计思路,通过maze_game主控模块协调各功能单元。mma7660_driver模块经I2C接口读取三轴加速度计数据,tilt_processing模块将其转换为倾角并计算小球移动矢量(dx, dy);button_scan模块实时监测START、SELECT、A、B按键状态,生成控制信号驱动游戏状态机在菜单、进行中、暂停、结束四种状态间切换。maze_data模块存储三层8×8迷宫结构,collision_detect模块根据小球目标位置与迷宫墙壁数据进行碰撞检测,决定是否更新ball_position寄存器。game_logic模块集成计时与计分功能,通过time_counter实现秒级计时并扣除暂停时间,score_calculator在通关时累加得分。display_controller模块将迷宫矩阵、小球坐标、终点位置(6,6)及状态栏信息(Lv、T、P)转换为图形数据,通过st7789_driver经SPI接口驱动240×240 LCD实现实时渲染。
buzzer_pwm模块根据碰撞与通关事件生成对应频率的PWM信号驱动蜂鸣器,因硬件故障该模块功能暂未实现。整个系统形成了传感器数据采集→逻辑处理→显示/音频输出的完整数据流闭环。
四.主要代码
4.1开发软件
Thonny是一款专为Python初学者设计的轻量级集成开发环境(IDE)。在本项目中,Thonny作为主要的代码编辑、调试与烧录工具,其核心优势在于对MicroPython的原生支持和极简的配置流程。
4.2编程语言
MicroPython是Python 3编程语言的精简高效实现,专为微控制器及资源受限的嵌入式系统设计。它保留了Python核心语法特性,并针对硬件交互进行了专门优化。特点包括:轻量级设计——MicroPython体积仅几百KB,Python 3语法兼容:支持绝大多数Python基础语法结构,包括条件判断、循环、函数定义、类继承、异常处理,跨平台支持:支持多种开发板平台,包括Raspberry Pi Pico(基于RP2040)。
4.3软件流程图

4.4核心代码
def init_display(self):
spi = machine.SPI(0, baudrate=8000000, polarity=1, phase=1,
sck=machine.Pin(2, machine.Pin.OUT),
mosi=machine.Pin(3, machine.Pin.OUT))
self.display = st7789.ST7789(spi, 240, 240,
reset=machine.Pin(0, machine.Pin.OUT),
dc=machine.Pin(1, machine.Pin.OUT),
cs=None,
xstart=0, ystart=0, rotation=0)
硬件初始模块:初始化240×240 LCD显示屏,配置SPI通信接口,设置引脚映射和显示参数,为后续图形渲染建立硬件基础。
def move_ball(self, dx, dy):
new_x = self.ball_pos[0] + dx
new_y = self.ball_pos[1] + dy
if not self.check_collision(new_x, new_y):
self.last_ball_pos = self.ball_pos.copy()
self.ball_pos = [new_x, new_y]
if new_x == self.goal_pos[0] and new_y == self.goal_pos[1]:
self.level_complete()
return True, "level_complete"
return True, False
else:
return False, False
姿态传感模块:接收加速度计转换的dx, dy位移量,计算小球新位置并进行碰撞检测,处理通关判定,返回移动结果和状态标志。
def check_collision(self, x, y):
maze = self.get_current_maze()
if x < 0 or x >= len(maze[0]) or y < 0 or y >= len(maze):
return True
return maze[y][x] == 1
碰撞检测模块:验证目标坐标是否超出迷宫边界或与墙壁(值为1的单元格)重叠,为小球移动提供边界约束条件。
def start_game(self):
if self.game_state == "menu" or self.game_state == "paused":
self.game_state = "playing"
self.game_start_time = time.time()
self.total_paused_time = 0
self.draw_game(force_redraw=True)
游戏状态控制模块:响应START按键事件,切换游戏状态为"playing",重置计时器并触发完整重绘,实现游戏开始/继续功能。
def play_game(self):
while True:
state_info = self.button_ctrl.update()
self.game_state = state_info['state']
if self.game_state == "playing":
current_time = time.time()
if current_time - last_time_update >= 1.0:
self.update_time_display()
last_time_update = current_time
if self.accel:
self.accel.getSample(accel_data)
x_tilt = accel_data[0] if accel_data[0] < 32 else accel_data[0] - 64
y_tilt = accel_data[1] if accel_data[1] < 32 else accel_data[1] - 64
dx, dy = 0, 0
sensitivity = 6
if x_tilt < -sensitivity: dy = 1
elif x_tilt > sensitivity: dy = -1
if y_tilt > sensitivity: dx = 1
elif y_tilt < -sensitivity: dx = -1
if dx != 0 or dy != 0:
moved, draw_flag = self.move_ball(dx, dy)
if moved and draw_flag is False:
self.draw_game(force_redraw=False)
time.sleep(0.1)
主控制循环模块:实现游戏主循环,周期性扫描按键状态,每秒更新时间显示,实时处理加速度计数据并转换为控制指令,协调游戏逻辑与显示更新。
import time
import sys
import machine
import gc
import os
def main():
print("=" * 40)
print("Pico游戏系统 - 主控程序")
print("=" * 40)
# 初始内存状态
gc.collect()
print(f"初始内存: {gc.mem_free()} bytes")
try:
# 1. 运行迷宫游戏
print("启动迷宫游戏...")
from maze_game import MazeGame
game = MazeGame()
game_completed = game.play_game()
# 调试信息
print(f"游戏返回结果: {game_completed}")
print(f"最终关卡: {game.current_level}")
print(f"最终得分: {game.score}")
if game_completed:
print("\n" + "=" * 40)
print("游戏通关!调用通关画面")
print("=" * 40)
# 清理内存
del game
gc.collect()
time.sleep(1)
# 2. 运行通关画面
# 确保 win_screen.py 文件存在
files = os.listdir()
print(f"当前目录文件: {files}")
if 'win_screen.py' in files:
print("找到 win_screen.py")
# 方法1:直接导入并调用
try:
print("尝试导入 win_screen...")
import win_screen
result = win_screen.show_win_screen()
if result:
print("win_screen 执行成功")
else:
print("win_screen 执行失败")
except Exception as e:
print(f"导入win_screen失败: {e}")
import traceback
traceback.print_exc()
else:
print("win_screen.py 文件不存在")
# 保持显示
print("\n通关画面显示中,按Ctrl+C退出...")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\n退出程序")
else:
print("\n游戏未通关或中断")
except KeyboardInterrupt:
print("\n程序被中断")
except Exception as e:
print(f"主程序错误: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
main()
游戏主函数模块
五.游戏中需要的困境
(1)主要表现为小球移动时画面卡顿、关卡切换延迟明显。经过分析,问题根源在于原始代码采用全屏重绘策略,每次小球位置更新都调用draw_full_maze()函数,导致整个8×8迷宫的64个单元格(包括墙壁、路径、终点)全部重新渲染,造成大量不必要的SPI通信和图形计算开销。为解决这一问题,设计了基于差异化的局部更新机制:在draw_game()函数中引入last_ball_pos位置追踪,仅对小球移动前后的两个单元格进行重绘,同时保持终点闪烁效果的独立更新。这种优化策略将每次移动的绘制操作从64次减少到3次。最终实现了流畅的视觉体验。

(2)树莓派开发板蜂鸣器故障
我按照教学视频里调用和调试蜂鸣器时,发现蜂鸣器无法正常运作,但是波形仍然清晰可见,判断是固件损坏

六.总结
本项目基于RP2040微控制器和MicroPython语言,成功实现了一个完整的重力感应迷宫游戏,通过MMA7660姿态传感器将物理倾斜转换为虚拟小球的移动控制,在240×240 IPS显示屏上实时渲染三层递进式迷宫,并集成碰撞检测、计时计分、音效反馈和按键控制功能。
在后续优化中,可从多个维度进行扩展:一是增加关卡数量和难度;二是添加主菜单系统;三是可以像吃豆人一样添加固定敌人来丰富游戏内容;四是提升性能与体验。