我正在我的RPi3上创建一个python程序,它根据Tkinter比例改变GPIO引脚的频率。
这是我的代码:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
from Tkinter import *
import time
freq = 1.0
master = Tk()
def update():
period = 1.0/float(freq)
GPIO.output(8, GPIO.HIGH)
time.sleep(period/2.0)
GPIO.output(8, GPIO.LOW)
time.sleep(period/2.0)
master.after(0, update)
scale = Scale(master, from_=1, to=20000, orient=HORIZONTAL, variable=freq)
scale.pack()
GPIO.setup(8, GPIO.OUT)
master.after(0, update)
master.mainloop()
GPIO.cleanup()
出于某种原因,master.after(0, update)
永远运行,master.mainloop()
永远不会运行。我可以判断,因为刻度永远不会显示,引脚8开启半秒钟,然后关闭半秒钟,循环重复。
如果我按Ctrl + C然后master.after(0, update)
停止运行并且master.mainloop()
开始运行,则会出现比例,但是当我左右拖动滑块时没有任何反应。
我在终端输入sudo python tone.py
然后按回车键运行程序。
固定/可替代?
答案 0 :(得分:1)
你犯了两个常见的错误:你不应该after(0, ...)
,你不应该打sleep
。
after(0, ...)
表示每次处理事件时,都会立即添加另一个事件。事件循环永远不会有机会处理队列中的其他事件,包括处理滑块的事件,屏幕更新等。
当您致电sleep
时,GUI就是这样:它会睡觉。当它处于睡眠状态时,它无法处理任何事件。
解决方案是仅在合理的时间范围内使用after
,而根本不调用sleep
。
例如:
def update():
...
# set the pin high
GPIO.output(8, GPIO.HIGH)
# set the pin low in half the period
master.after(period/2, GPIO.output, 8, GPIO.LOW)
# do this again based on the period
master.after(period, update)
另一种方式,如果你不断想要每半秒切换一次引脚,那就是:
def update(value=GPIO.HIGH):
GPIO.output(8, value)
next_value = GPIO.LOW if value == GPIO.HIGH else GPIO.HIGH
master.after(500, update, next_value)
当您使用滑块的variable
属性时,该变量必须是其中一个特殊tkinter变量的实例,例如IntVar
。然后,您需要致电get
或set
来获取或设置值。
例如:
freq = IntVar()
freq.set(1)
def update(value=GPIO.HIGH):
period = 1.0/float(freq.get())
...
答案 1 :(得分:0)
mainloop()
正在运行,但Tkinter
除非处于空闲状态,否则不会更新视图。 KeyboardInterrupt
会告诉它清理,此时它会完成事件队列(包括更新界面)并退出。
解决方案:让mainloop有空闲时间 - 你真的只需要将after(0, update)
更改为内部有几毫秒或告诉master
.update_idletasks()
更新GUI。
稍微好一点的解决方案是将你的高/低部分放入他们自己的函数中,在所需的延迟后调用每个部分 - 在mainloop gui中sleep
是一个坏主意,因为你的GUI无法更新如果程序正在睡觉。 (它也不能接受输入等)你会有毫秒帧来改变输入再次更新之前,同时使用两个相互调用的函数after
所选择的毫秒可以让你在等待时调整时间等等打开/关闭另一个。