Tkinter失败时的Python RaspberryPi GPIO事件检测 [英] Python RaspberryPi GPIO Event Detection in Tkinter Failing
问题描述
我在使用带有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屋!