树莓派快速反应检测器设计

描述

前面讲了什么是流程图,今天我们就利用流程图来帮我们设计程序,看看如何在开始程序设计时,借助流程图来帮我们梳理思路。

要让程序设计变得好玩,就要做一些有用或者有意思的程序出来,今天我们就要设计一个反应检测器,让两个人在看到一个信号灯变化时尽快按下按钮,由程序来判断谁先按下,先按下的人获得胜利。

用流程图帮助梳理思路

要做这样的反应检测器,大概的思路如下:

GPIO

那么如何判断谁先按下呢?

我们可以设置2个按钮,比如左按钮和右按钮,那么流程图可以改为:

GPIO

结合前面树莓派读取按钮的知识,当左右两个按钮都绑定一个函数,先按下的按钮就会触发该程序,把按钮对象作为参数传入该函数,然后判断该按钮的引脚数对应左按钮还是右按钮就可以判断出来哪个先按下了,从而判断输赢。

那么新的流程图应该如下:

GPIO

电路和需要的器材

思路理清了,我们就可以设计电路了,变化的信号灯可以用LED。所以器件列表如下:

  • 一个LED,颜色不限
  • 一个1K欧姆电阻,配合LED使用。
  • 两个按钮。
  • 若干跳线,用于连接器件
  • 面包板,可选,推荐使用
  • GPIO扩展板,可选,推荐使用

电路设计图如下:

GPIO

最终连接好的电路如下

GPIO

Python代码

现在可以按设计好的电路,让指示灯点亮随机时间后熄灭,左右2人看到灯熄灭后马上按下按钮。然后由程序来决出胜负。

随机时间由random库的uniform函数来生成,它的用法如下:

uniform(x,y)  #生成一个介于xy之间的随机浮点数,x是最小值,y是最大值

比如我们要让灯亮5到10秒之间,那么可以使用uniform(5,10)来获取随机数,数值将是大于5,小于10的浮点数。

我们的程序代码:

from gpiozero import LED,Button


from time import sleep
from random import uniform
from os import _exit



yellow= LED(5)   #黄灯链接了GPIO5


right = Button(17) #右按钮连接了GPIO17
left = Button(22)  #左按钮连接GPIO22


def btnPressed(button):
    btnpin = button.pin.number  #读取按下的引脚编号
    print("pressed: "+str(btnpin))
    if btnpin == 17:   #是否为右引脚
        print("右边按钮被先按下,右边赢!")
    else:
        print("左边按钮被先按下,左边赢!")
    _exit(0)      #退出程序




right.when_pressed = btnPressed
left.when_pressed = btnPressed
yellow.on()   #黄灯亮
sleep(uniform(5,10))   # 等待5-10秒之间的随机数
yellow.off()   #指示灯熄灭,玩家开始按键。

运行上面的程序,当黄灯熄灭时,2个玩家都按下按钮,程序可以判断出来是谁先按下了,但是这个程序有一个限制,每运行一次就退出了,要再次比赛,则需要重新启动程序。

我们尝试修改一下程序,每次决出胜负后,可以马上进行下一轮比赛。把指示灯控制部分移到while循环里。新代码如下:

from gpiozero import LED,Button


from time import sleep
from random import uniform
from os import _exit
   
yellow= LED(5)   #黄灯链接了GPIO5


right = Button(17) #按钮连接了GPIO17
left = Button(22)


def btnPressed(button):
    btnpin = button.pin.number
    print("pressed: "+str(btnpin))
    if btnpin == 17:
        print("右边按钮被先按下,右边赢!")
    else:
        print("左边按钮被先按下,左边赢!")


right.when_pressed = btnPressed
left.when_pressed = btnPressed
while True:
    yellow.on()
    sleep(uniform(5,10))
    yellow.off()
    print("waiting")
    left.wait_for_press()    #等待按钮被按下,在按钮按下前暂停此处
    right.wait_for_press()  #等待按钮被按下,在按钮按下前暂停此处

结果执行后发现如下的比赛结果:

GPIO

从程序输出看,虽然可以通过输出的先后顺序判断出是左边的按钮先按下,但是因为右边的按键也差不多同时调用了btnPressed程序,也打印了右边赢的信息,这显然是应该改进的。

怎么改呢?

是不是可以加一个标志变量呢?当第一个按下的按钮触发了btnPressed函数后,下一个按钮再次进入时应该看到这个标志位,并且知道自己已经输了。流程图应该改为这样

GPIO

最终的程序如下:

from gpiozero import LED,Button


from time import sleep
from random import uniform
from os import _exit

yellow= LED(5)   #黄灯链接了GPIO5


isWon = False   # 标志变量,第一个按下的按钮会改变它为True


right = Button(17) #按钮连接了GPIO17
left = Button(22)  #左按钮连接GPIO22


def btnPressed(button):
    global isWon      #使用全局变量isWon
    if isWon == True:  # 已经被更新为True,表示自己按晚了
        return       #什么也不做,直接退出该函数
    else:
        isWon = True    # 表示自己是赢家,把这个标志位设为True 
    btnpin = button.pin.number   #读取按下的引脚编号
    print("pressed: "+str(btnpin))
    if btnpin == 17:
        print("右边按钮被先按下,右边赢!")
    else:
        print("左边按钮被先按下,左边赢!")


right.when_pressed = btnPressed
left.when_pressed = btnPressed


while True:
    isWon  = False
    yellow.on()
    sleep(uniform(5,10))
    yellow.off()
    print("waiting")
    left.wait_for_press()
    right.wait_for_press()

运行上面的代码,可以每次循环进行一次比赛,只有当2个按钮都按下,决出胜负后才会进入下一个循环。从而实现了程序运行时可以不断进行比赛的效果。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分