首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用RPi按钮在任何时候中断GPIO TKinter循环

如何使用RPi按钮在任何时候中断GPIO TKinter循环
EN

Stack Overflow用户
提问于 2017-01-15 16:09:35
回答 2查看 1.4K关注 0票数 0

这是第二个版本的一个程序,我正在挣扎。我早些时候发布了一个关于这个程序的第一个版本的问题,但是没有运气。

这是我的“大图片的想法”,如果它能帮助你找到我偏离轨道的地方。我有很多植物需要浇水,我想用TKinter制作一个图形用户界面,它将出现在Raspberry Pi上的触摸屏上。Pi控制连接到水泵上的110 V继电器开关。它只是基本的“开/关”循环的z#的植物。

用户有三个滑块来调整,X,Y和Z值。X是水泵需要开多久,Y是水泵需要关闭多长时间(所以你有时间把水管实际移到下一个工厂),Z是你需要浇水的植物总数。我过去总是让循环永远运行,因为我总是可以让CTRL-C程序结束,但现在我试图让它在触摸屏上实现,而不需要键盘--比教一个不懂Linux意味着如何使用终端的人更方便用户。它还需要像人们习惯看到的程序那样运行,因此GUI触摸屏按钮(比如智能手机和平板电脑)。

大多数情况下,代码运行良好,它停止并开始时没有崩溃。我计算出了开始按钮,并且有一个重置按钮来清除滑块值,以防您想要在零处重新启动这些值。但最大的问题,似乎影响了这里的许多人,是该死的退出按钮。

我需要用户能够在循环期间的任何时间按下TKinter退出按钮,并让程序知道何时按下按钮并立即服从它,基本上是中断了循环。我试过很多事,什么都没用。复选按钮只会等到循环结束,然后更新切换值。此时为时已晚,我需要用户在整个浇水循环中进行控制。

我也不希望程序退出时退出,相反,我希望GPIO循环在"OFF“值上停止,并基本上将程序重置为开始状态。

我知道time.sleep()很粗糙,但我没有找到其他的方法。我见过人们谈论“线程”,我不知道这意味着什么,听起来我永远也不会。我还看到人们谈论过TKinters的"after()“函数,同样,我需要非常清楚的例子来回答。只是说“使用线程”没有任何帮助-我是个菜鸟!

代码语言:javascript
运行
复制
    from tkinter import *
    import RPi.GPIO as GPIO
    import time


    master = Tk()


    def onoffcycle():
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(14, GPIO.OUT)
        GPIO.setup(14, GPIO.LOW)
        y=off.get()
        y=float(y)
        x=on.get()
        x=float(x)
        GPIO.output(14, True)
        print("On")+str(x)
        time.sleep(x)
        GPIO.output(14, False)
        print("Off")+str(y)
        time.sleep(y)


    def start():
        print("Prepare to water in 10 seconds...")
        time.sleep(10)
        z=cycle.get()
        z=float(z)
        while z > 0:
            onoffcycle()
            z=z-1
            print("Cycles remaining:")+str(z)
            ###tog()
            ###if t==1:
                ###reset()
        else:
            reset()
        ### this program runs onoffcycle() for z number of cycles as set by the slider.
        ### It should check for an exit toggle, then run the program for one cycle,
        ### then check for exit, then another round. countdown from cycle.get variable


    def reset():
        GPIO.cleanup()
        on.set(0)
        off.set(0)
        cycle.set(0)

    t=IntVar()

    ###def tog():
        ### HELP!  This is where I need the program to be looking for the EXIT button being pressed
        ### in order to stop the program.  Everything I have tried so far waits until the z value drops
        ### to zero, basically until the program stops on its own.  I need a button that interrupts
        ### everything.


    on = Scale(master, label="Set # Seconds Water ON:", from_=0, to=180, orient=HORIZONTAL, length=400, width=35,
              troughcolor="red", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, sliderrelief=RIDGE,
               font = '-weight bold')
    on.grid(column=1, row=1, columnspan=3)

    off = Scale(master, label="Set # Seconds Water OFF:", from_=0, to=30, orient=HORIZONTAL, length=400, width=35,
              troughcolor="yellow", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, sliderrelief=RIDGE,
                font = '-weight bold')
    off.grid(column=1, row=2, columnspan=3)

    cycle = Scale(master, label="Set # of Plants to Water:", from_=0, to=200, orient=HORIZONTAL, length=400, width=35,
              troughcolor="green", bg="SteelBlue1", fg="black", bd=6, sliderlength=90, sliderrelief=RIDGE,
                font = '-weight bold')
    cycle.grid(column=1, row=3, columnspan=3)


    go = Button(master, text="START", command=start, bg="SteelBlue3", width=10, height=2, font='-weight bold')
    go.grid(column=1, row=4)

    adios = Checkbutton(master, text="EXIT", variable=t, indicatoron=0, bd=6, bg="SteelBlue3", width=11, height=2, font='-weight bold')
    adios.grid(column=3, row=4)
    ###adios should have a command to run an exit program - with toggle values? or something else?
    resetbutton = Button(master, text="RESET", command=reset, bg="SteelBlue3", width=10, height=2, font='-weight bold')
    resetbutton.grid(column=2, row=4)



    mainloop()
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-15 17:01:41

使用布尔变量True/False控制循环和其他元素

例如,创建全局变量。

代码语言:javascript
运行
复制
time_to_exit = False

当您按下True按钮时,将其设置为EXIT

并在功能上使用

代码语言:javascript
运行
复制
while z > 0 and not time_to_exit:

它应该停止循环。

如果循环停止并退出,您可以使用其他布尔变量通知程序。

代码语言:javascript
运行
复制
# inform function to use global variable
global loop_is_working
loop_is_working = True
while z > 0 and not time_to_exit:

# ...

def reset():
  # inform function to use global variable
  global loop_is_working

  loop_is_working = False

def on_exit:

   if loop_is_working:
       reset()
       # check again afte 100ms
       after(100, on_exit)
   else:
       # stop `mainloop()` and close tkinter window
       root.destroy()

另一个问题是:您使用了sleep()while,所以Tkinter必须等到它结束。

您可以使用master.after(miliseconds, function_name)Tkinter/mainloop来执行这个函数,同时它也可以检查按钮。

示例

代码语言:javascript
运行
复制
time_to_exit = False

def start():
    print("Prepare to water in 10 seconds...")

    # mainloop will run `start_loop` after `10s`
    master.after(10000, start_loop) # 10s = 10 000ms 

def start_loop():    
    z = float(cycle.get())
    loop(z)
    # or
    #master.after(0, loop, z)

def loop(z):    
    if z > 0 and not time_to_exit:
        onoffcycle()
        z -= 1
        print("Cycles remaining:", z)
            ###tog()
            ###if t==1:
                ###reset()
        # mainloop will run `loop` again as soon as possible
        master.after(0, loop, z)
     else:    
        reset()

甚至是

代码语言:javascript
运行
复制
# create global variables
time_to_exit = False
loop_is_working = False

def start():
    # inform function to use global variable
    global loop_is_working

    loop_is_working = True

    print("Prepare to water in 10 seconds...")

    # mainloop will run `start_loop` after `10s`
    master.after(10000, start_loop) # 10s = 10 000ms 

def start_loop():    
    z = float(cycle.get())
    loop(z)
    # or
    #master.after(0, loop, z)

def loop(z):    

    if z > 0 and not time_to_exit and loop_is_working:
        onoffcycle()
        z -= 1
        print("Cycles remaining:", z)
            ###tog()
            ###if t==1:
                ###reset()
        # mainloop will run `loop` again as soon as possible
        master.after(0, loop, z)
     else:    
        reset()

def reset():
  # inform function to use global variable
  global loop_is_working

  # ... your code ...

  loop_is_working = False
票数 0
EN

Stack Overflow用户

发布于 2017-01-17 18:20:39

因此,这是新的代码与furas的优秀建议。我还了解了如何使z值随每次迭代而减少。重置按钮现在将在程序完成当前循环后停止,并等待您启动新的循环。这是因为我仍然让time.sleep()处理打开和关闭时间。我试着用after()来解决这个问题,但是它一直导致其他更大的问题。此时,该程序在技术上是完全可用的,所以我不介意它挂在一个循环中;它不会损害现实世界的应用程序!我仍然有其他的问题,值得他们自己的问题,如配置触摸屏,以正确校准,以及程序自动启动后,自动启动LDXE。我计划将所有内容正确地放置在一个class()中。同时,希望能够在if:语句中更改Label小部件文本。谢谢大家!

代码语言:javascript
运行
复制
    #!/usr/bin/python
    from Tkinter import *
    import ttk
    import RPi.GPIO as GPIO
    import time


    master = Tk()
    master.title("Obligatory Title")
    master.attributes("-fullscreen", True)
    time_to_exit = False
    loop_is_working = False


    def onoffcycle():
        global t
        GPIO.setwarnings(False)
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(18, GPIO.OUT)
        GPIO.output(18, GPIO.LOW)
        y=float(off.get())
        x=float(on.get())
        GPIO.output(18, True)
        print("On")+str(x)
        t.set("Water ON")
        t.get()
        time.sleep(x)
        GPIO.output(18, False)
        print("Off")+str(y)
        t.set("Water OFF")
        time.sleep(y)             

    def start():
        global loop_is_working
        global t
        loop_is_working = True
        print("Prepare to water in 10 seconds...")
        t.set("Prepare to water in 10 seconds...")
        master.after(10000, loop)

    def loop():
        z=float(cycle.get())
        global loop_is_working
        global time_to_exit
        global t
        t.set("Now Watering...")
        if z > 0 and not time_to_exit and loop_is_working:
            onoffcycle()
            z=z-1
            cycle.set(z)
            print("Cycles remaining: ")+ str(z)
            master.after(0, loop)
        else:
            reset()


    def reset():
        global loop_is_working

        GPIO.cleanup()
        on.set(0)
        off.set(0)
        cycle.set(0)
        t.set("Welcome!  Drag the sliders to set values. Tap left or right of the sliders to fine tune values.")
        loop_is_working = False

    t = StringVar()
    t.set("Welcome!  Drag the sliders to set values. Tap left or right of the sliders to fine tune values.")

    welcome = Label(master, bg="Steelblue3", bd=6, relief=RAISED, width=92,
                    height=2, textvariable=t)
    welcome.grid(column=1, row=1, columnspan=3)


    on = Scale(master, label="Set # Seconds Water ON:", from_=0, to=120, orient=HORIZONTAL, length=735,
               width=50, troughcolor="steelblue", bg="SteelBlue1", fg="black", bd=6, sliderlength=90,
               sliderrelief=RIDGE)
    on.grid(column=1, row=2, columnspan=3)

    off = Scale(master, label="Set # Seconds Water OFF:", from_=0, to=30, orient=HORIZONTAL, length=735,
                width=50,troughcolor="steelblue", bg="SteelBlue1", fg="black", bd=6, sliderlength=90,
                sliderrelief=RIDGE)
    off.grid(column=1, row=3, columnspan=3)

    cycle = Scale(master, label="Set # of Plants to Water:", from_=0, to=200, orient=HORIZONTAL, length=735,
                  width=50,troughcolor="steelblue", bg="SteelBlue1", fg="black", bd=6, sliderlength=90,
                  sliderrelief=RIDGE)
    cycle.grid(column=1, row=4, columnspan=3)

    go = Button(master, text="START", command=start, bg="green3", width=19, height=3,
                bd=4, font='-weight bold')
    go.grid(column=1, row=5)

    adios = Button(master, text="EXIT", command=exit, bg="red3", width=19, height=3,
                bd=4, font='-weight bold')
    adios.grid(column=3, row=5)

    resetb = Button(master, text="RESET", command=reset, bg="yellow3", width=19,
                height=3, bd=4, font='-weight bold')
    resetb.grid(column=2, row=5)

    mainloop()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41663223

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档