学习资料来自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需要两个东西:trigger和handler。trigger告诉程序什么是打断的信号,handler是你之前定义的、在程序被打断后运行的代码。
本程序中的trigger是IRQ_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之后,添加
随后,来到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("右边的玩家胜利了!")
|