PyQt5串口测试工具

笔者经常会遇到使用上位机进行相关测试的场景,但现成的上位机并不能完全满足自己的需求,或是上位机缺乏使用说明。所以,自己写?

环境说明

pycharm 2023.2.25

python 3.10

anaconda

环境配置

conda create -n envsram     ##新建虚拟环境,不用anaconda也行自己使用python新建都行
conda env list    ##查看虚拟环境及路径,方便修改python解释器路径
conda activate envsram    
conda install pyqt     ##安装pyqt5及依赖designer    ##键入,以打开pyqt图像设计界面,设计完成后为.ui文件pyuic5 -o ccm_Test.py .\Uartsendframe.ui    ##转换.ui文件为测试文件pip install pyserial    ##我conda install失败了,直接用pip安装,为了上位机实现串口相关操作

代码测试

ui界面代码

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file '.\Uartsendframe.ui'
#
# Created by: PyQt5 UI code generator 5.15.10
#
# 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, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(432, 476)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)self.verticalLayout.setObjectName("verticalLayout")self.groupBox = QtWidgets.QGroupBox(self.centralwidget)self.groupBox.setObjectName("groupBox")self.gridLayout = QtWidgets.QGridLayout(self.groupBox)self.gridLayout.setObjectName("gridLayout")self.pushButton = QtWidgets.QPushButton(self.groupBox)self.pushButton.setObjectName("pushButton")self.gridLayout.addWidget(self.pushButton, 0, 3, 1, 1)self.pushButton2 = QtWidgets.QPushButton(self.groupBox)self.pushButton2.setObjectName("pushButton2")self.gridLayout.addWidget(self.pushButton2, 0, 4, 1, 1)self.pushButton3 = QtWidgets.QPushButton(self.groupBox)self.pushButton3.setObjectName("pushButton3")self.gridLayout.addWidget(self.pushButton3, 0, 5, 1, 1)self.pushButton4 = QtWidgets.QPushButton(self.groupBox)self.pushButton4.setObjectName("pushButton4")self.gridLayout.addWidget(self.pushButton4, 1, 5, 1, 1)self.lineEdit = QtWidgets.QLineEdit(self.groupBox)self.lineEdit.setObjectName("lineEdit")self.gridLayout.addWidget(self.lineEdit, 1, 1, 1, 4)self.label = QtWidgets.QLabel(self.groupBox)font = QtGui.QFont()font.setFamily("宋体")font.setPointSize(9)self.label.setFont(font)self.label.setObjectName("label")self.gridLayout.addWidget(self.label, 0, 0, 1, 1)self.label_2 = QtWidgets.QLabel(self.groupBox)self.label_2.setObjectName("label_2")self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)self.comboBox = QtWidgets.QComboBox(self.groupBox)self.comboBox.setObjectName("comboBox")self.comboBox.addItem("")self.gridLayout.addWidget(self.comboBox, 0, 1, 1, 2)self.verticalLayout.addWidget(self.groupBox)self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)self.groupBox_2.setObjectName("groupBox_2")self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_2)self.gridLayout_2.setObjectName("gridLayout_2")self.textEdit = QtWidgets.QTextEdit(self.groupBox_2)self.textEdit.setObjectName("textEdit")self.gridLayout_2.addWidget(self.textEdit, 0, 0, 1, 1)self.verticalLayout.addWidget(self.groupBox_2)MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 322, 26))self.menubar.setObjectName("menubar")self.menu = QtWidgets.QMenu(self.menubar)self.menu.setObjectName("menu")self.menu_2 = QtWidgets.QMenu(self.menubar)self.menu_2.setObjectName("menu_2")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.menubar.addAction(self.menu.menuAction())self.menubar.addAction(self.menu_2.menuAction())self.retranslateUi(MainWindow)self.pushButton.clicked.connect(self.comboBox.update) # type: ignoreQtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "串口sram测试工具v0.1"))self.groupBox.setTitle(_translate("MainWindow", "配置选项"))self.pushButton.setText(_translate("MainWindow", "刷新串口"))self.label.setText(_translate("MainWindow", "串口选择:"))self.label_2.setText(_translate("MainWindow", "文件路径:"))self.pushButton2.setText(_translate("MainWindow", "串口打开"))self.pushButton3.setText(_translate("MainWindow", "串口发送"))self.pushButton4.setText(_translate("MainWindow", "选择文件"))self.comboBox.setItemText(0, _translate("MainWindow", "com"))self.groupBox_2.setTitle(_translate("MainWindow", "数据显示"))self.menu.setTitle(_translate("MainWindow", "帮助"))self.menu_2.setTitle(_translate("MainWindow", "关于"))

逻辑代码

这边在处理的时候有几个遇到的bug,

1. 上位机需要一直接收,所以需要开一个线程用来持续接收。

2. 界面更新太平凡容易卡死,所以起一个信号量来更新

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog
from PyQt5.QtCore import pyqtSignal
from ccm_Test import Ui_MainWindow  
import time
import serial
import serial.tools.list_ports
import threadingclass MyApp(QMainWindow, Ui_MainWindow):data_received_signal = pyqtSignal(str)  # 定义信号,传递字符串数据def __init__(self):super().__init__()self.setupUi(self)self.data_received_signal.connect(self.update_text_edit)  # 连接信号到槽self.pushButton_onclik()self.pushButton2_onclik()self.pushButton3_onclik()self.pushButton4_onclik()def update_text_edit(self, data):self.textEdit.append(data)  # 更新文本编辑器def pushButton_onclik(self):# self.mainop()def cao():print("已刷新串口。")self.textEdit.append('刷新')ports = serial.tools.list_ports.comports()self.comboBox.clear()  # 清空所有项for port, desc, hwid in sorted(ports):print(port, type(port),type(ports))self.comboBox.addItem(port)  # 添加新的项列表# print(ports[0], type(ports[0]))# try:#     self.comboBox.clear()  # 清空所有项#     self.comboBox.addItems()  # 添加新的项列表##     print("Items added successfully.")# except Exception as e:#     print(f"An error occurred: {e}")self.pushButton.clicked.connect(cao)def pushButton2_onclik(self):# self.mainop()def cao():global port_nameglobal serial_portport_name = self.comboBox.currentText()baud_rate = 115200print(port_name)serial_port = self.open_serial(port_name, baud_rate)self.textEdit.append('打开'+port_name)self.pushButton2.clicked.connect(cao)def pushButton3_onclik(self):# self.mainop()''' bootloader 使用了0x20000400开始的地址,0xC00大小的区间。共开了0x10000的堆栈。 '''hex_string = "1234"hex_string1 = "1235"hex_string2 = "123455" #"52312000" 2000是实际动态代码 map文件中main的起始地址hex_string3 = "123456"hex_data_to_send = bytes.fromhex(hex_string)hex_data_to_send1 = bytes.fromhex(hex_string1)hex_data_to_send2 = bytes.fromhex(hex_string2)hex_data_to_send3 = bytes.fromhex(hex_string3)def cao():try:thread = threading.Thread(target=self.read_serial, args=(serial_port,))thread.start()except serial.SerialException as e:print(f"open_serial : {e}")## 第一条命令self.write_serial(serial_port, hex_data_to_send)self.textEdit.append('>> ' + hex_string)time.sleep(0.1)# rxbuff = self.read_serial(serial_port)# print(rxbuff)# self.textEdit.append('<< '+ rxbuff)## 第二条命令self.write_serial(serial_port, hex_data_to_send1)self.textEdit.append('>> ' + hex_string1)time.sleep(0.1)# rxbuff = self.read_serial(serial_port)# print(rxbuff)# self.textEdit.append('<< '+ rxbuff)## 第三条命令print(fileName)binfilecontent = self.read_bin_file(fileName)print(type(binfilecontent), binfilecontent)binfilecontent_len = len(binfilecontent)binfilecontent_len_hex = bytes.fromhex(self.int_to_hex16(binfilecontent_len))# print(binfilecontent_len_hex,type(binfilecontent_len_hex))# print(self.read_bin_file(fileName))self.write_serial(serial_port, hex_data_to_send2 + binfilecontent_len_hex + binfilecontent)self.textEdit.append('>> ' + hex_string2)time.sleep(0.1)# rxbuff = self.read_serial(serial_port)# self.textEdit.append('<< '+ rxbuff)## 第四条命令self.write_serial(serial_port, hex_data_to_send3)self.textEdit.append('>> ' + hex_string3)time.sleep(0.1)# rxbuff = self.read_serial(serial_port)# if(rxbuff == None):#     self.textEdit.append('<< ' + 'None.')# else:#     self.textEdit.append('<< '+ rxbuff)# time.sleep(3)# rxbuff = 0# rxbuff = self.read_serial(serial_port)# self.textEdit.append('等待后续sram测试数据返回...')# self.textEdit.append('<< '+ rxbuff)# self.close_serial(serial_port)passself.pushButton3.clicked.connect(cao)def pushButton4_onclik(self):# global fileNamedef cao():# 打开文件选择对话框options = QFileDialog.Options()options |= QFileDialog.DontUseNativeDialogglobal fileNamefileName, _ = QFileDialog.getOpenFileName(self, "QFileDialog.getOpenFileName()", "","All Files (*);;Text Files (*.txt)", options=options)if fileName:self.lineEdit.setText(fileName)  # 将选择的文件路径设置到 QLineEditpassself.pushButton4.clicked.connect(cao)# 打开串口def open_serial(self, port, baudrate):try:ser = serial.Serial(port, baudrate,parity=serial.PARITY_EVEN,  # 设置校验stopbits=serial.STOPBITS_ONE,  # 设置停止位bytesize=8,  # 数据位为 8 位timeout=0  # 超时设置 非阻塞)  # 打开串口print(f"Serial port {port} opened at {baudrate} baud.")# try:#     thread = threading.Thread(target=self.read_serial(ser), args=(ser,))#     thread.start()# except serial.SerialException as e:#     print(f"open_serial : {e}")return serexcept serial.SerialException as e:print(f"Error opening serial port {port}: {e}")return None# 从串口读取数据def read_serial(self, ser):while True:if ser:try:if ser.in_waiting > 0:received_data = ser.read(ser.in_waiting)received_hex = received_data.hex()if (received_hex == None):self.data_received_signal.emit('<< ' + received_hex)  # 发射信号('<< ' + 'None.')else:self.data_received_signal.emit('<< ' + received_hex)  # 发射信号print("Received data (hex):", received_hex)# return received_hexelse:# print("No data received.")passexcept serial.SerialTimeoutException:print("Read timeout occurred")except serial.SerialException as e:print(f"Error during read: {e}")time.sleep(0.1)  # 短暂休眠以减少CPU负担# 向串口写入数据def write_serial(self, ser, data):if ser:try:successlen = ser.write(data)  # 发送数据print("successlen: ",successlen)print(f"Sent data: {data}")# self.textEdit.append('>> ' + data.encode('utf-8').hex())except serial.SerialException as e:print(f"Error sending data: {e}")# 关闭串口def close_serial(self, ser):if ser:ser.close()print("Serial port closed.")# 读取bin文件def read_bin_file(self, file_path):try:with open(file_path, 'rb') as file:return file.read()except Exception as e:print(f"Failed to read file: {str(e)}")def int_to_hex16(self, value):if not (0 <= value <= 65535):raise ValueError("Integer value out of range for 16-bit representation")# 将整数转换为16位十六进制字符串hex_string = f"{value:04x}"return hex_stringif __name__ == "__main__":app = QApplication(sys.argv)window = MyApp()window.show()sys.exit(app.exec_())

界面示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/21654.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学生信息管理系统C++

设计目的 使学生进一步理解和掌握课堂上所学的面向对象C编程知识&#xff0c;巩固和加深学生对C面向对象课程的基本知识的理解和掌握。掌握C面向对象编程和程序调试的基本技能&#xff0c;学会利用C语言进行基本的软件设计&#xff0c;着重提高运用C面向对象语言解决实际问题的…

Go Modules 使用

文章参考https://blog.csdn.net/wohu1104/article/details/110505489 不使用Go Modules&#xff0c;所有的依赖包都是存放在 GOPATH /pkg下&#xff0c;没有版本控制。如果 package 没有做到完全的向前兼容&#xff0c;会导致多个项目无法运行(包版本需求不同)。 于是推出了g…

秋招突击——第四弹——Java的SSN框架快速入门——Spring(2)

文章目录 前言其他Spring加载properties 容器创建容器获取beanBeanFactory容器总结 注解注解开发对定义bean纯注解开发Bean管理Bean作用范围Bean生命周期 注解开发依赖注入第三方bean管理第三方bean管理第三方bean注入 注解开发总结 Spring整合整合mybatis整合Junit AOPAOP核心…

【C、C++编译工具】CLion工具介绍与安装

一、问题 最近突发奇想想学学最开始接触的语言C&#xff0c;之前大学的时候用的更多的工具还是VC&#xff0c;工作后慢慢接触了CLion&#xff0c;跟pycharm其实差不多&#xff0c;都是集成开发环境&#xff08;IDE&#xff09; 解释&#xff1a;什么是 IDE&#xff1f; 根据计…

2024年5月 | deepin 深度应用商店-应用更新记录

新增应用 序号应用名称deepin 系统版本应用分类应用类型1HitPaw Watermark Removerdeepin V23图形图像wine2PDF to DOCX转换器deepin V23网络应用linux3天工 AIdeepin V20.9效率办公linux4稻壳阅读deepin 20.9 deepin V23效率办公linux5讯飞星火deepin V20.9效率办公linux6文…

扩散模型的技术原理和应用价值

引言 一、扩散模型的基本概念 扩散模型(Diffusion Models)是一种基于概率论的生成模型&#xff0c;最初源自物理学中的扩散过程理论&#xff0c;比如墨水在水中的扩散过程。在机器学习领域&#xff0c;这一概念被创造性地应用于数据生成任务&#xff0c;特别是图像和声音的合成…

Proxmox Backup Server 命名空间使用

作者&#xff1a;田逸&#xff08;formyz&#xff09; Proxmox Backup Server&#xff08;一下统称PBS&#xff09;从2.2版本开始&#xff0c;新增了命名空间这样一个功能。这个功能大大便利了多Proxmox VE集群或者单节点备份&#xff0c;在以前PBS版本中&#xff0c;如果有多个…

HTML旋转照片盒子

效果图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compatible" content…

世界的本质是旋转(9) 利用声波传输mFSK多音调频文本

在上一篇文章中 &#xff0c;主要介绍的是使用专用的业余无线电设备传输调相波形。 对于买不起SDR设备的学生来说&#xff0c;可以使用这篇文章介绍的思路&#xff0c;使用声卡的数据线传输IQ路的基带数据。线路输入的好处&#xff1a; 不经过空气的媒介&#xff0c;波形的本…

江苏省汽车及零部件产业协作配套对接会在苏州举行

5月28日&#xff0c;江苏省汽车及零部件产业协作配套对接会暨“百场万企”大中小企业融通对接活动在苏州举办。本次活动以“深化整零协作&#xff0c;促进大中小企业融通发展”为主题&#xff0c;由江苏省工业和信息化厅、中国中检所属中国汽车工程研究院股份有限公司&#xff…

分享7个手机上堪称神器却鲜为人知的小众宝藏软件

分享7个手机上堪称神器却鲜为人知的小众宝藏软件&#xff0c;保证大家用过就舍不得卸载~ 1.志愿大师 马上就是高考季了&#xff0c;高考完的同学如果不知道该如何选专业&#xff0c;可以用这个软件来分析各个大学和专业设置等信息。 志愿大师是一款专为高考后学生设计的高效辅…

Others - 网友都是些人才,哈哈哈哈

感谢万能的网友们&#xff01; 原本枯燥的知识&#xff0c;在网友生动形象的表达下&#xff0c;也能简单易懂&#xff0c;哈哈哈哈

Prometheus+Altermanager实现钉钉告警

PrometheusAltermanager实现钉钉告警 Prometheus和Altermanager的安装这里就不赘述了&#xff0c;我之前的文章有写到 不记得的小伙伴可以去看看Prometheus和Altermanager的安装使用 直接开始上操作 下载钉钉并打开&#xff0c;先创建一个接收告警信息的钉钉群 添加一个自定…

【Nacos_bugs】java.lang.IllegalStateException: Failed to load ApplicationContext

报错原因 找不到配置文件。 Bug 排查 如果使用 Nacos 管理配置文件&#xff0c;需要检查本地 bootstrap.yml 配置是否出现问题&#xff1a; 检查点&#xff1a; 检查 Nacos 服务的地址有没有配置错误&#xff0c;如上图 ①&#xff0c;格式严格为 IP:端口号" 检查 D…

Ant Design Vue Pro流程分析记录

一、基本介绍 Ant Design Vue Pro提供了一套完整的解决方案&#xff0c;包括路由、状态管理、UI组件库、HTTP请求封装等&#xff0c;方便开发者快速搭建和维护企业级应用。 二、官网地址 Ant Design Pro of Vue 三、下载及安装 推荐使用Yarn 四、文件分布及说明 dist&#xf…

常见Rabbitmq面试题及答案总结

1、 什么是 rabbitmq 釆用AMQP高级消息队列协议的一种消息队列技术撮大的特点就是消费并不需要 确保提供方存在,实现了服务之间的高度解耦 2、 为什么要使rabbitmq &#xff08;1&#xff09; 在分布式系统下具备异步&#xff0c;削峰&#xff0c;负载均衡等一系列高级功能&…

企业百度百科如何修改

百度百科是一个可以让我们快速的了解一个企业情况的地方&#xff0c;同时也让我们的企业展示了什么&#xff0c;还有哪些是可以做的。 注册与登录 首先&#xff0c;你需要注册一个百度账号&#xff0c;并通过邮箱或手机进行验证。登录后&#xff0c;可以开始创建或编辑百度百科…

Leetcode - 周赛400

目录 一&#xff0c;3168. 候诊室中的最少椅子数 二&#xff0c;3169. 无需开会的工作日 三&#xff0c;3170. 删除星号以后字典序最小的字符串 四&#xff0c;3171. 找到按位与最接近 K 的子数组 一&#xff0c;3168. 候诊室中的最少椅子数 本题是一道模拟题&#xff0c;直…

归并排序法

归并排序法是典型的分治算法应用&#xff0c;1946年由冯.诺伊曼发明。 算法思路&#xff1a;归并排序算法有两个基本操作&#xff0c;一是分&#xff0c;也就是把原数组划分成两个子数组的过程&#xff0c;另一个是治&#xff0c;它将两个有序数组合并成一个更大的有序数组。 …

基于小波区间相关的信号降噪方法(MATLAB 2021B)

在我们处理信号过程中最重要的任务就是找到信号隐藏的规律和信号的特征。常用的傅里叶分析法只能用于在时间域或者频率域上分析信号&#xff0c;而通常的数据会在时间域和频率域均有特征。而小波分析是继傅里叶分析之后的一大突破性创新&#xff0c;也是近年来在学术界非常热门…