Tkinter失败时的Python RaspberryPi GPIO事件检测 [英] Python RaspberryPi GPIO Event Detection in Tkinter Failing

查看:63
本文介绍了Tkinter失败时的Python RaspberryPi GPIO事件检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用带有Tkinter的Python在Raspberry Pi上检测GPIO事件时遇到了一个奇怪的问题.

I'm having a strange problem detecting GPIO events on the Raspberry Pi using Python with Tkinter.

点击 startGameButton 后,调用 start_game 函数,在 try 块中添加GPIO事件,并进行while循环运行30秒.在这段时间里,我希望GPIO事件(引脚23上的 GPIO.Falling )会发生,并且每次事件发生时,都应该执行 p2ScoreEvent 函数.实际发生的是,如果我一直导致 GPIO.Falling 事件发生,则该事件似乎仅在第一次发生时触发,直到while循环完成之前,什么也不会发生.一旦循环完成,如果事件发生了多次,它将再次调用 p2ScoreEvent ,仅此而已.

Once the startGameButton is clicked, which calls the start_game function, a GPIO event is added in the try block, and a while loop runs for 30 seconds. During this time, I am expecting the GPIO event, GPIO.Falling on pin 23 to occur and each time that the event occurs, the p2ScoreEvent function should execute. What actually happens is the event seems to only fire the first time that it occurs, if I keep causing the GPIO.Falling event to occur nothing will happen until the while loop completes. Once the loop completes, if the event occured more than once it calls the p2ScoreEvent a second time, but that's it.

一旦我不在 start_game 中的while循环中,事件检测就可以完美地工作了.我还验证了这一部分:

Once I'm out of that while loop in start_game the event detection works perfectly. I've also verified that this part:

                try:
                GPIO.add_event_detect(P1PIN, GPIO.FALLING, callback=self.p2ScoreEvent)
                while (time.time() - start_time) < game_time
                    print "listening"
                    time.sleep(5)
            except:
                    print "Something went wrong..."
                    GPIO.cleanup()

不是功能的一部分时,可以在命令行上正常运行.

functions correctly at the command line when it is not part of a function.

以下是给我一些问题的完整代码段:

Here's the full code snippet that's giving me issues:

from Tkinter import *
import time
import RPi.GPIO as GPIO

class App:
        def p2ScoreEvent(self, p1pin):
                print "ScoreEvent"
                global p2score
                p2score = p2score + 1
                p2diag.set(p2diagString + repr(p2score))

        def start_game(self):
                global p2score
                start_time = time.time()
                game_time = 30      #length of game
                P1PIN = 23
                GPIO.setmode(GPIO.BCM)
                GPIO.setup(P1PIN, GPIO.IN)
                GPIO.add_event_detect(P1PIN, GPIO.FALLING, callback=self.p2ScoreEvent)

                try:
                    GPIO.add_event_detect(P1PIN, GPIO.FALLING, callback=self.p2ScoreEvent)
                    while (time.time() - start_time) < game_time
                        print "listening"
                        time.sleep(5)
                except:
                        print "Something went wrong..."
                        GPIO.cleanup()



        def __init__(self, master):
                frame = Frame(master)

                global p2diagString
                p2diagString = "Player 2 Score: "
                global p2score

                p2score = 0

                global p2diag
                p2diag = StringVar()
                p2diag.set(p2diagString + repr(p2score))

                p2Label = Label(root, fg="white", bg="blue", textvariable=p2diag).grid(row=1, column=1)

                self.startGameButton = Button(
                        root, text="Start Game!", command=self.start_game
                        )
                self.startGameButton.grid(row=3, columnspan=2)


root = Tk()
app = App(root)
root.mainloop()

我认为这与对 start_game 的函数调用有关,但是我不确定.我没有太多的python经验,所以我在理解到底发生了什么时遇到了一些麻烦.

I'm thinking this has something to do with the function call to start_game but I'm not sure exactly. I don't have much python experience, so I'm having a little trouble understanding what exactly is going on.

为什么GPIO事件仅在第一次发生时发生,为什么如果它实际上发生了2次以上,那么为什么会在while循环结束时仅触发一次?

Why does the GPIO event only occur the first time it happens, and why does it then fire once and only once at the end of the while loop if it actually occurred more than 2 times?

推荐答案

mainloop()可以完成程序中的所有工作-它运行事件功能(和其他功能)-一个接一个-并且看起来像多任务处理.但是,如果任何函数的工作时间过长(例如,它使用 while True time.sleep(),则 mainloop 可以执行其他函数.

mainloop() do all job in program - it runs event function (and other functions) - one after the other - and it looks like multitasking. But if any of function work too long (for example it use while True or time.sleep() then mainloop can execute other functions.

因此,请勿使用 time sleep()和长时间运行的循环,而应使用 root.after(time,function)重复运行某些功能.

So don't use time sleep() and long running loop but use root.after(time, function) to run some function repeatedly.

我无法对其进行测试,但它看起来可能像这样:

I can't test it but it could looks like this:

def my_loop(self):
    if (time.time() - self.start_time) < self.game_time:
       print "listening"
       root.after(5000, self.my_loop) # run my_loop again after 5000 milliseconds

def start_game(self):
        global p2score

        # use self. to get access in other function
        self.start_time = time.time()
        self.game_time = 30      #length of game

        P1PIN = 23
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(P1PIN, GPIO.IN)
        GPIO.add_event_detect(P1PIN, GPIO.FALLING, callback=self.p2ScoreEvent)

        try:
            GPIO.add_event_detect(P1PIN, GPIO.FALLING, callback=self.p2ScoreEvent)
            self.my_loop() # run my_loop first time
        except:
            print "Something went wrong..."
            GPIO.cleanup()


顺便说一句:

您可以使用 self.end_time 进行更少的计算

you could use self.end_time to make less calculations

def my_loop(self):
    if time.time() < self.end_time:
       print "listening"
       root.after(5000, self.my_loop) # run my_loop again after 5000 milliseconds

def start_game(self):
        global p2score

        # use self. to get access in other function
        # self.game_time = 30 
        self.end_time = time.time() + 30


顺便说一句:

我们使用 classes self.不使用 global

所有代码如下:

from Tkinter import *
import time
import RPi.GPIO as GPIO

class App():

    def __init__(self, master):

        self.master = master

        self.frame = Frame(master)

        self.p2diagString = "Player 2 Score: "
        self.p2score = 0

        self.p2diag = StringVar()
        self.p2diag.set(self.p2diagString + str(self.p2score))

        p2Label = Label(self.frame, fg="white", bg="blue", textvariable=self.p2diag)
        p2Label.grid(row=1, column=1)

        self.startGameButton = Button(
            self.frame, text="Start Game!", command=self.start_game
        )
        self.startGameButton.grid(row=3, columnspan=2)

    def p2ScoreEvent(self, p1pin):
        print "ScoreEvent"

        self.p2score += 1
        self.p2diag.set(self.p2diagString + str(self.p2score))

    def start_game(self):
        self.game_time = 30
        self.end_time = time.time() + self.game_time

        P1PIN = 23
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(P1PIN, GPIO.IN)
        GPIO.add_event_detect(P1PIN, GPIO.FALLING, callback=self.p2ScoreEvent)

        try:
            GPIO.add_event_detect(P1PIN, GPIO.FALLING, callback=self.p2ScoreEvent)
            self.my_loop()
        except:
            print "Something went wrong..."
            GPIO.cleanup()

    def my_loop(self):
        if time.time() < self.end_time:
           print "listening"
           root.after(5000, self.my_loop) # run my_loop again after 5000 milliseconds

    def run(self):
        self.master.mainloop()

#----------------------------------------------------------------------

App(Tk()).run()

我把 __ init __ 作为类中的第一个函数-读起来更容易-每个人都希望在课程开始时使用 __ init __ .

I put __init__ as first function in class - it easer to read it - everybody expect __init__ at the beginning of class.

我用 str()代替 repl()

在课堂上我不使用外部变量.我里面有所有变量.

In class I don't use external variables. I have all variables inside.

这篇关于Tkinter失败时的Python RaspberryPi GPIO事件检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆