【问题标题】:Python "shutdown / reboot raspberry pi" script, using a single buttonPython“关机/重启树莓派”脚本,使用单个按钮
【发布时间】:2015-05-19 19:23:48
【问题描述】:

我从这里得到了一段 Python 代码: http://www.raspberry-pi-geek.com/Archive/2013/01/Adding-an-On-Off-switch-to-your-Raspberry-Pi

我想改进它。

由于这是我第一次使用 Python,所以我一直无法理解实际发生的情况。

代码如下:

# Import the modules to send commands to the system and access GPIO pins
from subprocess import call
import RPi.GPIO as gpio
from time import sleep

gpio.setmode(gpio.BCM) # Set pin numbering to board numbering
gpio.setup(22, gpio.IN) # Set up pin 22 as an input

rebootBool = 0

# Define a function to keep script running
def main(pin):
    while True:
        #gpio.remove_event_detect(pin)
        gpio.add_event_detect(22, gpio.RISING, callback=confirmation, bouncetime=200) # Set up an interrupt to look for button presses
        sleep(5000000)

def confirmation(pin):
    gpio.remove_event_detect(pin)
    gpio.add_event_detect(22, gpio.RISING, callback=shutdown, bouncetime=200)
    sleep(3) # if button has been pressed again within 3 seconds, shut down will happen
    main(22)

def reboot(pin):
    rebootBool = 1
    call('reboot', shell=False)
    exit(0)

# Define a function to run when an interrupt is called
def shutdown(pin):
    gpio.remove_event_detect(pin)
    gpio.add_event_detect(22, gpio.RISING, callback=reboot, bouncetime=200)
    sleep(3) # if the button has been pressed for a third time, within 3 seconds, Pi will reboot
    if rebootBool == 0: # Just to make sure a halt is not called after the 3 seconds have passed, if reboot is called
        call('halt', shell=False)
    exit(0)

main(22) # Run the loop function to keep script running

我想做的是这样的:

  • 如果按钮被按下一次,则会执行确认功能,如果在 3 秒内按下按钮,则会重置按钮以调用关机功能。
    • 否则,使用主循环继续
  • 在关机函数中,如果再次按下(3秒内),它会重置以调用重启函数。
    • 否则继续,然后关闭

会发生什么:

如果我按下按钮两次或三次,它会告诉我 gpio.add_event_detect 已经定义,当它尝试在 main() 中定义它时。 所以它不会改变它,如果我再按一次它,它就会调用关闭函数。

我不明白的是:

为什么它要在 main 中定义 gpio 事件,而实际功能是重新启动或关闭(它应该调用重新启动或关闭)?

【问题讨论】:

    标签: python linux raspberry-pi interrupt


    【解决方案1】:

    因为回调函数在单独的线程中运行。这意味着,例如,当您在主循环中调用任何回调函数时,它仍然有效(主循环),因此当您从回调函数(线程#1)和主循环调用函数 gpio.add_event_detect 时会发生这种情况(线程#2)同时。这是典型的比赛条件。 您可以通过运行以下代码来检查它:

    #!/usr/bin/python
    # Import the modules to send commands to the system and access GPIO pins
    from subprocess import call
    import RPi.GPIO as gpio
    from time import sleep
    
    gpio.setmode(gpio.BCM) # Set pin numbering to board numbering
    gpio.setup(22, gpio.IN, pull_up_down=gpio.PUD_DOWN) # Set up pin 22 as an input
    
    rebootBool = 0
    
    # Define a function to keep script running
    def main(pin):
        while True:
            print "main loop"
            gpio.remove_event_detect(22)
            gpio.add_event_detect(22, gpio.RISING, callback=confirmation, bouncetime=200) # Set up an interrupt to look for button presses
            sleep(1)
            #raw_input()
    
    def confirmation(pin):
        print "confirmation1"
        sleep(5)
        print "confirmation2"
        gpio.remove_event_detect(22)
        gpio.add_event_detect(22, gpio.RISING, callback=shutdown, bouncetime=200)
        sleep(5) # if button has been pressed again within 3 seconds, shut down will happen
        gpio.remove_event_detect(22)
        main(22)
    
    def reboot(pin):
        rebootBool = 1
        print "reboot"
        #call('reboot', shell=False)
        exit(0)
    
    # Define a function to run when an interrupt is called
    def shutdown(pin):
        print "shutdown"
        gpio.remove_event_detect(pin)
        gpio.add_event_detect(22, gpio.RISING, callback=reboot, bouncetime=200)
        sleep(3) # if the button has been pressed for a third time, within 3 seconds, Pi will reboot
        if rebootBool == 0: # Just to make sure a halt is not called after the 3 seconds have passed, if reboot is called
            #call('halt', shell=False)
            print "halt"
        exit(0)
    
    main(22) # Run the loop function to keep script running
    

    【讨论】:

    • 谢谢,我现在明白了。我添加了一些打印命令,看看会发生什么,但不是这样。而且由于我认为回调是中断,并且中断会中断实际函数,因此要调用另一个函数,实际将暂停运行。
    【解决方案2】:

    因此,在 Anton Glukhov 向我解释了要注意什么之后,我发现了如何解决每个问题,现在它可以完美运行。

    这是更好地解释我所做的链接: http://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/

    不幸的是,除了在 main 函数中使用 while 循环之外,我无法做到这一点。 但由于没有发生任何重要的事情,因此每个循环都添加了 1 秒的睡眠时间,以确保最小的 CPU 使用率。

    我在这里分享最终代码,希望它可以帮助其他人:

    # Import the modules to send commands to the system and access GPIO pins
    from subprocess import call
    import RPi.GPIO as gpio
    from time import sleep
    from os import system
    
    gpio.setmode(gpio.BCM) # Set pin numbering to BCM numbering
    gpio.setup(22, gpio.IN) # Set up pin 22 as an input
    
    def confirmation(pin):
        #print "Confirmation Function on pin %d" % pin
        system('echo Press again to confirm Shut down menu! | wall -n') # let all logged in users know
        gpio.remove_event_detect(pin)
        gpio.add_event_detect(pin, gpio.RISING, bouncetime=200)
        sleep(2) # if button has been pressed again within 2 seconds, shut down function is called
        if gpio.event_detected(pin):
            shutdown(pin)
        else:
            #print "canceled"
            system('echo Shut down canceled! | wall -n') # let all logged in users know
            main()
    
    def resetPin(pin):
        #print "Pin %d has been reset" % pin
        gpio.remove_event_detect(pin)
        gpio.add_event_detect(pin, gpio.RISING, bouncetime=200)
    
    def reboot(pin):
        #print "Reboot Function on pin %d" % pin
        call('reboot', shell=False)
        exit(0)
    
    # Define a function to run when an interrupt is called
    def shutdown(pin):
        #print "ShutDown function on pin %d" % pin
        system('echo Press again if you want to reboot instead of shut down! | wall -n') # let all logged in users know
        gpio.remove_event_detect(pin)
        gpio.add_event_detect(pin, gpio.RISING, bouncetime=200)
        sleep(2) # if the button has been pressed for a third time, within 2 seconds, Pi will reboot
        if gpio.event_detected(pin):
            reboot(pin)
        else:
            call('halt', shell=False)
            exit(0)
    
    # Define a function to keep script running
    def main():
        #print "Main Function"
        resetPin(22)
        while True:
            sleep(1)
            if gpio.event_detected(22):
                confirmation(22)
    
    main() # Run the main function to keep script running
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多