Не могу в потоке QThread передать или считать данные по COM порту на PYQT 5
Необходимо считать и записать данные по COM порту в потоке. Не принимает данные по COM порту в потоке. Не понимаю как передать сигнал метода потока правильно. Программирую недавно, буду рад любому совету.
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import QIODevice, QByteArray
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
# Класс потока где обьявляется счетчик и приниматются или передаются данные по COM порту
class MyThread(QtCore.QThread):
#mysignal = QtCore.pyqtSignal(str)
mysignal = QtCore.pyqtSignal(QByteArray, name="My_Signal")
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
self.serport = QSerialPort()
self.serport.setBaudRate(9600)
self.serport.setPortName("COM3")
self.serport.setDataBits(8)
self.serport.setParity(0)
self.serport.setStopBits(1)
print(self.serport.open(QIODevice.ReadWrite))
print(self.serport.isReadable())
self.running = False
self.count = 0
# функция с телом потока
def run(self):
self.running = True
while self.running:
self.count += 1
#self.mysignal.emit("count = %s" % self.count)
buf = self.serport.readLine(14)
if buf:
self.mysignal.emit(buf)
print(buf)
self.sleep(1)
# Класс главного окна со счетчиком и привзкой потока через сигнал класса MyThread
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.label = QtWidgets.QLabel("Нажми кнопку для запуска потока")
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.btnStart = QtWidgets.QPushButton("Запустить поток")
self.btnStop = QtWidgets.QPushButton("Остановить поток")
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addWidget(self.label)
self.vbox.addWidget(self.btnStart)
self.vbox.addWidget(self.btnStop)
self.setLayout(self.vbox)
self.mythread = MyThread()
self.btnStart.clicked.connect(self.on_start)
self.btnStop.clicked.connect(self.on_stop)
self.mythread.mysignal.connect(self.on_change, QtCore.Qt.QueuedConnection)
# Старт потока
def on_start(self):
if not self.mythread.isRunning():
self.mythread.start()
# Останавливаем поток
def on_stop(self):
self.mythread.running = False
# Метод который получает данные через сигнал потока класса MyThread
def on_change(self, s):
self.label.setText(str(s))
# Метод который останавливает поток класса MyThread
def closeEvent(self, event):
self.hide()
self.mythread.running = False
self.mythread.wait(5000)
event.accept()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle("Запуск и остановка потока")
window.resize(300,100)
window.show()
sys.exit(app.exec_())
Ответы (2 шт):
Автор решения: Alexander Chernin
→ Ссылка
Создавайте объект серийного порта в методе run, чтобы он работал в рабочем окружении (адресном пространстве) потока.
Общая схема такая:
class MyThread(QThread):
# булевский флаг активности/завершения работы потока
_quit = False
def run(self):
serial = QSerialPort()
# необходимые настройки идут либо тут, либо в цикле, ниже,
# если вы будете их менять в процессе работы потока и серийного порта.
# В таком случае их надо постоянно проверять и пересоздавать порт, при необходимости
# Проверяем флаг выхода/завершения работы потока
while not self._quit:
if not serial.open(QIODevice.ReadWrite):
print('Не могу открыть порт. Ошибка - 'serial.error())
return
# Передача данных
if <есть данные на передачу>:
# Следующие пара функций вызываются вместе последовательно
# передаем данные в com-порт
serial.write(requestData)
# ожидаем пока все данные будут переданы
serial.waitForBytesWritten(<Время для передачи данных>)
# Получение данных
# currentWaitTimeout - время ожидания, в течении
# которого данных должны прийти, иначе вернется False и мы пойдем дальше
if serial.waitForReadyRead(currentWaitTimeout):
# Считываем то, что пришло
QByteArray responseData = serial.readAll()
# Останавливаем поток
def stop(self):
self._quit = True
Автор решения: eri
→ Ссылка
В Qt уже есть основной цикл и слот что в порту появились данные.
class MyThreadedPort(QtCore.QObject):
#mysignal = QtCore.pyqtSignal(str)
mysignal = QtCore.pyqtSignal(QByteArray, name="My_Signal")
def __init__(self, port="COM3", parent=None):
QtCore.QObject.__init__(self) # отдельный тред делается без parent
self.thread = QtCore.QThread()
self.moveToThread(self.thread) # уводим слоты в тред
self.serport = QSerialPort()
self.serport.setBaudRate(9600)
self.serport.setPortName(port)
self.serport.setDataBits(8)
self.serport.setParity(0)
self.serport.setStopBits(1)
self.thread.moveToThread(self.thread) # уводим порт в свой поток
print(self.serport.open(QIODevice.ReadWrite))
print(self.serport.isReadable())
self.serport.readyRead.connect(self.readyread)
self.running = False
self.count = 0
@QtCore.pyqtSlot()
def stop(self):
self.running = False # флаг ставится в треде - мутекс не нужен (QueuedConnection)
self.serport.close() # достаточно закрыть порт
@QtCore.pyqtSlot()
def readyread(self):
while self.running and self.serial.bytesAvailable() >= 14:
self.count += 1
buf = self.serport.readLine(14)
self.mysignal.emit(buf)
@QtCore.pyqtSlot('QByteArray')
def write(self, data):
self.serport.write(data)
self.serport.flush()