PyQT——URAT串口发送数据(上位机界面-农业灌溉)

实现功能

由于本人水平有限,仅用了最简单的一些pushButton和comboBox实现,主要功能:

  • 串口扫描、刷新、设置
  • 串口连接
  • 串口数据发送
  • 开始、停止手动灌溉
  • 开始、停止自动灌溉
页面实现效果

代码目录结构

代码案例
  • 代码已经全部添加注释,故不再做单独解释。
Main.py 
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
from ui.Ui_meanu import *
from drivers.driver_serial import *
import threading


class MainWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        # 固定窗口大小
        self.setFixedSize(650,400)
        # 点击按钮会触发的槽函数
        self.init_ui()

        # 实例化属性
        self.serial_ports=[] # 串口列表
        self.sp = None  # 串口对象
        self.scan_show_uart()
        self.baud_set()
        

    def init_ui(self):
        # 刷新串口的槽函数连接
        self.ui.pushButton_6.clicked.connect(self.scan_show_uart)
        # 链接串口的槽函数连接
        self.ui.pushButton.clicked.connect(self.connect_uart_slot)
        # 开始手动灌溉的槽函数连接
        self.ui.pushButton_2.clicked.connect(self.irrigation_slot)
        # 停止手动灌溉的槽函数连接
        self.ui.pushButton_3.clicked.connect(self.irrigation_slot)
        # 开始自动灌溉的槽函数连接
        self.ui.pushButton_4.clicked.connect(self.irrigation_slot)
        # 停止自动灌溉的槽函数连接
        self.ui.pushButton_5.clicked.connect(self.irrigation_slot)

        
    def irrigation_slot(self):
        '''灌溉的槽函数定义'''
        # 如果串口连接且是打开的才发数据
        if self.sp and self.sp.is_open():
            sender = self.sender()
            # 开始手动灌溉
            if sender is self.ui.pushButton_2:
                res,msg = self.sp.write(b'\x01') # 发送十六进制数据
                self.sp.write(b'\n')
            # 停止手动灌溉
            elif sender is self.ui.pushButton_3:
                res,msg = self.sp.write(b'\x00') # 发送十六进制数据
                self.sp.write(b'\n')
            # 开始自动灌溉
            elif sender is self.ui.pushButton_4:
                res,msg = self.sp.write(b'\x02') # 发送十六进制数据
                self.sp.write(b'\n')
            # 停止自动灌溉
            elif sender is self.ui.pushButton_5:
                res,msg = self.sp.write(b'\x03') # 发送十六进制数据
                self.sp.write(b'\n')
            # 如果发串口数据失败弹出警告
            if not res:
                QMessageBox.warning(self,'警告','发送失败,错误信息:'+msg)
            # 如果发送成功弹出提示
            else:
                QMessageBox.information(self,'提示','指令发送成功')  
        # 如果串口对象没连接弹出警告提示      
        else:
            QMessageBox.warning(self,'警告','请先连接串口')
    def connect_uart_slot(self):
        '''串口连接槽函数定义'''
        # 如果串口已经连接,再次点击就要关闭串口连接
        if self.sp:
            self.sp.close()
            self.sp = None
            self.ui.pushButton.setText('点击连接串口')
            self.ui.pushButton.setIcon(QIcon(":/img/img/disc.png"))
            return
        # 如果串口列表为空,弹出警告提示
        if not self.serial_ports:
            QMessageBox.warning(self,'警告','请先选择串口')
            return
        # 获取串口选中项
        index = self.ui.comboBox_3.currentIndex()
        uart_name = self.serial_ports[index][0]
        # 获取当前波特率选中项
        baud_rate = int(self.ui.comboBox_2.currentText())
        self.sp = SerialDevice(uart_name, baud_rate=baud_rate)  # 替换为您的串口名称、波特率和超时时间
        # 进行串口连接
        res, msg = self.sp.open()
        if not res:
            QMessageBox.warning(self,'警告',"串口无法连接,请检查是否被占用")
            return
        # 链接成功后改变状态
        self.ui.pushButton.setText('已连接(点击断开连接)')
        self.ui.pushButton.setIcon(QIcon(":/img/img/conn.png"))
        # 连接成功后就接受数据
        t = threading.Thread(target=self.read_thread,daemon=True)
        t.start()

    def read_thread(self):
        '''串口读取数据的线程函数'''
        while True:
            # 如果串口连接成功,就接收数据
            if self.sp and self.sp.is_open():
                data = self.sp.readline(1024)
                if data:
                    print(data)
            else:
                break
        
    def scan_show_uart(self):
        # 如果已经存在,需要清空串口列表和下拉选项,否则主动刷新时会增加多个
        if self.serial_ports:
            self.serial_ports = []
            self.ui.comboBox_3.clear()
        self.serial_ports = scan_serial_ports()
        # 如果存在串口,添加到下拉列表中
        if len(self.serial_ports) != 0: 
            for device, description in self.serial_ports:
                self.ui.comboBox_3.addItem(description)
    def baud_set(self):
        '''波特率默认设置'''
        self.ui.comboBox_2.addItems(['9600','19200','115200','256000','500000'])
        # 默认显示选中“115200”
        self.ui.comboBox_2.setCurrentIndex(2)
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    widget = MainWidget()
    widget.show()
    sys.exit(app.exec_())

Driver_serial.py
import serial
from serial import Serial
from serial.tools import list_ports


def scan_serial_ports():
    # 查看串口列表
    ports = list_ports.comports()
    # for port in ports:  # ListPortInfo
    #     # 设备名称、描述、硬件ID、供应商ID、产品ID、序列号、位置
    #     print(port.device, port.description, port.hwid, port.vid, port.pid, port.serial_number, port.location)
    return [(port.device, port.description) for port in ports]



class SerialDevice:
    def __init__(self, port, baud_rate=9600, timeout=None):
        self.port = port
        self.baud_rate = baud_rate
        self.timeout = timeout
        self.serial: Serial = None

    def open(self):
        try:
            self.serial = serial.Serial(self.port, self.baud_rate, timeout=self.timeout)
            if self.serial.is_open:
                # print(f"Serial port {self.port} opened successfully.")
                return True, f"Serial port {self.port} opened successfully."
        except serial.SerialException as e:
            print("请检查设备是否连接,或端口被其他软件占用,Failed to open serial port:", str(e))
            return False, str(e)

        return False, f"Serial port {self.port} open failed."

    def close(self):
        try:
            if self.serial and self.serial.is_open:
                self.serial.close()
                print("Serial port closed.")
                self.serial = None
            else:
                print("Serial port is not open.")
        except:
            pass

    def write(self, data):
        if not self.serial or not self.serial.is_open:
            print("Serial port is not open.")
            return False,"Serial port is not open."

        try:
            self.serial.write(data)
            print("Data written:", data)
            return True,"Data send successful"
        except serial.SerialException as e:
            print("Failed to write data:", str(e))
            return False,str(e)

    def flush(self):
        if not self.serial or not self.serial.is_open:
            print("Serial port is not open.")
            return None

        self.serial.flush()

    def read(self, num_bytes):
        if not self.serial or not self.serial.is_open:
            print("Serial port is not open.")
            return None
        try:
            return self.serial.read(num_bytes)
        except serial.SerialException as e:
            print("Failed to read data:", str(e))

        return None

    def readline(self):
        if not self.serial or not self.serial.is_open:
            print("Serial port is not open.")
            return

        try:
            return self.serial.readline()
        except serial.SerialException as e:
            print("Failed to read data:", str(e))

        return None

    def is_open(self):
        if not self.serial:
            return False

        return self.serial.is_open


if __name__ == '__main__':

    # 示例用法
    serial_ports = scan_serial_ports()
    if len(serial_ports) > 0:
        print("Available serial serial_ports:")
        for device, description in serial_ports:
            print(device, "->", description)
    else:
        print("No serial serial_ports found.")

    # 示例用法
    sp = SerialDevice("COM4", baud_rate=115200)  # 替换为您的串口名称、波特率和超时时间
    res, msg = sp.open()
    print("res = ", res)
    print("msg = ", msg)
    if res == True:
        # sp.write(b"Hello, Serial!\n")  # 发送数据
        sp.write(b"\x12\n")  # 发送数据
        # print(sp.read(10))  # 读取10个字节的数据
        print(sp.readline())  # 读取一行
        sp.close()
Ui_meanu.py(由QT页面编译而成)
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'c:\Users\Windows10\Desktop\02上课代码步骤\自动灌溉系统\ui\meanu.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(646, 447)
        self.label_3 = QtWidgets.QLabel(Form)
        self.label_3.setGeometry(QtCore.QRect(280, 40, 76, 22))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.label_3.setFont(font)
        self.label_3.setObjectName("label_3")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(190, 140, 78, 16))
        self.label_2.setObjectName("label_2")
        self.comboBox_2 = QtWidgets.QComboBox(Form)
        self.comboBox_2.setGeometry(QtCore.QRect(270, 130, 171, 31))
        self.comboBox_2.setObjectName("comboBox_2")
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(190, 180, 251, 31))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(10)
        font.setBold(True)
        font.setWeight(75)
        self.pushButton.setFont(font)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/img/img/disc.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton.setIcon(icon)
        self.pushButton.setObjectName("pushButton")
        self.pushButton_4 = QtWidgets.QPushButton(Form)
        self.pushButton_4.setGeometry(QtCore.QRect(190, 300, 111, 51))
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_2 = QtWidgets.QPushButton(Form)
        self.pushButton_2.setGeometry(QtCore.QRect(190, 230, 111, 51))
        self.pushButton_2.setObjectName("pushButton_2")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(190, 90, 78, 16))
        self.label.setTextFormat(QtCore.Qt.PlainText)
        self.label.setObjectName("label")
        self.comboBox_3 = QtWidgets.QComboBox(Form)
        self.comboBox_3.setGeometry(QtCore.QRect(270, 80, 171, 31))
        self.comboBox_3.setObjectName("comboBox_3")
        self.pushButton_3 = QtWidgets.QPushButton(Form)
        self.pushButton_3.setGeometry(QtCore.QRect(330, 230, 111, 51))
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_5 = QtWidgets.QPushButton(Form)
        self.pushButton_5.setGeometry(QtCore.QRect(330, 300, 111, 51))
        self.pushButton_5.setObjectName("pushButton_5")
        self.label_4 = QtWidgets.QLabel(Form)
        self.label_4.setGeometry(QtCore.QRect(450, 80, 54, 31))
        self.label_4.setText("")
        self.label_4.setObjectName("label_4")
        self.pushButton_6 = QtWidgets.QPushButton(Form)
        self.pushButton_6.setEnabled(True)
        self.pushButton_6.setGeometry(QtCore.QRect(450, 80, 31, 31))
        self.pushButton_6.setText("")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap(":/img/img/refresh.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_6.setIcon(icon1)
        self.pushButton_6.setObjectName("pushButton_6")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "智慧农业灌溉系统"))
        self.label_3.setText(_translate("Form", "串口设置"))
        self.label_2.setText(_translate("Form", "波特率设置 :"))
        self.pushButton.setText(_translate("Form", "点击连接串口"))
        self.pushButton_4.setText(_translate("Form", "开启自动灌溉"))
        self.pushButton_2.setText(_translate("Form", "开始手动灌溉"))
        self.label.setText(_translate("Form", "选 择 串 口:"))
        self.pushButton_3.setText(_translate("Form", "停止手动灌溉"))
        self.pushButton_5.setText(_translate("Form", "停止自动灌溉"))
from ui import img_rc
代码资源下载
  • 只有上位机界面,没有C代码。

点此下载

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的使用PyQt5实现串口通信的界面设计代码,其中包括了发送数据、停止发送数据以及刷新串口的功能: ``` python import sys import serial from PyQt5.QtCore import QIODevice, QSerialPort, QThread, pyqtSignal from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QTextEdit class SerialThread(QThread): data_received = pyqtSignal(str) def __init__(self, port, baudrate): super(SerialThread, self).__init__() self.port = port self.baudrate = baudrate self.is_running = True def __del__(self): self.is_running = False def run(self): ser = serial.Serial(self.port, self.baudrate) while self.is_running: if ser.in_waiting: data = ser.readline().decode() self.data_received.emit(data) ser.close() class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setWindowTitle("Serial Communication") self.resize(600, 400) # Create widgets self.text_edit_recv = QTextEdit(self) self.text_edit_recv.setGeometry(10, 10, 580, 180) self.text_edit_send = QTextEdit(self) self.text_edit_send.setGeometry(10, 200, 400, 180) self.btn_send = QPushButton('Send', self) self.btn_send.setGeometry(430, 200, 80, 30) self.btn_send.clicked.connect(self.send_data) self.btn_stop = QPushButton('Stop', self) self.btn_stop.setGeometry(520, 200, 80, 30) self.btn_stop.clicked.connect(self.stop_sending) self.btn_refresh = QPushButton('Refresh', self) self.btn_refresh.setGeometry(430, 250, 170, 30) self.btn_refresh.clicked.connect(self.refresh_ports) # Initialize variables self.port = None self.baudrate = 9600 self.serial_thread = None self.is_sending = False def send_data(self): if not self.is_sending: self.port.write(self.text_edit_send.toPlainText().encode()) self.is_sending = True def stop_sending(self): self.is_sending = False def refresh_ports(self): port_list = [port.device for port in QSerialPortInfo.availablePorts()] print("Available ports:", port_list) def open_serial_port(self): if not self.port: port_name = "COM6" # Replace with the actual port name self.port = serial.Serial(port_name, self.baudrate) self.serial_thread = SerialThread(port_name, self.baudrate) self.serial_thread.data_received.connect(self.display_data) self.serial_thread.start() def display_data(self, data): self.text_edit_recv.append(data) def closeEvent(self, event): if self.port: self.port.close() if self.serial_thread: del self.serial_thread if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ``` 在该示例代码中,我们使用了PyQt5中的QSerialPort模块来实现串口通信。SerialThread类继承自QThread,用于在后台线程中读取串口数据;MainWindow类继承自QMainWindow,用于创建GUI界面和处理相关事件。界面中包括了一个用于显示接收数据的文本框、一个用于输入发送数据的文本框、一个用于发送数据的按钮、一个用于停止发送数据的按钮以及一个用于刷新串口的按钮。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值