انجمن‌های فارسی اوبونتو

کمک و پشتیبانی => برنامه‌سازی => نویسنده: قاسم طلایی در 22 آذر 1398، 12:27 ب‌ظ

عنوان: مشکل اجرا در pyqt5
ارسال شده توسط: قاسم طلایی در 22 آذر 1398، 12:27 ب‌ظ
با سلام خدمت دوستان
من یه نرم افزار ساده با pyqt5 ساختم که کارش مانیتورینگ اطلاعات برد آردوینو هست.یعنی آردوینو به کامپیوتر وصل میشه و نرم افزار اونا رو مانیتور میکنه و فرمان به سمت میکرو صادر میکنه.
مشکل من بد اجرا شدن نرم افزار هست.با اینکه خیلی بار پردازشی زیادی نداره ولی خیلی سنگین اجرا میشه.البته این زمانی اتفاق میفته که درون while true قرار میگیره.یه خورده سرچ کردم و متوجه شدم باید عبارت QApplication.processEvents() رو در قسمت هایی که یه مقدار بار پردازشی سنگین میشه قرار داد.این کار رو کردم و نرم افزار یه خورده روان تر شد ولی باز هم یه خورده لگ داره.
اینم تصویر برنامه من هست.

https://pasteboard.co/IL1S2oO.png
 (https://pasteboard.co/IL1S2oO.png)
و این هم کد برنامه هست.
import sys
from PyQt5.QtWidgets import QDialog ,QApplication ,QSlider ,QProgressBar
from out import *
import serial
import matplotlib.pyplot as plt
from matplotlib import style

lamp=0
y_temp=[]
y_hum=[]

class MyAPP(QDialog):
    def __init__(self):
        super().__init__()
        self.ui=Ui_Dialog()
        self.ui.setupUi(self)
        self.ui.pushButton.clicked.connect(self.message)
        self.ui.find_port_push.clicked.connect(self.find_port)
        self.ui.close.clicked.connect(self.close_port)
        self.ui.lamp_change.valueChanged.connect(self.change_lamp)
        self.show()
    def change_lamp(self):
        global lamp
        QApplication.processEvents()
        lamp=self.ui.lamp_change.value()
        if lamp == 0:
            self.ui.lamp_status.setText('خاموش')
        if lamp == 1:
            self.ui.lamp_status.setText('روشن')
        QApplication.processEvents()
    def close_port(self):
        ser=serial.Serial()
        global x
        x = 0
        ser.close()
        self.ui.check_connect.setText("قطع اتصال.صبر کنید")
        style.use('fivethirtyeight')
        #hum graph
        plt.subplot(2,1,1)
        plt.plot(y_hum)
        plt.title('Humidity chart')
        plt.ylabel('Humidity')
        #temp graph
        plt.subplot(2,1,2)
        plt.plot(y_temp)
        plt.title('Temperature chart')
        plt.ylabel('Temperature ($^\circ$C)')
        #show graph
        plt.show()
    def find_port(self):
        ser = serial.Serial()
        ser.baudrate=int(self.ui.buadrate.itemText(self.ui.buadrate.currentIndex()))
        coms=['COM1','COM2','COM3','COM4','COM5','COM6','COM7','COM8','COM9','COM10','COM11','COM12']
        for x in coms:
            ser.port=x
            try:
                ser.open()
            except:
                self.ui.find_port_label.setText("لطفا صبر کنید...")
            finally:
                if ser.is_open == True :
                    self.ui.find_port_label.setText(x)
                    ser.close()
                    break
                else:
                    self.ui.find_port_label.setText('پورت پیدا نشد !')
    def message(self):
        global x
        global lamp
        x = 1
        ser = serial.Serial()
        ser.baudrate=int(self.ui.buadrate.itemText(self.ui.buadrate.currentIndex()))
        ser.port=self.ui.port.itemText(self.ui.port.currentIndex())
        try:
            ser.open()
        except:
            self.ui.check_connect.setText("اتصال ناموفق")
        finally:
            if ser.is_open == True :
                QApplication.processEvents()
                self.ui.check_connect.setText("اتصال برقرار است")
                while True:
                    #QApplication.processEvents()
                    if ser.is_open == True:
                        #QApplication.processEvents()
                        s=ser.readline()
                        s=str(s)
                        s=s.strip('b')
                        s=s.strip("'")
                        s=s.split("&")
                        s[1]=s[1].strip("\\r\\n")
                        QApplication.processEvents()
                        if s[0] != ' NAN':
                            QApplication.processEvents()
                            self.ui.lcd_temp.setText(s[0])
                            QApplication.processEvents()
                            self.ui.bar_temp.setValue(abs(float(s[0])))
                            QApplication.processEvents()
                            self.ui.lcd_hum.setText(s[1])
                            QApplication.processEvents()
                            self.ui.bar_hum.setValue(abs(float(s[1])))
                            QApplication.processEvents()
                            y_hum.append(abs(float(s[1])))
                            y_temp.append(abs(float(s[0])))
                        ser.write(lamp)
                        if x != 1:
                            x = 1
                            break
                       
if __name__=="__main__":
    app=QApplication(sys.argv)
    w=MyAPP()
    w.show()
    sys.exit(app.exec_())

عنوان: پاسخ : مشکل اجرا در pyqt5
ارسال شده توسط: Geek در 22 آذر 1398، 07:16 ب‌ظ
باید از کلاس QThread استفاده کنی:
https://doc.qt.io/qt-5/qthread.html
اطلاعات بیشتر:
https://en.wikipedia.org/wiki/Multithreading_(computer_architecture)
عنوان: پاسخ : مشکل اجرا در pyqt5
ارسال شده توسط: احمد حمزه ئی در 23 آذر 1398، 03:22 ب‌ظ
می‌تونید بجای pyserial از QSerialPort (https://doc.qt.io/qt-5/qserialport.html) استفاده کنید (برای مثال این پاسخ (https://stackoverflow.com/a/55071476) رو ببینید).
وقتی یک بایت از درگاه سریال دریافت شد، سیگنال readyRead صدا زده میشه و بدون استفاده از حلقه بایت‌های دریافتی در دسترس هست.
به عنوان یک پروتکل ساده، میشه خروجی حسگرها رو در میکروکنترلر به شکل یک رشته درآورد که داده‌های مختلف با کاما جدا شده:
22.51,10.0\nمثلا عدد اول دما و دومی رطوبت هست. کاراکتر n\ هم انتهای پیام رو مشخص میکنه.
در پایتون وقتی کاراکتر n\ رسید یعنی یک پیام کامل دریافت شد، بنابراین کد زیر اجرا میشه و متن پیام در متغیر text و داده‌ها بصورت عدد اعشاری در آرایه data‌ قرار می‌گیره:
text = self.serial.readLine().data().decode().rstrip()
data = [float(x) for x in text.split(',')]

نمونه برنامه کامل، تصویرش رو پیوست کردم:
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QComboBox, QPushButton, QVBoxLayout, QWidget, QTextEdit, QLabel
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
from PyQt5.QtCore import QIODevice

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Serial Port')
        self.statusBar().showMessage('Ready')

        layout = QVBoxLayout()
        widget = QWidget()
        widget.setLayout(layout)

        self.textView = QTextEdit(readOnly=True)
        layout.addWidget(self.textView)

        self.temperatureLabel = QLabel('Temperature: no data')
        layout.addWidget(self.temperatureLabel)

        self.humidityLabel = QLabel('Humidity: no data')
        layout.addWidget(self.humidityLabel)

        self.portCombo = QComboBox()
        ports = QSerialPortInfo.availablePorts()
        self.portCombo.addItems([port.portName() for port in ports])
        layout.addWidget(self.portCombo)

        self.connectButton = QPushButton('Connect')
        layout.addWidget(self.connectButton)
        self.connectButton.clicked.connect(self.connectSerial)

        self.serial = QSerialPort(self)
        self.serial.readyRead.connect(self.readData)

        self.setCentralWidget(widget)
        self.show()

    def connectSerial(self):
        if not self.serial.isOpen():
            portName = self.portCombo.currentText()
            self.serial.setPortName(portName)
            successful = self.serial.open(QIODevice.ReadWrite)

            if successful:
                self.statusBar().showMessage('Port opened.')
                self.connectButton.setText('Disconnect')
            else:
                self.statusBar().showMessage('Port was not opened.')
        else:
            self.serial.close()
            self.statusBar().showMessage('Port closed.')
            self.connectButton.setText('Connect')

    def readData(self):
        while self.serial.canReadLine():
            self.statusBar().showMessage('Data received.')
            text = self.serial.readLine().data().decode().rstrip()
            self.textView.append(text)

            data = [float(x) for x in text.split(',')]
            self.temperatureLabel.setText('Temperature: {}'.format(data[0]))
            self.humidityLabel.setText('Humidity: {}'.format(data[1]))

if __name__=="__main__":
    app = QApplication(sys.argv)
    win = Window()
    sys.exit(app.exec_())

توی این کد، خط self.serial.readyRead.connect(self.readData) سیگنال readyRead رو به تابع readData متصل میکنه و با دریافت هر بایت این تابع اجرا میشه.
در داخل تابع با چک کردن ()self.serial.canReadLine میشه فهمید که یک پیام کامل دریافت شده.
عنوان: پاسخ : مشکل اجرا در pyqt5
ارسال شده توسط: قاسم طلایی در 24 آذر 1398، 09:49 ب‌ظ
بسیار متشکرم از پاسخ جامع شما. با استفاده از کتابخانه qserialport مشکل حل شد. البته مشکل اصلی من در قسمت پایتون بود نه در قسمت میکرو.
بازم متشکرم