Python RaspberryPi GPIO Event Detection in Tkinter Failing
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.
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 millisecondsdef 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()
BTW:
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 millisecondsdef start_game(self): global p2score # use self. to get access in other function # self.game_time = 30 self.end_time = time.time() + 30
BTW:
We use classes
and self.
to not use global
All code could look like this:
from Tkinter import *import timeimport RPi.GPIO as GPIOclass 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()
I put __init__
as first function in class - it easer to read it - everybody expect __init__
at the beginning of class.
I use str()
in place of repl()
In class I don't use external variables. I have all variables inside.