在 Raspberry Pi 上定期轮询端口或硬件 IO 点

periodic polling of port or hardware IO point on Raspberry Pi

在使用带有 Python 的 Qt5 开发应用程序时,您通常是事件驱动的。没有汗水,就像一个魅力。但是,在某些情况下,您需要轮询某些硬件 GPIO 的状态(即按下按钮),或者从串行端口获取一些信息,或者类似 gpsd 守护进程的东西。

处理此问题的首选方法是什么?通过 QTimer,比如说,每 50 毫秒 运行?或者还有其他我没有找到的方法吗?是在 GPIO pi 上设置触发器更好 (https://www.ics.com/blog/control-raspberry-pi-gpio-pins-python) 还是与 Qt5 Gui 有任何冲突?

基本文档看起来并不可怕,我当然可以遵循一些示例,但不知道是否有 better/canonical/more Pythonic 方法。

https://doc.qt.io/qtforpython/PySide2/QtCore/QTimer.html

https://python-catalin.blogspot.com/2019/08/python-qt5-qtimer-class.html

我认为没有 pythonic 解决方案,不是因为你不能使用 python,而是因为 python与主题无关。而且也没有规范的解决方案,一切都将取决于应用程序。

根据我的经验,我发现重用处理 GPIO 的库(如 Rpi.GPIO 或 gpiozero)要容易得多。这些库有一个创建线程的策略,其中监视引脚的状态,因此您不能直接使用回调来更新 GUI,但您必须实现包装器(参见 示例)。

简单的例子:

import sys

from gpiozero import Button

from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl
from PyQt5.QtWidgets import QMainWindow, QApplication


class ButtonManager(QObject):
    pressed = pyqtSignal()

    def __init__(self, parent=None):
        super(ButtonManager, self).__init__(parent)
        self._button = Button(20)
        self._button.when_pressed = self._on_when_pressed

    def _on_when_pressed(self):
        self.pressed.emit()


class MainWindow(QMainWindow):
    @pyqtSlot()
    def on_pressed(self):
        print("pressed")


def main():

    app = QApplication(sys.argv)
    w = MainWindow()

    button_manager = ButtonManager()
    button_manager.pressed.connect(w.on_pressed)

    w.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

如果你打算使用串行端口,那么最好的选择是使用 Qt 串行端口,因为与 pyserial 不同,它不需要使用线程,但通知是通过信号(参见 例如)

使用 QTimer 是另一种选择。