2022寒假在家一起练-基于RP2040 Game Kit实现复古小游戏:2048
使用RP2040 Game Kit 开发复古小游戏:2048
标签
嵌入式系统
2022寒假在家练
树莓派RP2040
2048游戏
Huang
更新2022-03-03
华南理工大学
1149

一、项目需求和功能实现

-设计或移植一款经典的游戏,通过LCD屏显示,通过按键和四向摇杆控制游戏的动作,-本次选择的游戏是2048,具体需求有:

-驱动LCD屏幕完成图形和数字的绘制

-通过ADC采集摇杆信号,判断摇杆位置

-完成2048游戏的矩阵变换逻辑,以摇杆位置为控制信号

-读取按键状态,完成悔棋机制

在最终的设计中,摇动摇杆即可完成相应方向的数字变换,点击按钮B即可返回上一次操作。

整体实现的流程图如下

FoQODXyaqmuAAJdtX1uDvark1Ard

二、具体实现代码

2.1 导入python库

import uos

import machine

import time

import st7789 as st7789

from fonts import vga2_8x8 as font1

from fonts import vga1_16x32 as font2

from machine import Pin

import framebuf

import random

将一些MicroPython支持的库导入,其中fonts st7789两个库是参考自板卡自带的例子,用于字体显示和驱动LCD屏幕。machine是MicroPython中一个非常重要的库,内置有操作GPIO、定时器、PIO和各种通信协议的类,可以直接调用。在本次设计中,主要用machine库来设置SPI0、配置、读取ADC的值、操作GPIO,以完成摇杆和按键状态的读取。time库用于完成一些延时,主要有sleep() sleep_ms() sleep_us() 等几个函数。framebuf用于创建显示缓存,将要显示的图形缓存好,通过SPI发送给屏幕控制器。random用于生成随机数。

 

2.2 初始化屏幕显示

st7789_res = 0
st7789_dc  = 1
disp_width = 240
disp_height = 240
CENTER_Y = int(disp_width/2)
CENTER_X = int(disp_height/2)
print(uos.uname())
spi_sck=machine.Pin(2)
spi_tx=machine.Pin(3)
spi0=machine.SPI(0,baudrate=4000000, phase=1, polarity=1, sck=spi_sck, mosi=spi_tx)
#
print(spi0)
display = st7789.ST7789(spi0, disp_width, disp_width,
                          reset=machine.Pin(st7789_res, machine.Pin.OUT),
                          dc=machine.Pin(st7789_dc, machine.Pin.OUT),
                          xstart=0, ystart=0, rotation=0)
display.fill(st7789.BLACK)
display.fill_rect(46,46,148,148,st7789.WHITE)

这里定义了一些SPI协议的引脚,比如st7789_res = 0,这里的0指的是RP2040GPIO编号,对应于原理图的框内标识。machine.spi 定义了使用40kHz波特率的SPI0,并将其绑定在所定义的引脚上。st7789.ST7789实例化了一个对象display,方便我们后续调用库中的方法。随后进行了屏幕的初始化,两层for循环内指定了背景方块的位置,具体方法和实际效果如下图所示。

Fmork4zBaGuRD5ACUktZwpC8WcYTFmPFmdg2Baziw9zWi6j7S4N6etAp

2.3 定义类

放一下类定义的伪代码

class Matrix2048():

    def __init__(self, column: int = 4):
       
    def last_step(self):   

    def generate_number(self):

    def init(self):

    def move_left(self):

    def move_right(self):

    def move_up(self):

    def move_down(self):

    def update_ui(self):

定义的矩阵变换类中有九个函数__init__()是初始化函数,在类被实例化的时候会执行一次。注意该函数中重新定义了一个同名实例display,和此前屏幕初始化部分的实例是不同的,只能用于类的内部。last_step()用于反悔,支持一次撤回操作。generate_number()用于确定新生成基数2的随机位置。函数init()用于初始化屏幕,注意这一部分和此前的操作相同。接下来四个是矩阵变换函数,用于在对应的输入到来时完成显示矩阵的变化。最后是update_ui()函数,用于更新显示矩阵。

 

2.4 读取四项摇杆方位和按键状态

x_side = machine.ADC(28)

y_side = machine.ADC(29)

button = machine.Pin(buttonB,Pin.IN)

up = 0

down = 0

left = 0

right = 0

regret = 0

g = Matrix2048(4)

 

machine.ADC()用于读取对应引脚的模拟电压值,括号内的数值同样是GPIO编号。ADC默认16bit精度,即返回的数值范围为(0,65535)。machine.Pin用于指定和配置引脚。此外还定义了一些标志变量,并实例化了上文所描述的类。

 

2.5 主循环

while True:

    updown = x_side.read_u16()    #up:  400 down :64000

    leftright = y_side.read_u16() #left:256 right:65000

                                  #normal: 33000~34000

    time.sleep(0.1)

#====================================================

#--------------button and direction------------------

#====================================================

    if button.value() == 0:

        regret = 1

    if updown <= 400:

        up = 1

    elif updown >= 64000:

        down = 1

    elif leftright <= 300:

        left = 1

    elif leftright >= 65000:

        right = 1

#====================================================

#--------------------call update---------------------

#====================================================

    if up:    # 向上

        time.sleep_ms(30)

        g.move_up()

        g.generate_number()

        g.update_ui()

    elif down:  # 向下

        time.sleep_ms(30)

        g.move_down()

        g.generate_number()

        g.update_ui()

    elif left:  # 向左

        time.sleep_ms(30)

        g.move_left()

        g.generate_number()

        g.update_ui()

    elif right:  # 向右

        time.sleep_ms(30)

        g.move_right()

        g.generate_number()

        g.update_ui()

#====================================================

#----------------------regret------------------------

#====================================================

    if regret:

            display.text(font2, "regret",46,14,st7789.WHITE,st7789.BLACK)

            g.last_step()

            g.update_ui()

            regret_flag = 1

            time.sleep_ms(500)

            regret = 0

            display.text(font2, "regret",46,14,st7789.BLACK,st7789.BLACK)

#====================================================

#--------------------reset flag----------------------

#====================================================

    up = 0

    down = 0

    left = 0

    right = 0

    regret = 0

主循环中指明了判断摇杆方向的取值范围,这一范围是实际读取大量操作数据后估算的。摇杆判明方向后,将对应的标志变量置1,完成后续的判断操作。同时由于每次循环的周期至少大于100ms,因此无需进行按键的消抖。

 

三、收获和感想

这是我首次使用MicroPython对嵌入式系统进行编程。不得不感慨一下可以如此方便地调用底层硬件功能,而无需过于繁杂地记忆底层函数和校对语言格式。我在这个项目中投入的时间不长,整体实现方面还有很多可以改进的地方:撤回操作仅支持一步回退,可以更改为多次历史记录;获得的分数可以显示上去;初始化的时候可以放置一些别的屏幕等等。RP2040 Game Kit上也还有很多别的硬件资源(比如PIO和三轴姿态传感器、红外收发),我将会继续探索,期待有一天能赶上群里大佬的步伐。

附件下载
代码文件.zip
源代码
团队介绍
华南理工大学 黄宇康
团队成员
Huang
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号