更新日志:
202210141442:优化功能(增加自动读取和单次读取可选)和界面美化。
202210141627:优化功能(添加菜单和读取优化,连接状态显示)
202210261446:优化功能(添加CRC校验工具)
202211021208:优化外观(外观美化)
202211181512:优化功能(添加modbusRTU通讯协议)

Python简易串口调试助手

  • 1 软件配置
    • 1 使用软件
    • 2 安装方式
  • 2 需要的包
  • 3 程序

1 软件配置

1 使用软件

python有很多编辑器,pycharm、vscode都可以,本例用的是vscode

系统平台:windows10

2 安装方式

1、VS code:vscode是微软旗下的一款程序编写器,可以直接在其官网下载,免费,不过微软服务器下载有时候会很慢,可以搜索一下国内镜像下载,会快不少。
2、Pycharm:如果不想用vscode,可以用Pycharm,Pycharm是Jetbrain公司旗下的软件,也可以在其官网下载(有免费版,个人用足矣。)

2 需要的包

1、PyQt5
2、serial、pyserial
安装方式直接使用pip就可以:

pip install PyQt5

其他类似

3 程序

串口调试程序,我之前写过一个:
https://blog.csdn.net/normer123456/article/details/124402399
这次是在之前的基础上,增加了一下界面优化的内容和功能上优化。
先说界面优化:
界面优化使用了Qt提供的Qss样式:

qss格式大概是这样

可以看到,就是对窗口及其子控件进行美化,如字体、字体位置、背景色、等等,这是完全自定义的,自己调整到一个合适的界面配置即可,比如我自己设置的:

20221026新增:

202211021209:UI优化,为界面配色增加了渐进色。
主窗体:

crc窗口:

202211181512:添加ModbusRTU主站协议(读取从站数据)
新增“通讯”菜单项,在此菜单下选择“自由协议通讯”或者“ModbusRTU通讯”。

qss文件调用:

 self.qss_style_file='E:\\100proworld2021\Python2022\style.qss'self.qss1=QssRead.readQSS(self.qss_style_file)

我这里是单独写了一个函数,用于读取qss文件,然后在串口的程序引用即可。

from qss_read import QssRead

qss_read.py内容如下:

class QssRead:@staticmethoddef readQSS(style):with open(style, "r") as f:return f.read()

可以看到,就是读取qss文件的内容并返回。
调用完,还要设置主窗口的style:

self.setStyleSheet(self.qss1)

以下是完整程序:
20221026:增加crc校验工具函数
20221102:窗体外观美化
20221118:增加ModbusRTU通信功能

 from asyncio.windows_events import NULL
from ftplib import CRLF
from turtle import color
from numpy.lib.function_base import place
import serial
import serial.tools.list_ports
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
import sys
import re
import os
import threading
import datetime
import time
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from qss_read import QssReadclass modbus_rtu_win(QWidget):"""modbusRTU窗口"""def __init__(self):super().__init__()self.initUI()def initUI(self):self.stylefile1='S01_SerialDeviceComm_pro2022\qss_modbus_main_style2.qss'self.qss1=QssRead.readQSS(self.stylefile1)self.UI_x_posi=30self.UI_y_posi=30self.lbl_chose_mode=QLabel(self)self.lbl_chose_mode.setGeometry(self.UI_x_posi+10,self.UI_y_posi+10,100,20)self.lbl_chose_mode.setText('选择通讯协议:')self.cmb_modbus_or_serial=QComboBox(self)self.cmb_modbus_or_serial.setGeometry(self.UI_x_posi+10,self.UI_y_posi+30,120,20)self.cmb_modbus_or_serial.addItems(['ModbusRTU主站','自由串口'])self.lbl_modbus_slave_addr=QLabel(self)self.lbl_modbus_slave_addr.setGeometry(self.UI_x_posi+10,self.UI_y_posi+60,100,20)self.lbl_modbus_slave_addr.setText('从站地址:')self.le_modbus_slave_addr=QLineEdit(self)self.le_modbus_slave_addr.setGeometry(self.UI_x_posi+10,self.UI_y_posi+80,60,20)self.le_modbus_slave_addr.setText('1')#串口参数设置self.h1_layout=QHBoxLayout()self.gb1=QGroupBox('串口参数设置',self)self.gb1.setGeometry(200,20,140,170)self.cmb_serial_param_port=QComboBox(self)self.cmb_serial_param_port.setGeometry(210,40,80,20)self.cmb_serial_param_port.addItem('COM1')self.cmb_serial_param_baudrate=QComboBox(self)self.cmb_serial_param_baudrate.setGeometry(210,70,80,20)self.cmb_serial_param_baudrate.addItems(['9600','19200','38400','57600','119200'])self.cmb_serial_param_databits=QComboBox(self)self.cmb_serial_param_databits.setGeometry(210,100,80,20)self.cmb_serial_param_databits.addItems(['8','7','6','5'])self.cmb_serial_param_stopbits=QComboBox(self)self.cmb_serial_param_stopbits.setGeometry(210,130,80,20)self.cmb_serial_param_stopbits.addItems(['1','1.5','2'])self.cmb_serial_param_parity=QComboBox(self)self.cmb_serial_param_parity.setGeometry(210,160,80,20)self.cmb_serial_param_parity.addItems(['无校验','偶校验','奇校验','Mark','Space'])self.gb1.setLayout(self.h1_layout)self.btn_get_serialport=QPushButton('获取串口',self)self.btn_get_serialport.setGeometry(self.UI_x_posi+330,self.UI_y_posi+10,100,20)self.btn_get_serialport.clicked.connect(self.get_local_serialport_func)self.btn_open_serial=QPushButton('打开串口',self)self.btn_open_serial.setGeometry(self.UI_x_posi+330,self.UI_y_posi+50,100,20)self.btn_open_serial.clicked.connect(self.open_serialport_func)self.btn_close_serial=QPushButton('关闭串口',self)self.btn_close_serial.setGeometry(self.UI_x_posi+330,self.UI_y_posi+90,100,20)self.btn_close_serial.clicked.connect(self.close_serialport_func)self.radio_read_function=QRadioButton(self)self.radio_read_function.setGeometry(self.UI_x_posi+50,self.UI_y_posi+170,120,20)self.radio_read_function.setText('读')self.radio_read_function.setChecked(True)#self.radio_read_function.toggled.connect(lambda:self.radio_btn_change_func(self.radio_read_function))self.cmb_modbus_read_data=QComboBox(self)self.cmb_modbus_read_data.setGeometry(self.UI_x_posi+110,self.UI_y_posi+170,120,20)self.cmb_modbus_read_data.addItems(['线圈','输入点','输入寄存器','保持寄存器'])self.cmb_modbus_read_data.setCurrentIndex(3)#读 首地址self.le_modbus_read_data_addr=QLineEdit(self)self.le_modbus_read_data_addr.setGeometry(self.UI_x_posi+250,self.UI_y_posi+170,60,20)self.le_modbus_read_data_addr.setText('0')#读 长度self.le_modbus_read_data_length=QLineEdit(self)self.le_modbus_read_data_length.setGeometry(self.UI_x_posi+320,self.UI_y_posi+170,40,20)self.le_modbus_read_data_length.setText('2')self.radio_write_function=QRadioButton(self)self.radio_write_function.setGeometry(self.UI_x_posi+50,self.UI_y_posi+200,120,20)self.radio_write_function.setText('写')#self.radio_write_function.toggled.connect(lambda:self.radio_btn_change_func(self.radio_write_function))self.cmb_modbus_write_data=QComboBox(self)self.cmb_modbus_write_data.setGeometry(self.UI_x_posi+110,self.UI_y_posi+200,120,20)self.cmb_modbus_write_data.addItems(['线圈','单寄存器','多线圈','多寄存器'])self.cmb_modbus_write_data.setCurrentIndex(3)#写 首地址self.le_modbus_write_data_addr=QLineEdit(self)self.le_modbus_write_data_addr.setGeometry(self.UI_x_posi+250,self.UI_y_posi+200,60,20)self.le_modbus_write_data_addr.setText('0')#写 长度self.le_modbus_write_data_length=QLineEdit(self)self.le_modbus_write_data_length.setGeometry(self.UI_x_posi+320,self.UI_y_posi+200,40,20)self.le_modbus_write_data_length.setText('2')#建立按钮组来管理RadioButtonself.bg_1=QButtonGroup(self)self.bg_1.addButton(self.radio_read_function)self.bg_1.addButton(self.radio_write_function)#self.bg_1.buttonToggled.connect(self.radio_btn_change_func)self.lbl_modbus_send_command=QLabel(self)self.lbl_modbus_send_command.setGeometry(self.UI_x_posi+50,self.UI_y_posi+240,80,20)self.lbl_modbus_send_command.setText('发送指令码:')self.le_modbus_send_command=QLineEdit(self)self.le_modbus_send_command.setGeometry(self.UI_x_posi+140,self.UI_y_posi+240,200,20)self.le_modbus_crc16=QLineEdit(self)self.le_modbus_crc16.setGeometry(self.UI_x_posi+360,self.UI_y_posi+240,60,20)self.btn_modbus_cmd_execute=QPushButton('发送',self)self.btn_modbus_cmd_execute.setGeometry(self.UI_x_posi+100,self.UI_y_posi+300,80,40)self.btn_modbus_cmd_execute.clicked.connect(self.modbus_rtu_master_send_func)self.lbl_2=QLabel(self)self.lbl_2.setGeometry(520,20,100,20)self.lbl_2.setText('返回数据:')self.te_modbus_recv=QTextEdit(self)self.te_modbus_recv.setGeometry(520,60,250,200)self.stb_1=QLabel(self)self.stb_1.setGeometry(10,self.height()-10,200,20)self.stb_1.setText('COM未连接')self.setWindowTitle('ModbusRTU主站')self.setWindowIcon(QIcon('S01_SerialDeviceComm_pro2022\chuankou1.png'))self.setStyleSheet(self.qss1)self.setGeometry(100,100,800,600)self.get_local_serialport_func()self.serial_11=serial.Serial()def get_local_serialport_func(self):"""获取本地串口号"""self.plist=list(serial.tools.list_ports.comports())self.listindex={}#print(self.plist)if len(self.plist) <=0:print('无串口可用')qm=QMessageBox.warning(self,'提示','未找到串口,请检查接线')if qm == QMessageBox.Yes:print('Yes')else:print('no')else:self.cmb_serial_param_port.clear()for i in list(self.plist):self.cmb_serial_param_port.addItem(i.name)self.cmb_serial_param_port.setCurrentIndex(0)def open_serialport_func(self):"""打开串口"""try:parity1=''port1=self.cmb_serial_param_port.currentText()baud1= int(self.cmb_serial_param_baudrate.currentText())databits1=int(self.cmb_serial_param_databits.currentText())stopbits1=int(self.cmb_serial_param_stopbits.currentText())match self.cmb_serial_param_parity.currentText():case '无校验':parity1='N'     #无校验case '偶校验':parity1='E'     #根据数据中1的位数来判断,1的数量为偶数,p=0,反之,p=1case '奇校验':parity1='O'     #根据数据中1的位数来判断,1的数量为偶数,p=1,反之,p=0case 'Mark':parity1='M'     #校验位始终为1case 'space':parity1='S'     #校验位始终为0self.serial_11=serial.Serial(port1,baud1,databits1,parity1,stopbits1)if self.serial_11.isOpen:#print('已打开')self.stb_1.setText('串口已连接!')self.stb_1.setStyleSheet("background-color:lime")print(port1)print(baud1)print(databits1)print(stopbits1)print(parity1)self.modbus_rtu_master_init_func()except Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)def close_serialport_func(self):""""""try:if self.serial_11.isOpen:self.read_data_flag=False           self.serial_11.close()if self.serial_11.isOpen()==False:QMessageBox.warning(self,'提示!','串口已关闭',QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)self.stb_1.setStyleSheet("background-color:gray")else:exitexcept Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)def crc_cal_func(self,crc_in:str):"""CRC计算函数"""#16进制元数据crc_source_data=crc_in#去除空格crc_source_data_nospace=crc_source_data.replace(" ","")#print(crc_source_data_nospace)#每2个字符添加空格crc_source_data_spaceper2=re.sub(r"(?<=\w)(?=(?:\w\w)+$)", " ", crc_source_data_nospace)                         crc_source_data_list=crc_source_data_spaceper2.split(' ')      crc_datas=list(crc_source_data_list)#初始值crc16=0xFFFF#多项式poly=0xA001#计算过程for crc_temp_data in crc_datas:if crc_temp_data != '':a=int(crc_temp_data,16)crc16=a ^ crc16         #异或for i in range(8):if 1 & crc16 ==1:crc16 = crc16 >> 1crc16=crc16 ^ polyelse:crc16=crc16 >> 1else:QMessageBox.information(self,'提示!','请输入正确的数据!' + '\n'+'如:01 00 03 00')return    crc16=hex(int(crc16))crc16=crc16[2:].upper()length=len(crc16)crc16_high=crc16[0:length-2].zfill(2)crc16_high=str(crc16_high)crc16_low=crc16[length-2:length].zfill(2)crc16_low=str(crc16_low)#print(crc16_high,crc16_low)self.crc16_end=crc16_low + ' '+ crc16_highreturn self.crc16_enddef radio_btn_change_func(self):""""""#print(self.bg_1.checkedButton())check_btn1=self.bg_1.checkedButton()print(check_btn1.text())def modbus_rtu_master_init_func(self):"""modbus主站初始化"""if self.serial_11.isOpen:self.master=modbus_rtu.RtuMaster(self.serial_11)self.master.set_timeout(5.0)else:QMessageBox.warning(self,'提示!','无串口可用',QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)def hex_without0x(self,s1:int):"""返回16进制不带0x前缀"""s2=hex(s1)if s1<256:if s1<16:s3='0' +s2.replace('0x','')s3='00' + ' ' + s3else:s3=s2.replace('0x','')s3='00' + ' ' + s3elif s1>=256 and s1<4096:s3='0' +s2.replace('0x','')s3=self.str_fen_ge(s3)else:s3=s2.replace('0x','')s3=self.str_fen_ge(s3)s3=s3.upper()return s3def str_fen_ge(self,a):"""对字符进行分隔"""b=re.findall(r'.{2}',a)c=' '.join(b)return str(c)def modbus_rtu_master_send_func(self):"""modbus发送指令码"""self.recv1=''modbus_slave_addr1=int(self.le_modbus_slave_addr.text())try:if self.serial_11.isOpen:if self.bg_1.checkedButton().text() == '读':first_addr1=int(self.le_modbus_read_data_addr.text())len1=int(self.le_modbus_read_data_length.text())data1=self.master.execute(modbus_slave_addr1,cst.READ_HOLDING_REGISTERS,first_addr1,len1)#data1=self.master.execute(1,cst.READ_COILS,0,10)#data1=self.master.execute(1,cst.READ_DISCRETE_INPUTS,0,10)#data1=self.master.execute(1,cst.READ_INPUT_REGISTERS,0,10)#data1=self.master.execute(1,cst.READ_HOLDING_REGISTERS,0,10)elif self.bg_1.checkedButton().text() == '写':first_addr1=int(self.le_modbus_write_data_addr.text())len1=int(self.le_modbus_write_data_length.text())#data1=self.master.execute(1,cst.WRITE_SINGLE_COIL,0,output_value=1)#data1=self.master.execute(1,cst.WRITE_SINGLE_REGISTER,0,output_value=10)#data1=self.master.execute(1,cst.WRITE_MULTIPLE_COILS,0,output_value=[1,1,0,1,0,0,1])data1=self.master.execute(modbus_slave_addr1,cst.WRITE_MULTIPLE_REGISTERS,first_addr1,len1,output_value=[51])                  print(data1)for i,l in enumerate(data1):self.recv1 +=str(i) +'-->'+ str(data1[i])+'\n'self.te_modbus_recv.setText(self.recv1)else:QMessageBox.warning(self,'提示!','无串口可用',QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)self.f0='01'match self.bg_1.checkedButton().text():case '读':self.f1='03'self.f2=self.hex_without0x(int(self.le_modbus_read_data_addr.text()))self.f3=self.hex_without0x(int(self.le_modbus_read_data_length.text()))case '写':self.f1='06'self.f2=self.hex_without0x(int(self.le_modbus_write_data_addr.text()))self.f3=self.hex_without0x(int(self.le_modbus_write_data_length.text()))self.f10=self.f0+' '+self.f1+' '+self.f2+' '+self.f3self.f5=self.crc_cal_func(self.f10)self.le_modbus_send_command.setText(self.f10)self.le_modbus_crc16.setText(self.f5)except Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)#print('异常:',e)def closeEvent(self,e1):"""关闭事件"""if self.serial_11 is not None:if self.serial_11.isOpen:self.close_serialport_func()class helpinfo_win2(QWidget):"""帮助窗口"""def __init__(self,title:str):super().__init__()self.title_win=titleself.initUI()def initUI(self):self.stylefile='S01_SerialDeviceComm_pro2022\qss_helpinfo_win_style.qss'self.qss1=QssRead.readQSS(self.stylefile)self.help_text=self.helpfile_read('S01_SerialDeviceComm_pro2022\helpfile_title.txt')self.label_1=QLabel(self)self.label_1.setGeometry(20,20,400,90)self.label_1.setText(self.help_text)#self.label_1.setStyleSheet("background-color:yellow")self.label_1.adjustSize()self.help_text2=self.helpfile_read('S01_SerialDeviceComm_pro2022\help.txt')self.label_2=QLabel(self)self.label_2.setGeometry(20,80,500,120)self.label_2.setText(self.help_text2)#self.label_2.setStyleSheet("background-color:aquamarine")self.label_2.adjustSize()self.setWindowTitle(self.title_win)self.setWindowIcon(QIcon('S01_SerialDeviceComm_pro2022\chuankou1.png'))self.setStyleSheet(self.qss1)self.resize(600,300)def helpfile_read(self,f):with open(f,"r",encoding='utf-8') as f:text1=f.read()return text1class crc_win(QWidget):"""CRC窗口"""def __init__(self):super().__init__()self.initUI()def initUI(self):self.qss_style_file='S01_SerialDeviceComm_pro2022\qss_crc_win_style.qss'self.qss1=QssRead.readQSS(self.qss_style_file)self.btn_crc_cal=QPushButton('CRC计算',self)self.btn_crc_cal.setGeometry(100,60,100,20)self.btn_crc_cal.clicked.connect(self.crc_cal_func)self.label_crc_data=QLabel(self)self.label_crc_data.setGeometry(100,100,100,20)self.label_crc_data.setText('要校验的数据:')self.le_crc_data=QLineEdit(self)self.le_crc_data.setGeometry(200,100,300,20)self.le_crc_data.setText('')self.le_crc_result=QLineEdit(self)self.le_crc_result.setGeometry(520,100,80,20)self.le_crc_result.setText('')self.label_crc_resutl=QLabel(self)self.label_crc_resutl.setGeometry(520,130,100,20)self.label_crc_resutl.setText('CRC校验计算结果')self.le_crc_all=QLineEdit(self)self.le_crc_all.setGeometry(200,160,300,20)self.le_crc_all.setText('')self.label_crc_all=QLabel(self)self.label_crc_all.setGeometry(100,160,60,20)self.label_crc_all.setText('总的结果:')self.setWindowTitle('CRC校验计算工具')self.setWindowIcon(QIcon('S01_SerialDeviceComm_pro2022\crc1.png'))self.setStyleSheet(self.qss1)self.setGeometry(200,150,800,300)def crc_cal_func(self):"""CRC计算函数"""#16进制元数据crc_source_data=self.le_crc_data.text()#去除空格crc_source_data_nospace=crc_source_data.replace(" ","")#print(crc_source_data_nospace)#每2个字符添加空格crc_source_data_spaceper2=re.sub(r"(?<=\w)(?=(?:\w\w)+$)", " ", crc_source_data_nospace)                         crc_source_data_list=crc_source_data_spaceper2.split(' ')      crc_datas=list(crc_source_data_list)#初始值crc16=0xFFFF#多项式poly=0xA001#计算过程for crc_temp_data in crc_datas:if crc_temp_data != '':a=int(crc_temp_data,16)crc16=a ^ crc16         #异或for i in range(8):if 1 & crc16 ==1:crc16 = crc16 >> 1crc16=crc16 ^ polyelse:crc16=crc16 >> 1else:QMessageBox.information(self,'提示!','请输入正确的数据!' + CRLF+'如:01 00 03 00')self.le_crc_data.setText('01 03 00 00')return    crc16=hex(int(crc16))crc16=crc16[2:].upper()length=len(crc16)crc16_high=crc16[0:length-2].zfill(2)crc16_high=str(crc16_high)crc16_low=crc16[length-2:length].zfill(2)crc16_low=str(crc16_low)#print(crc16_high,crc16_low)self.le_crc_result.setText(crc16_low + ' '+ crc16_high)self.le_crc_all.setText(crc_source_data_spaceper2+' '+crc16_low+' '+crc16_high)class serial_win(QMainWindow):"""主窗口"""def __init__(self) -> None:super().__init__()self.initUI()def initUI(self):self.qss_style_file='S01_SerialDeviceComm_pro2022\qss_main_style.qss'self.qss1=QssRead.readQSS(self.qss_style_file)self.serial1=Noneself.read_data_flag=Falseself.port=''self.baud=0self.timeout=0.0self.send_data=bytes()self.read_data=''#添加菜单项self.menu1=self.menuBar()self.menu1.setGeometry(QRect(0,0,80,40))self.menu1.setObjectName("menubar")#一级菜单self.file=self.menu1.addMenu('文件')#self.file_open=self.file.addMenu('打开')#self.file_exit=self.file.addMenu('退出')#二级菜单self.file_open=QAction('打开(&O)',self)self.file.addAction(self.file_open)self.file_exit=QAction('退出(&E)',self)self.file.addAction(self.file_exit)self.comm=self.menu1.addMenu('通讯')self.comm_freeserial=self.comm.addAction('自由协议')self.comm_modbusrtu=self.comm.addAction('Modbus-RTU')self.edit=self.menu1.addMenu('编辑')self.tool=self.menu1.addMenu('工具')self.tool_crc=QAction('CRC校验工具',self)self.tool.addAction(self.tool_crc)self.about=self.menu1.addMenu('关于')self.about_me=QAction('本程序(&M)',self)self.about.addAction(self.about_me)self.about_help=QAction('帮助&H',self)self.about.addAction(self.about_help)#为菜单添加响应self.file_open.triggered.connect(self.file_open_func)self.file_exit.triggered.connect(self.close)self.comm_modbusrtu.triggered.connect(self.modbus_win_func)self.tool_crc.triggered.connect(self.crc_func)self.about_me.triggered.connect(self.about_me_show)self.about_help.triggered.connect(self.about_help_show)self.btn_plist=QPushButton('获取可用串口',self)          #新建按钮实例self.btn_plist.setGeometry(20,30,80,20)                 #按钮布局位置self.btn_plist.clicked.connect(self.get_serial_info)    #按钮链接函数#self.btn_plist.adjustSize()                             #按钮自适应文本self.btn_serial_init=QPushButton('串口初始化',self)self.btn_serial_init.setGeometry(20,60,80,20)self.btn_serial_init.clicked.connect(self.serial_init)#self.btn_serial_init.adjustSize()self.btn_serial_open=QPushButton('打开串口',self)self.btn_serial_open.setGeometry(20,90,80,20)self.btn_serial_open.clicked.connect(self.open_serial)#self.btn_serial_open.adjustSize()self.btn_serial_close=QPushButton('关闭串口',self)self.btn_serial_close.setGeometry(20,120,80,20)self.btn_serial_close.clicked.connect(self.close_serial)#self.btn_serial_close.adjustSize()self.btn_read_data=QPushButton('单次读取数据',self)self.btn_read_data.setGeometry(20,150,80,20)self.btn_read_data.clicked.connect(self.read_serial_data_th)#self.btn_read_data.adjustSize()#self.btn_read_data.setStyleSheet("background-color:red")self.btn_send_data=QPushButton('发送数据',self)self.btn_send_data.setGeometry(20,460,80,20)self.btn_send_data.clicked.connect(self.send_serial_data)#self.btn_send_data.adjustSize()self.btn_close_win=QPushButton('关闭窗口',self)self.btn_close_win.setGeometry(20,180,80,20)self.btn_close_win.clicked.connect(self.close)self.label_conn_status=QLabel(self)self.label_conn_status.setGeometry(140,60,60,20)self.label_conn_status.setText('连接状态')self.label_conn_status.setStyleSheet("background-color:#FCF8F8;color:#535353")self.x=500self.y=30self.serial_port_set=QComboBox(self)self.serial_port_set.setGeometry(500,self.y,100,20)self.serial_port_set.addItems(['COM1'])self.label_port_set=QLabel(self)self.label_port_set.setGeometry(420,self.y,60,20)self.label_port_set.setText('串口号:')self.serial_baud_set=QComboBox(self)self.serial_baud_set.setGeometry(500,self.y+30,100,20)self.serial_baud_set.addItems(['9600','19200','38400','115200'])self.label_baud_set=QLabel(self)self.label_baud_set.setGeometry(420,self.y+30,60,20)self.label_baud_set.setText('波特率:')self.serial_stopbit_set=QComboBox(self)self.serial_stopbit_set.setGeometry(500,self.y+60,100,20)self.serial_stopbit_set.addItems(['0','1'])self.label_stopbit_set=QLabel(self)self.label_stopbit_set.setGeometry(420,self.y+60,60,20)self.label_stopbit_set.setText('停止位:')self.serial_parity_set=QComboBox(self)self.serial_parity_set.setGeometry(500,self.y+90,100,20)self.serial_parity_set.addItems(['无','奇校验','偶校验'])self.label_parity_set=QLabel(self)self.label_parity_set.setGeometry(420,self.y+90,60,20)self.label_parity_set.setText('校验位:')self.serial_databit_set=QComboBox(self)self.serial_databit_set.setGeometry(500,self.y+120,100,20)self.serial_databit_set.addItems(['8','7'])self.label_databit_set=QLabel(self)self.label_databit_set.setGeometry(420,self.y+120,60,20)self.label_databit_set.setText('数据位:')self.serial_timeout_set=QLineEdit(self)self.serial_timeout_set.setGeometry(500,self.y+150,100,20)self.serial_timeout_set.setText('1000')self.label_timeout_set=QLabel(self)self.label_timeout_set.setGeometry(420,self.y+150,60,20)self.label_timeout_set.setText('超时时间:')self.label_timeout_set2=QLabel(self)self.label_timeout_set2.setGeometry(610,self.y+150,60,20)self.label_timeout_set2.setText('ms')self.le_send_data=QLineEdit(self)                   #发送数据文本框self.le_send_data.setGeometry(120,460,700,20)self.le_send_data.setText('please input send_data here!')self.le_recv_data=QTextEdit(self)                                       #接收数据文本框self.le_recv_data.setGeometry(20,240,800,200)self.le_recv_data.setText('receive data in here!')self.label_recv_data=QLabel(self)self.label_recv_data.setGeometry(20,210,60,20)self.label_recv_data.setText('接收数据:')self.checkbox1=QCheckBox(self)self.checkbox1.setGeometry(120,210,70,20)self.checkbox1.setText('自动接收')#self.checkbox1.adjustSize()self.checkbox1.stateChanged.connect(self.cb1_check_status)self.label_auto_recdata_timeset=QLabel(self)self.label_auto_recdata_timeset.setGeometry(220,210,60,20)self.label_auto_recdata_timeset.setText('时间间隔:')self.le_auto_recdata_timeset=QLineEdit(self)self.le_auto_recdata_timeset.setGeometry(290,210,40,20)self.le_auto_recdata_timeset.setText('1000')#self.le_auto_recdata_timeset.adjustSize()self.label_auto_recdata_timeset_2=QLabel(self)self.label_auto_recdata_timeset_2.setGeometry(335,210,20,20)self.label_auto_recdata_timeset_2.setText('ms')self.label_recvdata_length=QLabel(self)self.label_recvdata_length.setGeometry(540,210,60,20)self.label_recvdata_length_2=QLabel(self)self.label_recvdata_length_2.setGeometry(485,210,60,20)self.label_recvdata_length_2.setText('字节数:')self.setGeometry(100,100,1000,600)self.setWindowIcon(QIcon('S01_SerialDeviceComm_pro2022\chuankou1.png'))     #为窗口添加ICONself.setWindowTitle('串口调试助手')self.setStyleSheet(self.qss1)self.show()def modbus_win_func(self):self.modbus_win1=modbus_rtu_win()self.modbus_win1.show()def file_open_func(self):"""打开按钮"""path,_=QFileDialog.getOpenFileName(self,'open file','','txt file(*.txt)')if path:try:with open(path,"r",encoding='utf-8') as f:text=f.read()print(text)except Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)def crc_func(self):"""CRC校验"""self.crc_win=crc_win()self.crc_win.show()def about_me_show(self):"""本程序按钮"""QMessageBox.information(self,'关于本程序','本程序是用于实现与PLC等设备进行串口通讯!')def about_help_show(self):"""帮助按钮"""self.help_window=helpinfo_win2("帮助?")self.help_window.show()def cb1_check_status(self):     if QAbstractButton.isChecked(self.checkbox1):       #判断复选框是否选中self.read_data_flag=Trueself.btn_read_data.setEnabled(False)self.btn_read_data.setStyleSheet("background-color:gray")self.read_serial_data_th()else:self.read_data_flag=Falseself.btn_read_data.setEnabled(True)self.btn_read_data.setStyleSheet("background-color:rgb(250, 250, 252)")def get_serial_info(self):"""用于获取设备串口信息"""self.plist=list(serial.tools.list_ports.comports())if len(self.plist) <=0:print('无串口可用')qm=QMessageBox.warning(self,'提示','未找到串口,请检查接线')if qm == QMessageBox.Yes:print('Yes')else:print('no')else:for i in list(self.plist):self.serial_port_set.clear()self.serial_port_set.addItem(i.name)self.serial_port_set.currentText=i.namedef serial_init(self):"""用于串口初始化"""self.port=self.serial_port_set.currentTextself.baud=int(self.serial_baud_set.currentText())self.timeout=float(self.serial_timeout_set.text())try:self.serial1=serial.Serial(port=self.port,baudrate=self.baud,bytesize=8,parity='N',stopbits=1)print(self.serial1)if self.serial1.isOpen: self.label_conn_status.setText('连接成功')self.label_conn_status.setStyleSheet("background-color:#36F12F")                             print('串口正常')except Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)def open_serial(self):"""打开串口"""try:self.serial1.open()except Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)def close_serial(self):"""关闭串口"""try:if self.serial1.isOpen:self.read_data_flag=False           self.serial1.close()if self.serial1.isOpen()==False:QMessageBox.warning(self,'提示!','串口已关闭',QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)self.label_conn_status.setText('连接断开')self.label_conn_status.setStyleSheet("background-color:gray")else:exitexcept Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)def read_serial_data_auto(self):"""自动读取串口数据"""print('开始接收数据:')self.time_jiange=float(self.le_auto_recdata_timeset.text()) / 1000.0while self.read_data_flag:ct=datetime.datetime.now()ct_str=ct.strftime("%Y-%m-%d %H:%M:%S")try:           if self.serial1.isOpen:       self.len=self.serial1.in_waitingself.label_recvdata_length.setText(str(self.len))#print(self.len)         self.read_data=self.serial1.read(size=self.len)self.read_data_str=self.read_data.hex()self.read_data_str_fg=self.str_fen_ge(self.read_data_str)self.le_recv_data.append('\n'+'['+ct_str+']'+' '+self.read_data_str_fg+'\n')time.sleep(self.time_jiange)else:breakexcept Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)breakdef read_serial_data_manual(self):"""手动获取串口数据"""print('开始接收数据:')ct2=datetime.datetime.now()ct_str2=ct2.strftime("%Y-%m-%d %H:%M:%S")try:           if self.serial1.isOpen:   self.len2=self.serial1.in_waiting    self.label_recvdata_length.setText(str(self.len2))         self.read_data=self.serial1.read(size=self.len2)self.read_data_str=self.read_data.hex()self.read_data_str_fg=self.str_fen_ge(self.read_data_str)self.le_recv_data.append('\n'+'['+ct_str2+']'+' '+self.read_data_str_fg+'\n')else:print('串口未打开')except Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)def read_serial_data_th(self):#新建线程用于接收串口数据if self.serial1 is serial.Serial:if self.serial1.isOpen() == True:if self.read_data_flag:self.th1=threading.Thread(name='t1',target=self.read_serial_data_auto)self.th1.start()else:self.read_serial_data_manual()else:QMessageBox.information(self,'提示','无串口可用!')else:qb1=QMessageBox.information(self,'提示','无串口可用!')if qb1==QMessageBox.Ok:self.checkbox1.setChecked(False)def send_serial_data(self):"""发送串口数据"""current_dt=datetime.datetime.now()                          #获取系统时间current_dt_str=current_dt.strftime("%Y-%m-%d %H:%M:%S")     #格式化时间try:self.send_data_str=self.le_send_data.text()self.send_data=bytes.fromhex(self.send_data_str)self.serial1.write(self.send_data)except Exception as e:QMessageBox.warning(self,'提示!',str(e),QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Ok)print('异常:',e)def str_fen_ge(self,a):"""对字符进行分隔"""b=re.findall(r'.{2}',a)c=' '.join(b)return str(c)if __name__ == '__main__':app=QApplication(sys.argv)ex=serial_win()sys.exit(app.exec_())    

主窗口样式文件:
20221102:更新
qss_main_style.qss:

/*
*
{
color:red;
}
*/
QMainWindow
{background-color: qlineargradient(x1:0, y1:1, x2:1, y2:1, stop:0 #9EEDF3,stop:0.3 #62ACF1, stop:0.5 #5CEE7C,stop:1 #3FECC1);
}
QMenuBar
{background-color:qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #80EBE5, stop:0.5 #81D5EB, stop:1 #3F9CE7);
}
QMenu
{background-color:qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #C3F7DA, stop:0.6 #746ACE, stop:1 #E9F3EE);
}
QPushButton
{text-align:center;color:#050505;background-color:qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #707270, stop:0.4 #F1F1F7,stop:0.6 #E4F0F8,stop:0.8 #D5D2FC, stop:1 #6D6F70);
}
QLabel
{text-align: center;font:lighter;font-size:13px;background-color:rgba(228, 236, 228, 0);color:black;}
QCheckBox
{text-align: center;
}
QComboBox
{text-align: center;background-color: rgb(248, 249, 250);
}
QLineEdit
{background-color: rgb(250, 250, 250);
}
QTextEdit
{background-color:antiquewhite;
}
QMessageBox
{   icon:'CoDeSys.ico';background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #EFF1E4, stop:0.5 #87F0D6, stop:1 #578EF3);
}

crc窗口样式文件:
20221102:更新
qss_crc_win_style.qss:

/*
*
{
color:red;
}
*/
QWidget
{background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #749DF5, stop:0.3 #F37C7C,stop:0.5 #F35CC1, stop:1 #C96FF3);
}
QPushButton
{text-align:center;
color:rgb(14, 13, 13);
background-color:qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #3DFA3D, stop:0.4 #EC8C55,stop:0.6 #86E1F1,stop:0.8 #4438F5, stop:1 #EFF4F7);
}
QLabel
{text-align: center;
font:lighter;
font-size:13px;
background-color:rgba(228, 236, 228, 0);
color:black;}
QCheckBox
{text-align: center;
}
QComboBox
{text-align: center;
background-color: rgb(248, 249, 250);
}
QLineEdit
{background-color: rgb(250, 250, 250);
}
QTextEdit
{background-color:antiquewhite;
}
QMessageBox
{   icon:'CoDeSys.ico';background-color: aquamarine;
}

样式文件的读取模块:
qss_read.py:

class QssRead:@staticmethoddef readQSS(style):with open(style, "r") as f:return f.read()

<Python>简易串口调试助手(优化版,自由协议+ModbusRTU)相关推荐

  1. 串口调试助手 安卓版 附下载地址

    平时工作中和硬件同事对接的比较多,软件和硬件的通讯,串口用的也比较多的.在网上找了很多串口调试工具,大都年代久远,没有继续更新维护的了. 于是,自己抽空写了一个:串口调试助手.基于Android-Se ...

  2. python实现SMO(优化版)

    #来自周志华的<机器学习> from numpy import *#存储变量的类 class opStruct():def __init__(self,dataMatIn,classLab ...

  3. TwinCAT3串口通讯EL6021模块使用-和串口调试助手自由协议通讯

    目录 一.简介 二.环境介绍 三.接线连接 四.创建TwinCAT3程序工程 1.IO扫描和参数设置 2.字符串型数据发送和接收PLC程序创建 (1)库文件添加 (2)创建任务和程序 (3)变量关联 ...

  4. 汇川AM402和串口调试助手自由协议通信

    1.硬件说明 PLC:汇川AM402-CPU1608TP PC:串口调试助手 连接:RS485转232.USB转232 如下图所示 PLC的DB9接头2路485接线说明 选择一路使用即可,本测试选择1 ...

  5. <Python>PyQt5自己编写一个音乐播放器(优化版)

    Python音乐播放器 更新日志: 20221031:添加独立播放列表 20221107:添加"上一首"."下一首"功能 展示图片: 202211071308更 ...

  6. Python 简易版贪食蛇(源代码)

    Python 简易版贪食蛇 简易版贪食蛇代码如下,直接运行即可. 1. 效果图 2.源代码 源代码如下: #!/usr/bin/env python # -*- coding: utf-8 -*-im ...

  7. 通达信手机版分时图指标大全_通达信精选指标——操盘手主图优化版

    通达信精选指标--操盘手主图优化版 MA10:MA(CLOSE,10),LINETHICK1,COLORYELLOW; MA20:MA(CLOSE,20),LINETHICK1,COLORMAGENT ...

  8. python三级菜单(优化版)

    python三级菜单(优化版) #!/usr/bin/env python #-*- coding:utf-8 -*-dic = {'北京': {'东城':{'沙河': ['沙河机场', '链家'], ...

  9. 串口调试助手源代码 qt编写 带协议解析 帧判断 通信数据保存等功能

    串口调试助手源代码 qt编写 带协议解析 帧判断 通信数据保存等功能 使用说明介绍 1.功能介绍: 采用Qt编写的串口调试助手工具,功能齐全,除了具备十六进制收发及文件保存等基本功能外,还具有以下功能 ...

最新文章

  1. mediav聚效广告代码片段
  2. 217. 验证码 demo
  3. 别再@微信官方 了,我给你一面小国旗!
  4. 连接LilyPad之Windows平台的驱动
  5. 【Linux迁移到Windows服务器时的注意事项】
  6. sdut 1028 Catch That Cow( BFS)
  7. 随机查找数组中第i个元素(按顺序排列的)
  8. adb 查看当前包名和Activity
  9. SQLite轻量级数据库,操作数据常用语句
  10. 解决ionic切换路由后,不继承tab路由,没有返回按钮问题
  11. UICollectionView reloadData后cell被隐藏
  12. ppt流程图字体太小_简单三步,用WPS轻松完成一个又大气又好看的流程图!
  13. ServiceLoader用法demo
  14. vs 错误error C2011:类型重定义的解决办法
  15. centos安装aria2c_CentOS安装aria2 + yaaw实现离线下载
  16. 编写数码管c语言程序,跪求单片机0~99数码管显示用C语言编写的程序
  17. TransBigData:一款基于 Python 的超酷炫交通时空大数据工具包
  18. 郭明錤连发8条猛料!爆苹果MR头显最新进展
  19. Java获取名字首字母拼音并按名字拼音分组工具类
  20. 引流、回流、截留、一个普通的早餐店如何做到日盈利2000的?

热门文章

  1. MySQL删除用户报错:ERROR 1396 (HY000): Operation DROP USER failed for ‘tsjt‘@‘127.0.0.1‘
  2. 前端Html快速入门
  3. android 获取alertdialog的view,Android AlertDialog使用
  4. vue 搜索文本让搜索的字体高亮显示
  5. H5 实现公众号授权登录
  6. 成就好生意·成为好企业丨828 B2B企业节,永洪科技来了
  7. 用迭代法求非线性方程的实根
  8. 总结了9款Mac端超好用的免费开源软件,你还有更好的推荐吗?
  9. TranslateMessage DispatchMessage
  10. 魅族android n彩蛋,魅族17“隐藏彩蛋”曝光!Flyme大版本更新正式解锁