学习资料来自Get started with MicroPython on Raspberry Pi Pico

微控制器可不只存在于工业设备中,他们存在于身边很多物品中,包括玩具和游戏。

人类的平均反应速度约为200毫秒~250毫秒,本项目我们将设计一个测试反应力的、可供单人或双人的小游戏。

所需材料

  • 树莓派Pico
  • 一块面包板
  • 一个任意颜色的LED
  • 一个330Ω的电阻
  • 两个按钮
  • 公对公跳线若干

单人游戏

电路连接

单人反应力小游戏.png

代码实现

拆解分析

首先导入库

1
2
3
import machine
import utime
import urandom # 处理随机数

接着,将变量pressed设为False,然后将GP15设为LED,GP14设为按钮。

1
2
3
pressed = False
led = machine.Pin(15, machine.Pin.OUT)
button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN)

之前我们已经处理过按钮了,但这次有些不同,我们将采用一种不同的更加灵活的方式:打断请求(interrupt requests或IRQs)

定义一个函数用于处理打断:

1
2
3
4
5
def button_handler(pin):
global pressed
if not pressed:
pressed=True
print(pin)

这个函数开始时检查变量pressed的值,然后将其设置为True以忽略以后的按钮点击。

然后点亮LED,使用urandom库将程序暂停5到10秒中的随机值。(程序中的uniform指的是均匀分布(uniform distribution))

1
2
3
led.value(1)
utime.sleep(urandom.uniform(5, 10))
led.value(0)

在程序最后一行输入:

1
button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler)

建立一个IRQs需要两个东西:triggerhandlertrigger告诉程序什么是打断的信号,handler是你之前定义的、在程序被打断后运行的代码。

本程序中的triggerIRQ_RISING,也就是说打断在该针(pin)的值从低(由于按钮的内置电阻而成为默认值)升高(当按钮被按下)时发生。

接着在最后一行前添加如下代码:

1
timer_start = utime.ticks_ms()

这行代码创建了一个新的名为timer_start的变量,并用utime.ticks_ms()函数的输出为其赋值。这个函数是用来计算utime库开始运行到此所经过时间(单位:毫秒)的。这就提供了一个参考点:恰在LED熄灭之后和洽在trigger准备阅读按钮按下之前。

接着,找到button_handler,并在其下添加

1
2
timer_reaction = utime.ticks_diff(utime.ticks_ms(), timer_start)
print("你的反应时间为" + str(timer_reaction) + "毫秒!")

第一行又定义了一个新变量,用来记录打断何时发生(也就是什么时候按下的按钮),这次我们用来utime.ticks_diff函数记录这一行代码被触发时与timer_start中参考点之间的时间差。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import machine
import utime
import urandom

pressed = False
led = machine.Pin(15, machine.Pin.OUT)
button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN)


def button_handler(pin):
global pressed
if not pressed:
pressed=True
timer_reaction = utime.ticks_diff(utime.ticks_ms(), timer_start)
print("你的反应时间为" + str(timer_reaction) + "毫秒!")

led.value(1)
utime.sleep(urandom.uniform(5, 10))
led.value(0)
timer_start = utime.ticks_ms()
button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler)

双人游戏

电路连接

双人反应力小游戏.png

实物图(效果图):

双人反应力小游戏实物图.jpg

代码实现

拆解分析

在原来单人游戏的基础上,增加一个按钮,并将其命名为right_button,现在,定义两个按钮:

1
2
left_button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN)
right_button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN)

同样,其他地方也需要我们将其一分为二,在程序末尾:

1
2
left_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler)
right_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler)

这时,程序就可以运行了,但为了让游戏更刺激一点,程序需要报告是哪个玩家先按下的按钮。

在定义两个按钮与LED之后,添加

1
fastest_button = None

随后,来到button_handler后,删去处理计时器和打印的两个,并用

1
2
global fastest_button
fastest_button = pin

替代。

这两行代码能够让函数改变fastest_button变量,而非仅仅是读取,并让其包含触发打断的针(pin)的信息。

现在,到程序末尾,添加

1
2
while fastest_button is None:
utime.sleep(1)

这创建了一个有限循环,程序将在fastest_button仍为零时保持运行。

最后,我们需要确定胜利的玩家:

1
2
3
4
if fastest_button is left_button:
print("Left Player wins!")
elif fastest_button is right_button:
print("Right Player wins!")

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import machine
import utime
import urandom

pressed = False
led = machine.Pin(15, machine.Pin.OUT)
left_button = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_DOWN)
right_button = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_DOWN)
fastest_button = None


def button_handler(pin):
global pressed
if not pressed:
pressed=True
timer_reaction = utime.ticks_diff(utime.ticks_ms(), timer_start)
print("最快反应时间为" + str(timer_reaction) + "毫秒!")
global fastest_button
fastest_button = pin

led.value(1)
utime.sleep(urandom.uniform(5, 10))
led.value(0)
timer_start = utime.ticks_ms()
left_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler)
right_button.irq(trigger=machine.Pin.IRQ_RISING, handler=button_handler)
while fastest_button is None:
utime.sleep(1)
if fastest_button is left_button:
print("左边的玩家胜利了!")
elif fastest_button is right_button:
print("右边的玩家胜利了!")