基于PyQT5解析串口数据并通过GUI显示应用开发

您所在的位置:网站首页 python串口通讯书籍 基于PyQT5解析串口数据并通过GUI显示应用开发

基于PyQT5解析串口数据并通过GUI显示应用开发

2024-07-16 01:25| 来源: 网络整理| 查看: 265

解析串口数据并通过GUI显示应用开发-Python

​ 本片文章主要介绍如何通过Python开发一款UI界面的应用,该应用能实现对来自串口数据的接收和解析,将解析后的数据显示在UI界面上,同时实现数据帧接收频率的计算与超时接收的监测。环境:PyCharm Community Edition 2021.2、Python 3.7.6(高版本在安装pyqt5-tools是会出现报错)

在这里插入图片描述

一、GUI绘制 1.1、安装UI设计的第三方库

首先安装PyQT5,可以在window的命令提示符从清华源进行安装

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQT5

再安装pyqt5-tools包,这个第三方库包含qtdesinger工具

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyqt5-tools

在这里插入图片描述

1.2、在Pycharm中配置外部工具环境 先点击Pycharm右上角的齿轮按键,进入设置页面

在这里插入图片描述

在工具->外部工具->“+”图标,添加外部工具

在这里插入图片描述

添加qtdesinger工具(绘制ui文件),变量配置如下

在这里插入图片描述

D:\APP\Python3.7.6\Lib\site-packages\qt5_applications\Qt\bin\designer.exe (这个找到自己designer.exe所在的目录) $FileDir$\$FileName$ $FileDir$

同样添加pyuic5工具(将制作的ui文件,转化成Py文件),变量配置如下

D:\APP\Python3.7.6\Scripts\pyuic5.exe (这个找到自己pyuic5.exe所在的目录) $FileName$ -o $FileNameWithoutExtension$.py $FileDir$

最后添加pyrcc工具,变量配置如下

D:\APP\Python3.7.6\Scripts\pyuic5.exe (这个找到自己pyuic5.exe所在的目录) $FileName$ -o $FileNameWithoutExtension$.py ,working directory:$FileDir$ D:\APP\Python3.7.6\Scripts (这个找到自己py安装的目录) 1.3、利用qtdesinger绘制UI界面

首先从 工具->External Tools->qtdesinger,启动qtdesinger

在这里插入图片描述

可以创建一个Main Window窗口,在窗口内部绘制UI界面

在这里插入图片描述

这里就不具体地用文字描述整个ui界面的搭建过程,就简单介绍一下整个界面和需要使用的组件,以及需要修改的属性。QT Desinger的界面如下,上方是一些调整组件布局的工具;左侧是ui界面上的一些组件(按键、标签、文本框之类的);可以将左侧的组件拖到中间的界面,然后通过上方的布局工具,调整这些工具的位置;当选中一个组件后,可以通过右侧的属性框,修改组件的一些属性(这里建议把所有组件的Name都改一下,方便后面程序设计好找到对应的组件)

在这里插入图片描述

将设计好的ui文件保存到工程所在的目录下面

1.4、测试UI界面

右击ui文件 -> External Tools -> pyuic5,将刚刚保存的ui文件转成py文件 在这里插入图片描述

在生成的py文件后面添加如下程序,

if __name__ == "__main__": import sys from PyQt5.QtWidgets import QApplication, QMainWindow app = QApplication(sys.argv) MainWindow = QMainWindow() ui = Ui_MainInfo() # 这里需要根据自己的ui类名称进行修改 ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())

右击运行该文件的结果

在这里插入图片描述

二、串口数据接收与解析 2.1、安装串口第三方库

Python使用串口需要安装pyserial库

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyserial 2.2、串口的使用

测试用例

import serial#导入串口通信库 from time import sleep ser = serial.Serial() def port_open_recv():#对串口的参数进行配置 ser.port='com3' ser.baudrate=9600 ser.bytesize=8 ser.stopbits=1 ser.parity="N"#奇偶校验位 ser.open() if(ser.isOpen()): print("串口打开成功!") else: print("串口打开失败!") #isOpen()函数来查看串口的开闭状态 def port_close(): ser.close() if(ser.isOpen()): print("串口关闭失败!") else: print("串口关闭成功!") def send(send_data): if(ser.isOpen()): ser.write(send_data.encode('utf-8'))#编码 print("发送成功",send_data) else: print("发送失败!") if __name__ == '__main__': port_open_recv() while True: a=input("输入要发送的数据:") send(a) sleep(0.5)#起到一个延时的效果,这里如果不加上一个while True,程序执行一次就自动跳出了

常用接口函数

ser.isOpen():查看端口是否被打开。 ser.open() :打开端口‘。 ser.close():关闭端口。 ser.read():从端口读字节数据。默认1个字节。 ser.read_all():从端口接收全部数据。 ser.write("hello"):向端口写数据。 ser.readline():读一行数据。 ser.readlines():读多行数据。 in_waiting():返回接收缓存中的字节数。 flush():等待所有数据写出。 flushInput():丢弃接收缓存中的所有数据。 flushOutput():终止当前写操作,并丢弃发送缓存中的数据。 2.3、数据帧的解析

数据帧的内容如下,一共有12个数据,我们需要获取以逗号分割,等号后面的数据。所以提出数据的思路就不难看出,先将字符串以逗号分割生成12个列表(每个列表的内容也是字符串),再对每个列表的内容以等于号进行分割,取等号后面的内容,具体实现程序如下。

sen1_d=6553,sen2_d=69,sen3_d=23,sen4_d=6553,sen5_d=49,sen6_d=23,sen7_d=6553,sen8_d=31,sen9_d=142,sen10_d=6553,sen11_d=21,sen12_d=6553 def process(message:str): res = list() if message.count("=") == 12: message_list = message.split(",") for x in message_list : res.append(x.split("=")[1]) return res if __name__ == "__main__": test = "sen1_d=6553,sen2_d=69,sen3_d=23,sen4_d=6553,sen5_d=49,sen6_d=23,sen7_d=6553,sen8_d=31,sen9_d=142,sen10_d=6553,sen11_d=21,sen12_d=6553" res_list = process(test) print(len(res_list)) print(res_list) 三、多任务创建 3.1、启动UI界面

创建main.py文件,所需的第三方库,以及自己创建的ui界面和数据帧处理函数

import sys import time from PyQt5.QtWidgets import * from PyQt5.QtCore import * from MainInfo import Ui_MainInfo import serial#导入串口通信库 import data_process

创建自己的ui界面类,该类需要继承QMainWindow类和自己设计Ui_MainInfo类,并在初始化函数定义自己需要使用的变量、通过连接槽关联两个线程(串口接收数据线程、监测是否超时线程)以及按键连接函数的具体实现,具体程序实现如下:

class MyMainForm(QMainWindow, Ui_MainInfo): def __init__(self, parent=None): super(MyMainForm, self).__init__(parent) self.setupUi(self) # 定义变量 self.com = "com3" self.baud = 115200 self.switch_state = bool(0) self.count = 0 # 计算两个有效数据帧的时间差 self.start_time = time.time() self.end_time = time.time() self.time = 0 self.receive_message = "" # 监测串口已打开时,多长时间没有手有效数据帧 self.check_time_start = time.time() self.check_time_end = time.time() self.limit_time = 6.0 self.check = 0 # 连接槽关联连接按键 self.connect_button.clicked.connect(self.connection_button_cliked) self.set_limit_time_button.clicked.connect(self.set_limit_time) # 连接槽关联线程 self.thread = process_task() self.thread.start() self.thread.sig.connect(self.update_info) self.check_thread = check_task() self.check_thread.start() # 显示默认参数 self.com_value.setText(f"{self.com}") self.baud_value.setText(f"{self.baud}") self.limit_time_value.setText(f"{self.limit_time}") def update_info(self,info): self.receive_message = info temp_list = data_process.process(self.receive_message) if len(temp_list) == 12: print(self.receive_message) self.end_time = time.time() self.time = self.end_time - self.start_time if self.count == 0: self.count = 1 else: self.fps_value.setText(str(self.time)) self.f1_value.setText(temp_list[5]) self.f2_value.setText(temp_list[4]) self.f3_value.setText(temp_list[3]) self.f4_value.setText(temp_list[2]) self.f5_value.setText(temp_list[1]) self.f6_value.setText(temp_list[0]) self.r1_value.setText(temp_list[11].split('\\')[0]) self.r2_value.setText(temp_list[10]) self.r3_value.setText(temp_list[9]) self.r4_value.setText(temp_list[8]) self.r5_value.setText(temp_list[7]) self.r6_value.setText(temp_list[6]) self.start_time = time.time() self.check_time_start = time.time() self.check = 1 # print(f"context:{self.receive_message},type = {type(self.receive_message)}") def connection_button_cliked(self): if self.switch_state == 0: self.connect_button.setText("断开") self.baud = int(self.baud_value.text()) self.com = str(self.com_value.text()) self.message.append(f"com:{self.com},baud:{self.baud}") port_open_recv(self.com,self.baud) self.message.append("Connected") self.check = 0 else: self.connect_button.setText("连接") ser.close() self.message.append("Disconnect") self.switch_state = bool(1 - self.switch_state) def set_limit_time(self): self.limit_time = float(self.limit_time_value.text()) self.message.append(f"下限时间修改为:{self.limit_time}")

然后在if __name__ == "__main__":实例化MyMainForm对象并启动界面

if __name__ == "__main__": #固定的,PyQt5程序都需要QApplication对象。sys.argv是命令行参数列表,确保程序可以双击运行 app = QApplication(sys.argv) #初始化 myWin = MyMainForm() # 将窗口控件显示在屏幕上 myWin.show() # 程序运行,sys.exit方法确保程序完整退出。 sys.exit(app.exec_()) 3.2、创建串口接收任务

在MyMainForm类的初始化函数中已经连接并启动了process_task线程,这里就需要具体实现process_task的内容,首先process_task类需要继承QThread类,并重写run函数,在run函数中实现自己设计的功能,具体程序实现如下:

class process_task(QThread): sig = pyqtSignal(str) def __init__(self, parent=None): super(process_task, self).__init__(parent) self.receistr = " " def run(self): # 需要执行的内容 while True: time.sleep(0.01) # 提供读取串口是否被打开时间,以免闪退 if ser.isOpen() : self.receistr = ser.readline() # 发出信号 self.sig.emit(str(self.receistr)) else: pass 3.3、创建接收超时监测任务

超时监测任务的创建方式和串口接收数据的任务创建方式相同,需要在run函数里面具体实现自己的功能,这里我是在run函数里面判断串口是否打开,如果打开则开始监测时间,如果实现超过设定的时间,则在ui界面给出相应的提示。

class check_task(QThread): def __init__(self, parent=None): super(check_task, self).__init__(parent) def run(self): # 需要执行的内容 while True: time.sleep(0.01) # 提供读取串口是否被打开时间,以免闪退 if ser.isOpen() : # 监测时间 myWin.check_time_end = time.time() if myWin.check_time_end - myWin.check_time_start > myWin.limit_time : if myWin.check == 1 : myWin.message.append("接收超时") myWin.check_time_start = time.time() else: pass 四、将py文件转为exe文件 4.1、安装第三方工具库

py文件转为exe文件需要依赖pyinstaller第三方库实现,所以首先通过命令输入以下命令安装第三方库

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyinstaller 4.2、执行命令生成exe文件

第三方库安装完成后,通过命令行进入py文件所在目录,然后执行一下命令

在这里插入图片描述

pyinstaller -F main.py # 依据自己的py文件名

然后可以在工程文件的dist目录下找到刚才生成的exe文件

在这里插入图片描述

然后双击可以正常运行

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3