网站首页

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 软件工程 > 操作系统 > 嵌入式 >

使用pyside6编写简单的串口上位机

时间:2026-03-02 19:43

人气:

作者:admin

标签:

导读:一、设计UI界面 使用qt设计师 需要注意的是 调整整体大小 最后设置整体自动调整大小时,对于QMainWindow窗口需要右键最基本的框,选择布局,不然在右侧是没有布局选项的 窗口放大时非...

使用qt设计师

需要注意的是

调整整体大小

最后设置整体自动调整大小时,对于QMainWindow窗口需要右键最基本的框,选择布局,不然在右侧是没有布局选项的

窗口放大时非对话框有最大大小,不跟着变大

设置对应窗口的对齐为 0

按钮进入对齐后选择minimum,可以变大

默认时

编写基本框架

选择自己使用的是QMainWindow还是QWidget

导入pyside的库

from PySide6.QtWidgets import QApplication,QMainWindow,QWidget

引用对应界面库

#ui为上一层目录
from ui.Ui_serial_up import Ui_MainWindow
class MyWindow(QMainWindow,Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

if __name__ == "__main__":
    app = QApplication()
    window = MyWindow()
    window.show()
    sys.exit(app.exec())

逻辑部分

导入串口所需库

from PySide6.QtCore import QThread,Signal

import serial
import serial.tools.list_ports

配置大体框架

#接收线程
class SerialReadThread(QThread):
    ReadSignal = Signal(str) #接收信号
    def __init__(self,serial_obj):
        super().__init__()
        
    def run():
    
    def stop():

子窗口

子窗口现在qt设计师设计好,使用QSialog类型

#子窗口界面
class SettingSerial(QDialog,Ui_Dialog):
    def __init__(self,parent = None):#parent 为传入形参接口
        super().__init__(parent)
        self.setupUi(self)#调用子窗口Ui
        #绑定自带的确认和取消键
        #连接固定的确定取消方法
        #self.reject()和self.accept()是取消和确认方法
        self.buttonBox.accepted.connect(self.buttonAccept)
        self.buttonBox.rejected.connect(self.reject)
        
    def buttonAccept(self): 
        self.accept()
    def backSetting(self):
    '''子窗口返回方法,同与父窗口调用后关闭子窗口时调用'''

父窗口框架

#界面
class MyWindow(QMainWindow,Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)#调用父窗口Ui
        
    def SerialSend(self):
    
    def SerialReceive(self):
    
    def SerialStart(self):
    
    def SerialStop(self):
    
    def ClearTx(self):
    
    def ClearRx(self):
    

编写代码

首先编写主界面的基本操作

#清除
def clearTx(self):
        self.TextEdit_2.clear()
    
    def clearRx(self):
        self.TextEdit_1.clear()
#变量定义
def initVariable(self):
    self.baudrate = "115200"
    self.bytesize = '8'
    self.stopbits_set = '1'
    self.parity_set = 'None'
    # 串口对象
    self.serial_port = None
    self.reader_thread = None
    self.send_byte_count = 0  #发送字节总数
    self.receive_byte_count = 0  #接收字节总数
#按键关联方法
def ConnectButton(self):
    #关联按键
    self.pushButton_5.clicked.connect(self.clearTx)
    self.pushButton.clicked.connect(self.clearRx)
    #打开串口
    self.pushButton_2.clicked.connect(self.SerialSwitch)
    #刷新端口
    self.action10.setShortcut('F5')
    self.action10.setStatusTip('刷新端口')
    self.action10.triggered.connect(self.RefreshSerial)
    #串口设置
    self.pushButton_4.clicked.connect(self.open_dialog)
    self.action20.setStatusTip('配置串口')
    self.action20.triggered.connect(self.open_dialog)
    #更改baud下拉栏
    self.comboBox_2.currentIndexChanged.
        connect(self.backBaudrate)
    #发送数据
    self.pushButton_3.clicked.connect(self.SendData)

打开串口关闭串口

def SerialSwitch(self):
    '''设置标志位,区分打开关闭串口'''
    if self.serial_port and self.serial_port.is_open:
        self.closeSerial()
    else:
        self.StartSerial()
def StartSerial(self):
    #读取当前com口
    is_com = self.comboBox.currentText()
    if not is_com :
        QMessageBox.warning(self,"warning","没有可用的串口")
        return
    #读取的端口从 - 分割开
    com = is_com.split(" - ")[0]
    #把确认的端口信息赋值给局部变量,后面赋值给串口库形参
    baudrate = self.baudrate
    bytesize = int(self.bytesize)
    stopbits = serial.STOPBITS_ONE
    if self.stopbits_set == '1.5':
        stopbits = serial.STOPBITS_ONE_POINT_FIVE
    elif self.stopbits_set == '2':
        stopbits = serial.STOPBITS_TWO
    parity = serial.PARITY_NONE
    if self.parity_set == 'Odd':
        parity = serial.PARITY_ODD
    elif self.parity_set == 'Even':
        parity = serial.PARITY_EVEN
    elif self.parity_set == 'Mark':
        parity = serial.PARITY_MARK
    elif self.parity_set == 'Space':
        parity = serial.PARITY_SPACE

    try:
        self.serial_port = serial.Serial(
            port=com,
            baudrate=baudrate,
            bytesize=bytesize,
            stopbits=stopbits,
            parity=parity,
            timeout=0.1   # 读超时,让线程可以循环检查停止标志
        )
    except Exception as e:
        QMessageBox.critical(self, "错误", f"无法打开串口:{e}")
        return
    #开启多线程
    self.reader_thread = SerialReadThread(self.serial_port)
    #判断ReadSignal信号是否接收到数据,接收到进入数据处理
    self.reader_thread.ReadSignal.connect(self.on_data_received)
    self.reader_thread.start()
    #打开串口后将按钮改为关闭
    self.pushButton_2.setText('关闭串口')
    #失能部分按键,防止误触,出错
    self.set_serial_settings_enabled(False)

def closeSerial(self):
    if self.reader_thread:
        self.reader_thread.stop()
        self.reader_thread = None
    if self.serial_port and self.serial_port.is_open:
        self.serial_port.close()
    self.serial_port = None
    self.pushButton_2.setText("打开串口")
    self.set_serial_settings_enabled(True)

失能使能模块方法包装

def set_serial_settings_enabled(self, enabled):
    self.comboBox.setEnabled(enabled)
    self.comboBox_2.setEnabled(enabled)
    self.pushButton_4.setEnabled(enabled)
    self.action20.setEnabled(enabled)

打开串口的时候,关闭其他使能

设置串口 读 多线程

class SerialReadThread(QThread):
    #创建信号 , bytes类型
    ReadSignal = Signal(bytes)

    def __init__(self,serial_port):
        super().__init__()
        self.serial_port = serial_port
        self.is_running = False

    def run(self):
        self.is_running = True
        while self.is_running and self.serial_port and self.serial_port.is_open:
            try:
            #接收数据
                data = self.serial_port.read(self.serial_port.in_waiting or 1)
                if data:
                    #将接收到的数据连接上信号
                    self.ReadSignal.emit(data)
            except Exception as e:
                break
        

    def stop(self):
        self.is_running = False
        #等待主线程完成,使子线程完全退出
        self.wait()

接收数据处理

def on_data_received(self,data):
    #状态栏的变量,接收数据+1
    self.receive_byte_count += len(data)
    self.update_status_bar()
    #判断hex是否勾选
    if self.checkBox_3.isChecked():
        hex_str = data.hex().upper()

        hex_str = ' '.join(hex_str[i:i+2] for i in range(0, len(hex_str), 2))
        self.TextEdit_1.insertPlainText(hex_str + " ")
    else:
        try:
            text = data.decode('utf-8', errors='replace')
        except:
            text = str(data)
        self.TextEdit_1.insertPlainText(text)

    #自动滚动
    #返回光标
    cursor = self.TextEdit_1.textCursor()
    #光标移动到最后
    cursor.movePosition(cursor.MoveOperation.End)
    #页面到光标处
    self.TextEdit_1.setTextCursor(cursor)

子窗口

子窗口

class SettingSerial(QDialog,Ui_Dialog):
    def __init__(self,parent = None):
        super().__init__(parent)
        self.setupUi(self)

        self.buttonBox.accepted.connect(self.buttonAccept)
        self.buttonBox.rejected.connect(self.reject)
    #刷新子窗口com,父子一致
    def refreashCom(self,postList,currentPort):
        self.comboBox.clear()
        self.comboBox.addItems(postList)
        if currentPort :
            Index = self.comboBox.findText(currentPort)
            if Index>=0:
                self.comboBox.setCurrentIndex(Index)
    #刷新子窗口,父子一致
    def refreashBaud(self,baudrate):
        if baudrate :
            Index = self.comboBox_2.findText(baudrate)
            if Index>=0:
                self.comboBox_2.setCurrentIndex(Index)
    #刷新子窗口,父子一致
    def refreashother(self,bytesize,stopbits_set,parity_set):
        if bytesize :
            Index = self.comboBox_3.findText(bytesize)
            if Index>=0:
                self.comboBox_3.setCurrentIndex(Index)
        if stopbits_set :
            Index = self.comboBox_4.findText(stopbits_set)
            if Index>=0:
                self.comboBox_4.setCurrentIndex(Index)
        if parity_set :
            Index = self.comboBox_6.findText(parity_set)
            if Index>=0:
                self.comboBox_6.setCurrentIndex(Index)
    
    def buttonAccept(self): 
        self.accept()

    def backSetting(self):
        com = self.comboBox.currentText()#.split(" - ")[0]
        return (com
                ,self.comboBox_2.currentText()
                ,self.comboBox_3.currentText()
                ,self.comboBox_4.currentText()
                ,self.comboBox_6.currentText()
                ,self.comboBox_5.currentText()
                )     

父窗口调用子窗口

父窗口按键关联

def open_dialog(self):
    dialog = SettingSerial(self)
    '''刷新数据'''
    self.RefreshSerial()
    dialog.refreashCom(self.postList,self.currentPort)
    dialog.refreashBaud(self.baudrate)
    dialog.refreashother(self.bytesize,self.stopbits_set,self.parity_set)
    #使用.exec()方法,等待子窗口点击确认,此时可以返回一些数据
    if dialog.exec() == QDialog.Accepted:
        self.settings = dialog.backSetting()
        self.settingAccept(self.settings)

返回数据

def settingAccept(self,settings):
    self.currentPort,self.baudrate,self.bytesize,self.stopbits_set,self.parity_set,flow_set = settings
    if self.currentPort :
        Index = self.comboBox.findText(self.currentPort)
        if Index>=0:
            self.comboBox.setCurrentIndex(Index)
    if self.baudrate :
        baud = self.comboBox_2.findText(self.baudrate)
        if baud>=0:
            self.comboBox_2.setCurrentIndex(baud)

发送数据

def SendData(self):
    if not self.serial_port or not self.serial_port.is_open:
        QMessageBox.warning(self, "警告", "请先打开串口!")
        return
    #读取当前发送框有什么
    text = self.TextEdit_2.toPlainText()
    if not text:
        return
    #判断是不是 使用hex方式
    if self.checkBox_3.isChecked():
        hex_str = ''.join(text.split())
        try:
            #.fromhex 转16进制
            data = bytes.fromhex(hex_str)
        except ValueError as e:
            QMessageBox.warning(self, "错误", f"无效的十六进制字符串:{e}")
            return
    else:
        #ASCII发送
        data = text.encode('utf-8', errors='ignore')
    try:
        #返回发送的长度
        sent_bytes = self.serial_port.write(data)
        #状态栏
        self.send_byte_count += sent_bytes
        self.update_status_bar()
    except Exception as e:
        QMessageBox.critical(self, "错误", f"发送失败:{e}")

运行

if __name__ == "__main__":
    app = QApplication()
    window = MyWindow()
    window.setWindowIcon(QIcon("icon.png"))
    window.show()
    sys.exit(app.exec())

状态栏

可以创建QLabel窗口,然后使用.addPermanentWidget(self.label)一直添加到状态栏右侧

def status_bars(self):
    '''多状态栏'''
    status_text = f"接收:{self.receive_byte_count} 字节 | 发送:{self.send_byte_count} 字节"
    self.serial_status_label = QLabel(status_text)
    self.statusBar.addPermanentWidget(self.serial_status_label)

    self.textlabel = QLabel(' 天天好心情')
    self.statusBar.addPermanentWidget(self.textlabel)

def update_status_bar(self):
    """更新状态栏显示:发送/接收字节数"""
    # status_text = f"接收:{self.receive_byte_count} 字节 | 发送:{self.send_byte_count} 字节"
    # self.statusBar.setStyleSheet("QStatusBar { padding-left: 1000px; }")
    # 设置状态栏文本(showMessage默认显示5秒,传0表示永久显示)
    # self.statusBar.showMessage(status_text, 0)
    self.serial_status_label.setText(f"接收:{self.receive_byte_count} 字节 | 发送:{self.send_byte_count} 字节")

https://gitee.com/liliww/serial-upper-computer.git

温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信