Raspberry Pi - Python 中的 GPIO 事件

Posted

技术标签:

【中文标题】Raspberry Pi - Python 中的 GPIO 事件【英文标题】:Raspberry Pi- GPIO Events in Python 【发布时间】:2013-04-15 03:53:22 【问题描述】:

我使用 Raspberry Pi 上的 GPIO 引脚和 PIR 传感器来检测运动。当传感器检测到运动时,我想将软件移至其他功能。

目前,为了检测运动,我的程序在等待检测运动时不断循环运行。虽然这目前有效,但对于将来的使用,这将是非常低效的,我希望通过将其分配给一个事件来改进这一点。

有什么方法可以将我的 GPIO 输入绑定到程序检测到的事件,而无需手动运行循环。

这是我当前用于检测运动的循环:

var = 1
counter = 0
while var == 1:
    if GPIO.input(7):
        counter += 1
        time.sleep(0.5)
    else:
        counter = 0
        time.sleep(1)

    if counter >= 3:
        print "Movement!"
        captureImage()
        time.sleep(20)

计数器和多次检测运动用于减少传感器检测到的误报数量。

【问题讨论】:

【参考方案1】:

kapcom01 提供了一些很棒的想法,但最好不要在中断中做很多指令。

通常在调用回调时将标志设置为 1,然后在主函数中进行处理。以这种方式没有释放程序的风险。

类似这样的:

     from time import sleep
     import RPi.GPIO as GPIO



     def init():
         # make all your initialization here
         flag_callback = False
         # add an interrupt on pin number 7 on rising edge
         GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)


     def my_callback():
         # callback = function which call when a signal rising edge on pin 7
         flag_callback = True


     def process_callback():
         # TODO: make process here
         print('something')


     if __name__ == '__main__':
     # your main function here

     # 1- first call init function
     init()

     # 2- looping infinitely 
     while True:
         #3- test if a callback happen
         if flag_callback is True:
             #4- call a particular function
             process_callback()
             #5- reset flagfor next interrupt
             flag_callback = False
    pass

【讨论】:

【参考方案2】:

RPi.GPIO Python 库现在支持事件,在Interrupts and Edge detection 段落中进行了说明。

因此,在使用 sudo rpi-update 更新您的 Raspberry Pi 以获得最新版本的库后,您可以将代码更改为:

from time import sleep
import RPi.GPIO as GPIO

var=1
counter = 0

GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def my_callback(channel):
    if var == 1:
        sleep(1.5)  # confirm the movement by waiting 1.5 sec 
        if GPIO.input(7): # and check again the input
            print("Movement!")
            captureImage()

            # stop detection for 20 sec
            GPIO.remove_event_detect(7)
            sleep(20)
            GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)

GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)

# you can continue doing other stuff here
while True:
    pass

我选择Threaded callbacks 方法是因为我认为您的程序会并行执行一些其他操作来更改var 的值。

【讨论】:

【参考方案3】:

现在 RPi GPIO 库具有内置的中断驱动 GPIO 控制,可以在单独的线程中释放资源。 您不妨阅读以下http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3

【讨论】:

【参考方案4】:

您可以将 GPIO 代码包装到它自己的线程中,并让程序的其余部分在 GPIO 等待输入时执行其他操作。查看threading module

首先我将你的代码包装成一个函数

def wait_input():
    var=1
    counter = 0
    while var == 1:
        if GPIO.input(7):
            counter += 1
        time.sleep(0.5)
        else:
            counter = 0
            time.sleep(1)
        if counter >= 3:
            print "Movement!"
            captureImage()
            time.sleep(20)

然后在你的主程序中你可以这样

input_thread = threading.Thread(target = wait_input)
input_thread.start()
# do something in the meanwhile
input_thread.join()

关于 python 线程的 SO 有很多问题,所以你可能想挖掘它们。请注意,在使用线程时还需要考虑很多事情,尤其是在具有全局解释器锁 (GIL) 的 python 中,它一次只允许一个进程运行。查看multiprocessing module 可能也很聪明,可以通过它绕过 GIL。

【讨论】:

这种方法是否适用于 GUI?我想要做的是从我的 GUI 调用这个循环在其中运行的运动检测器类,但是使用循环它只会使 GUI 崩溃。如果我在线程中使用它,它会导致运动检测循环在后台运行,同时 GUI 侦听与其关联的输入吗? @Stefoth 这就是 GUI 编程的工作原理。您的 GUI 将在其自己的线程中运行,而运动检测代码将在其自己的线程中运行。

以上是关于Raspberry Pi - Python 中的 GPIO 事件的主要内容,如果未能解决你的问题,请参考以下文章

Raspberry Pi - Python 中的 GPIO 事件

Adafruit_DHT不适用于python 3 Raspberry Pi 3 B.

使用 Raspberry Pi 将图像发送到 Python 中的 QL-800 打印机时如何解码此错误?

我无法列出 Raspberry Pi 附近的 BLE 设备(python、btmgmt)

rpi-rf_send 脚本 + python raspberry pi 中的硬编码射频代码

在 Raspberry Pi 上从 python 脚本为 Twilio 服务运行终端命令时出错