我有一个在Python 5.3和PyQt 7.1(我认为)中开发的应用程序。到目前为止,我在GUI中的一切工作都很好。我现在需要能够通过GPIO.add_event_detect检测到两个外部机械按钮的按下。我添加了用于检测信号下降沿的GPIO命令,当我尝试执行代码时,我得到了已经为此GPIO通道启用的冲突边缘检测。"
我尝试将代码移动到不同的类(它不是在while循环中),只是为了看看我是否会得到不同的错误。
我正在寻找任何文档或说明,解释如何将add_event_detect用于基于事件的应用程序,如QT。
一如既往,非常感谢!
迈克
编辑: 我尝试了下面的建议,我遇到执行问题。下面的代码只有三个类 - 我没有添加可执行代码,因为我不确定是否有人想花时间为GPIO引脚添加2个N.C.按钮。我希望你能够通过阅读代码来看到问题。
ExecuteSession类工作正常。我试图增加读取GPIO引脚16和16上两个信号下降沿的能力。 18个PStop和EStop课程。当ExecuteSession启动时,我可以看到打印语句"在PStop"和#34;在EStop"。当我按下按钮时,我没有看到其他打印声明。我是Python和Threads的新手,我很感激任何建议。
我确实创建了一个小型测试程序,以确保Pi看到状态转换,并且确实如此。
由于
class PStop(QThread):
PT_event_detected = pyqtSignal(int)
def __init__(self):
QThread.__init__(self)
self.queue=Queue()
GPIO.add_event_detect(16, GPIO.FALLING, callback=self.queue.put)
print("In PStop")
def run(self):
while True:
print("In PStop Run")
self.PT_event_detected.emit(self.queue.get())
print("PT EVENT " +str(self.queue.get()))
class EStop(QThread):
ER_event_detected = pyqtSignal(int)
def __init__(self):
QThread.__init__(self)
self.queue=Queue()
GPIO.add_event_detect(18, GPIO.FALLING, callback=self.queue.put)
print("In EStop")
def run(self):
while True:
print("In EStop Run")
self.ER_event_detected.emit(self.queue.get())
print("ER EVENT " +str(self.queue.get()))
class ExecuteSession(QThread):
PBValueSig = pyqtSignal(int)
PBValueDone = pyqtSignal(int)
PBValuePause = pyqtSignal(int)
PBTimeActual = pyqtSignal(int)
durComplete = 0
def __init__(self, dur='', pause='', stopExe =''):
QThread.__init__(self)
self.dur = dur
self.pause = pause
self.stopExe = stopExe
self.E_Stop = EStop()
self.E_Stop.ER_event_detected.connect(self.Ext_Stop_Detect)
self.E_Stop.start()
self.P_Stop = PStop()
self.P_Stop.PT_event_detected.connect(self.Ext_Stop_Detect)
self.P_Stop.start()
def stop(self):
self.stop()
def __del__(self):
self.wait()
def run(self):
i = 1
while i <= dur: #self.dur:
iA = i
if self.stopExe == True:
durComplete = i
i = self.dur + 1 #Complete
elif self.pause == False: #12/15 added el
self.PBValueSig.emit(i)
i = i + 1
durComplete = i
time.sleep(1)
self.PBTimeActual.emit(iA)
time.sleep(1)
self.PBValueDone.emit(durComplete)
def Ext_Stop_Detect(self, channel):
print("CHANNEL " +str(channel))
答案 0 :(得分:2)
您看到的错误可能是由于this问题造成的。虽然你可能实际上并没有像那个问题那样在while循环中使用它,但是你很可能 多次调用它,因为你已经在Qt回调或类似中得到它。无论如何......如何将它与Qt整合......
GPIO.add_event_detect
方法在GPIO端口的状态更改时执行回调。监视GPIO的代码在单独的线程中运行,这意味着回调在单独的线程中运行。这给与Qt集成带来了一些问题,因为你需要确保以线程安全的方式执行它(如果你做错了,你可能最终会得到像this这样的错误。)
一个简单的解决方案是假设从Python线程调用时,Qt信号是线程安全的(这是GPIO库将使用的)。就我所知,这是一个悬而未决的问题,因为从技术上讲,它们被记录为从Python线程使用时不是线程安全的,但通常我发现它没问题。如果你想偶尔冒一个程序崩溃的风险,那么你就是“简单地”这样做的。
我假设你的程序中有一个QMainWindow
的子类,但这可以添加到任何Qt类中:
class MainWindow(QMainWindow):
event_detected = pyqtSignal(int)
def__init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.event_detected.connect(self.on_gpio_event)
GPIO.add_event_detect(channel, GPIO.BOTH, callback=self.event_detected.emit)
def on_gpio_event(self, channel):
# your code here!
print("An event occurred on channel {}".format(channel))
或者,这样做“绝对安全”的方式涉及更多的工作。在这里,您告诉GPIO库将任何事件放入线程安全的Python队列中,该队列由QThread读取线程,该队列发出Qt信号(Qt信号在从QThreads使用时绝对是线程安全的)
from six.moves.queue import Queue
class RelayThread(QThread):
event_detected = pyqtSignal(int)
def __init__(self, *args, **kwargs):
QThread.__init__(self, *args, **kwargs)
self.queue = Queue()
GPIO.add_event_detect(channel, GPIO.BOTH, callback=self.queue.put)
def run(self):
while True:
self.event_detected.emit(self.queue.get())
class MainWindow(QMainWindow):
def__init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.relay_thread = RelayThread()
self.relay_thread.event_detected.connect(self.on_gpio_event)
self.relay_thread.start()
@pyqtSlot(int)
def on_gpio_event(self, channel):
# your code here!
print("An event occurred on channel {}".format(channel))
无论如何,希望有所帮助。如果没有特定的代码,你就会有点难以做到,但总的来说,这就是你如何将覆盆子pi上的GPIO端口与Qt事件循环接口。