33.python串口助手工具案例详解
逻辑文件
import sys import serial import serial.tools.list_ports from Ui_day13_test01 import Ui_mainWindow from PyQt5.QtWidgets import QMainWindow,QApplication,QMessageBox from PyQt5.QtCore import QTimer # AttributeError: 'Pyqt5_Serial' object has no attribute 'setCentralWidget'的解决方法 class PyqtSerial(QMainWindow,Ui_mainWindow): def __init__(self): super().__init__() # 用super继承父类中的__init__()方法 # 因为前面Ui程序中mainWindow = QtWidgets.QMainWindow(),而在逻辑文件中self是 # 指myshow对象,相当于就是用用myshow来设置界面 self.setupUi(self) self.start() self.setWindowTitle('我的串口小助手') # 更改软件标题名称 self.ser=serial.Serial() # 调用串口模块 # 接收数据和发送数据数目置零 self.data_num_received = 0 self.recv_byte.setText(str(self.data_num_received)) self.data_num_sended = 0 self.send_byte.setText(str(self.data_num_sended)) # 函数执行条件变量 self.com_check=False # 判断串口是否检查 # 设置界面启动函数 def start(self): self.state_label.setText('请点击【检测串口】按钮!') # 串口检测按钮 self.ser_test.clicked.connect(self.portCheck) # 串口信息显示 self.com_port.currentTextChanged.connect(self.portImf) # 打开串口按钮 self.open_ser.clicked.connect(self.portOpen) # 关闭串口按钮 self.close_ser.clicked.connect(self.portClose) # 发送数据按钮 self.send_botton.clicked.connect(self.dataSend) # 发送定时器发送数据 self.timer_send=QTimer() # 括号内可以加self,也可以不加 self.timer_send.timeout.connect(self.dataSend) # 每次计时结束,触发括号内的函数 self.time_send.stateChanged.connect(self.dataTimerSend) # QCheckBox选择框改变后连接括号内的函数 # 接收定时器接收数据 # 程序先运行start函数,然后运行到这个定时器时,就不操作了,只要界面上有操作, # 并且该操作对应的函数里有self.timer.start()开始计时的代码,则当计时结束后, # 就会触发此定时器后面的函数 self.timer=QTimer() # 创建一个定时器 self.timer.timeout.connect(self.dataReceive) # 每次计时结束,触发括号内的函数 # 清除发送窗口 self.send_clear.clicked.connect(self.sendDataClear) # 清除接收窗口 self.recv_clear.clicked.connect(self.receiveDataClear) # 清除发送窗口 def sendDataClear(self): self.send_data.setText('') # 清除接收窗口 def receiveDataClear(self): self.recv_data.setText('') # 定时发送数据 def dataTimerSend(self): if self.time_send.isChecked(): # 检查time_send的QCheckBox是否勾选上 self.timer_send.start(int(self.time_num.text())) # 计时器按time_num值开始计时 self.time_num.setEnabled(False) # time_num的QLineEdit不选中 else: self.timer_send.stop() # 发送计时器停止 self.time_num.setEnabled(True) # # time_num的QLineEdit选中 # 发送数据 def dataSend(self): if self.ser.isOpen(): # 判断串口是否打开 input_s=self.send_data.toPlainText() # 将发送文本框中的内容赋值给变量 if input_s !='': # 判断发送文本框中有内容 # 非空字符串 if self.send_hex.isChecked(): # 判断hex的QCheckBox勾选上了 # hex发送 input_s=input_s.strip() # 去掉发送文本框内容前后的空格、回车等 send_list=[] # 创建一个发送列表 while input_s !='': # 发送内容变量不为空 try: # >>> int('12',base=16) # 如果是带参数base的话,12要以字符串的形式进行输入,12 为 16进制 # 18 num=int(input_s[0:2],16) # 将发送内容的前两位转换成16进制 except ValueError: QMessageBox.critical(self,'wrong data','请输入十六进制数据,以空格分开!') return input_s=input_s[2:].strip() # 切割input_s中前两位,并去掉前后空格,最后赋值到input_s send_list.append(num) # 将已经转换的前两位添加到发送列表中 input_s=bytes(send_list) # 将发送列表转换成bytes else: # ascii发送 input_s=(input_s+'\r\n').encode('gbk') # 将发送内容按gbk格式编码 num=self.ser.write(input_s) # 发送数据 self.data_num_sended+=num # 已发送内容计数 self.send_byte.setText(str(self.data_num_sended)) # 改变已发送计数框中的值 else: pass # 关闭串口 def portClose(self): self.timer.stop() # 接收定时器关闭 self.timer_send.stop() # 发送定时器关闭 try: self.ser.close() # 关闭串口 except: pass self.open_ser.setEnabled(True) # 设置按钮QPushButton状态为True self.close_ser.setEnabled(False) # 设置按钮QPushButton状态为False self.time_num.setEnabled(True) # QLineEdit恢复默认值 # 接收数据和发送数据数目置零 self.data_num_received=0 self.recv_byte.setText(str(self.data_num_received)) self.data_num_sended=0 self.send_byte.setText(str(self.data_num_sended)) self.groupBox_4.setTitle('串口状态(已关闭)') # 改变串口状态框的名称 # 接收数据 def dataReceive(self): # self.timer.start(2000) # 此处设置的时间为2000毫秒,表示每间隔2000毫秒运行下面的print代码 # print('数据接收中') try: num=self.ser.inWaiting() # 返回接收缓冲区中的字符数 except: self.portClose() # 关闭串口 return None if num>0: # 接收缓冲区中的字符数大于零时 data=self.ser.read(num) # 读取全部数据 num=len(data) # 提取数据的字符长度 # hex显示 if self.recv_hex.checkState(): # 判断hex接收的QCheckBox是否选中 out_s='' for i in range(0,len(data)): # 循环遍历接收到的数据 # X:输出整数的大写十六进制方式; out_s=out_s+'{:X}'.format(data[i])+' ' # 将字符转换成整数的大写十六进制方式 self.recv_data.insertPlainText(out_s) # 将转换好的数据添加到接收数据文本框中 else: # 串口接收到的字符串为b'123',要转化成unicode字符串才能输出到窗口中去 self.recv_data.insertPlainText(data.decode('gbk')) # 统计接收字符的数量 self.data_num_received+=num # 将接收到的数据的长度数赋值给计数变量 self.recv_byte.setText(str(self.data_num_received)) # 将接收到的数据长度数显示在计数文本框中 # 获取到text光标 textCursor=self.recv_data.textCursor() # 滚动到底部 textCursor.movePosition(textCursor.End) # 设置光标到text中去 self.recv_data.setTextCursor(textCursor) else: pass # 打开串口 def portOpen(self): # try: # # 设置串口参数(此为网友代码),运行出错, # self.ser.port=self.com_port.currentText() # self.ser.baudrate=int(self.baudrate.currentText()) # self.ser.bytesize=int(self.data_bit.currentText()) # self.ser.stopbits=int(self.stop_bit.currentText()) # self.ser.parity=self.check_bit.currentText() # 出错原因在这里,这个是不用的 # except Exception as e: # print('请先打开其它设置!',e) # 设置串口参数 self.ser.port = self.com_port.currentText() self.ser.baudrate = int(self.baudrate.currentText()) self.ser.bytesize = int(self.data_bit.currentText()) self.ser.stopbits = int(self.stop_bit.currentText()) try: self.ser.open() except: QMessageBox.critical(self,'Port Error','此串口不能被打开!') return None # return代表结束该函数执行,此处可以写成return不加None # 打开串口接收定时器,周期为2ms self.timer.start(2) # 此处的意思是当2ms的时间到了之后,触发括号内的dataReceive函数 if self.ser.isOpen(): self.open_ser.setEnabled(False) # 设置按钮QPushButton状态为False self.close_ser.setEnabled(True) # 设置按钮QPushButton状态为True self.groupBox_4.setTitle('串口状态(已开启)') # 串口信息 def portImf(self): if self.com_check: # 显示选定的串口的详细信息 imf_s=self.com_port.currentText() # 将串口选择的当前内容赋值给变量 if imf_s !='': self.state_label.setText('串口{}选择完成!'.format(self.com_port.currentText())) else: self.state_label.setText('请先点击检测串口按钮!') # 串口检查 def portCheck(self): # 检测所有存在的串口,将信息存储在字典中 self.com_dict={} # 创建一个空字典 port_list=list(serial.tools.list_ports.comports()) # 查找串口数据,并保存在列表中 self.com_port.clear() # 清空默认串口菜单数据 # 遍列串口数列表,并将com名称重新添加到串口菜单中 for port in port_list: self.com_dict['%s'%port[0]]='%s'%port[1] self.com_port.addItem(port[0]) # 判断串口是否找到 if len(self.com_dict)==0: self.state_label.setText('无串口!') else: self.state_label.setText('共有{}个串口,请选择串口!'.format(len(self.com_dict))) self.com_check=True if __name__ == '__main__': app=QApplication(sys.argv) # 由于前面导入的是PyQt5.QtWidgets,而QApplication是该模块里的一个类 myshow=PyqtSerial() # 根据类来创建一个对象 myshow.show() # 对象显示 sys.exit(app.exec_())
界面文件
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_mainWindow(object): def setupUi(self, mainWindow): mainWindow.setObjectName("mainWindow") mainWindow.resize(721, 490) mainWindow.setMinimumSize(QtCore.QSize(721, 490)) mainWindow.setMaximumSize(QtCore.QSize(721, 490)) self.centralWidget = QtWidgets.QWidget(mainWindow) self.centralWidget.setObjectName("centralWidget") self.widget = QtWidgets.QWidget(self.centralWidget) self.widget.setGeometry(QtCore.QRect(20, 20, 681, 451)) self.widget.setObjectName("widget") self.groupBox = QtWidgets.QGroupBox(self.widget) self.groupBox.setGeometry(QtCore.QRect(0, 0, 221, 311)) self.groupBox.setObjectName("groupBox") self.layoutWidget = QtWidgets.QWidget(self.groupBox) self.layoutWidget.setGeometry(QtCore.QRect(10, 20, 201, 281)) self.layoutWidget.setObjectName("layoutWidget") self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") self.label_3 = QtWidgets.QLabel(self.layoutWidget) self.label_3.setObjectName("label_3") self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1) self.label_4 = QtWidgets.QLabel(self.layoutWidget) self.label_4.setObjectName("label_4") self.gridLayout.addWidget(self.label_4, 2, 0, 1, 3) self.label_5 = QtWidgets.QLabel(self.layoutWidget) self.label_5.setObjectName("label_5") self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1) self.label_6 = QtWidgets.QLabel(self.layoutWidget) self.label_6.setObjectName("label_6") self.gridLayout.addWidget(self.label_6, 4, 0, 1, 1) self.label_7 = QtWidgets.QLabel(self.layoutWidget) self.label_7.setObjectName("label_7") self.gridLayout.addWidget(self.label_7, 5, 0, 1, 1) self.label_8 = QtWidgets.QLabel(self.layoutWidget) self.label_8.setObjectName("label_8") self.gridLayout.addWidget(self.label_8, 6, 0, 1, 1) self.stop_bit = QtWidgets.QComboBox(self.layoutWidget) self.stop_bit.setObjectName("stop_bit") self.stop_bit.addItem("") self.stop_bit.addItem("") self.gridLayout.addWidget(self.stop_bit, 6, 1, 1, 2) self.open_ser = QtWidgets.QPushButton(self.layoutWidget) self.open_ser.setObjectName("open_ser") self.gridLayout.addWidget(self.open_ser, 7, 0, 1, 3) self.close_ser = QtWidgets.QPushButton(self.layoutWidget) self.close_ser.setObjectName("close_ser") self.gridLayout.addWidget(self.close_ser, 8, 0, 1, 3) self.com_port = QtWidgets.QComboBox(self.layoutWidget) self.com_port.setFocusPolicy(QtCore.Qt.WheelFocus) self.com_port.setObjectName("com_port") self.com_port.addItem("") self.com_port.addItem("") self.com_port.addItem("") self.com_port.addItem("") self.gridLayout.addWidget(self.com_port, 1, 1, 1, 2) self.label_2 = QtWidgets.QLabel(self.layoutWidget) self.label_2.setObjectName("label_2") self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1) self.baudrate = QtWidgets.QComboBox(self.layoutWidget) self.baudrate.setObjectName("baudrate") self.baudrate.addItem("") self.baudrate.addItem("") self.gridLayout.addWidget(self.baudrate, 3, 1, 1, 2) self.data_bit = QtWidgets.QComboBox(self.layoutWidget) self.data_bit.setObjectName("data_bit") self.data_bit.addItem("") self.data_bit.addItem("") self.data_bit.addItem("") self.data_bit.addItem("") self.gridLayout.addWidget(self.data_bit, 4, 1, 1, 2) self.check_bit = QtWidgets.QComboBox(self.layoutWidget) self.check_bit.setObjectName("check_bit") self.check_bit.addItem("") self.check_bit.addItem("") self.gridLayout.addWidget(self.check_bit, 5, 1, 1, 2) self.ser_test = QtWidgets.QPushButton(self.layoutWidget) self.ser_test.setObjectName("ser_test") self.gridLayout.addWidget(self.ser_test, 0, 1, 1, 2) self.groupBox_2 = QtWidgets.QGroupBox(self.widget) self.groupBox_2.setGeometry(QtCore.QRect(250, 0, 321, 181)) self.groupBox_2.setObjectName("groupBox_2") self.recv_data = QtWidgets.QTextEdit(self.groupBox_2) self.recv_data.setGeometry(QtCore.QRect(10, 20, 301, 151)) self.recv_data.setObjectName("recv_data") self.groupBox_3 = QtWidgets.QGroupBox(self.widget) self.groupBox_3.setGeometry(QtCore.QRect(250, 200, 321, 181)) self.groupBox_3.setObjectName("groupBox_3") self.send_data = QtWidgets.QTextEdit(self.groupBox_3) self.send_data.setGeometry(QtCore.QRect(10, 20, 301, 151)) self.send_data.setObjectName("send_data") self.groupBox_4 = QtWidgets.QGroupBox(self.widget) self.groupBox_4.setGeometry(QtCore.QRect(0, 330, 221, 111)) self.groupBox_4.setObjectName("groupBox_4") self.layoutWidget1 = QtWidgets.QWidget(self.groupBox_4) self.layoutWidget1.setGeometry(QtCore.QRect(30, 20, 161, 51)) self.layoutWidget1.setObjectName("layoutWidget1") self.gridLayout_2 = QtWidgets.QGridLayout(self.layoutWidget1) self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setObjectName("gridLayout_2") self.label_9 = QtWidgets.QLabel(self.layoutWidget1) self.label_9.setObjectName("label_9") self.gridLayout_2.addWidget(self.label_9, 0, 0, 1, 1) self.label_11 = QtWidgets.QLabel(self.layoutWidget1) self.label_11.setObjectName("label_11") self.gridLayout_2.addWidget(self.label_11, 1, 0, 1, 1) self.send_byte = QtWidgets.QLineEdit(self.layoutWidget1) self.send_byte.setObjectName("send_byte") self.gridLayout_2.addWidget(self.send_byte, 1, 2, 1, 1) self.recv_byte = QtWidgets.QLineEdit(self.layoutWidget1) self.recv_byte.setObjectName("recv_byte") self.gridLayout_2.addWidget(self.recv_byte, 0, 2, 1, 1) spacerItem = QtWidgets.QSpacerItem(80, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_2.addItem(spacerItem, 0, 1, 1, 1) self.state_label = QtWidgets.QLabel(self.groupBox_4) self.state_label.setGeometry(QtCore.QRect(20, 80, 181, 21)) self.state_label.setText("") self.state_label.setObjectName("state_label") self.recv_hex = QtWidgets.QCheckBox(self.widget) self.recv_hex.setGeometry(QtCore.QRect(590, 20, 91, 19)) self.recv_hex.setObjectName("recv_hex") self.send_hex = QtWidgets.QCheckBox(self.widget) self.send_hex.setGeometry(QtCore.QRect(590, 200, 91, 19)) self.send_hex.setObjectName("send_hex") self.recv_clear = QtWidgets.QPushButton(self.widget) self.recv_clear.setGeometry(QtCore.QRect(590, 50, 70, 30)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.recv_clear.sizePolicy().hasHeightForWidth()) self.recv_clear.setSizePolicy(sizePolicy) self.recv_clear.setStyleSheet("background-color: rgb(174, 255, 235);") self.recv_clear.setObjectName("recv_clear") self.send_botton = QtWidgets.QPushButton(self.widget) self.send_botton.setGeometry(QtCore.QRect(590, 230, 70, 30)) self.send_botton.setStyleSheet("background-color: rgb(174, 255, 235);") self.send_botton.setObjectName("send_botton") self.send_clear = QtWidgets.QPushButton(self.widget) self.send_clear.setGeometry(QtCore.QRect(590, 280, 70, 30)) self.send_clear.setStyleSheet("background-color: rgb(174, 255, 235);") self.send_clear.setObjectName("send_clear") self.layoutWidget2 = QtWidgets.QWidget(self.widget) self.layoutWidget2.setGeometry(QtCore.QRect(260, 400, 211, 23)) self.layoutWidget2.setObjectName("layoutWidget2") self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget2) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.time_send = QtWidgets.QCheckBox(self.layoutWidget2) self.time_send.setObjectName("time_send") self.horizontalLayout.addWidget(self.time_send) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.time_num = QtWidgets.QLineEdit(self.layoutWidget2) self.time_num.setMinimumSize(QtCore.QSize(60, 0)) self.time_num.setMaximumSize(QtCore.QSize(60, 16777215)) self.time_num.setObjectName("time_num") self.horizontalLayout.addWidget(self.time_num) self.label = QtWidgets.QLabel(self.layoutWidget2) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) mainWindow.setCentralWidget(self.centralWidget) self.retranslateUi(mainWindow) QtCore.QMetaObject.connectSlotsByName(mainWindow) def retranslateUi(self, mainWindow): _translate = QtCore.QCoreApplication.translate mainWindow.setWindowTitle(_translate("mainWindow", "串口小助手")) self.groupBox.setTitle(_translate("mainWindow", "串口设置")) self.label_3.setText(_translate("mainWindow", "串口选择:")) self.label_4.setText(_translate("mainWindow", "Serial Port (COM1->COM2)")) self.label_5.setText(_translate("mainWindow", "波特率:")) self.label_6.setText(_translate("mainWindow", "数据位:")) self.label_7.setText(_translate("mainWindow", "校验位:")) self.label_8.setText(_translate("mainWindow", "停止位:")) self.stop_bit.setItemText(0, _translate("mainWindow", "1")) self.stop_bit.setItemText(1, _translate("mainWindow", "2")) self.open_ser.setText(_translate("mainWindow", "打开串口")) self.close_ser.setText(_translate("mainWindow", "关闭串口")) self.com_port.setItemText(0, _translate("mainWindow", "COM1")) self.com_port.setItemText(1, _translate("mainWindow", "COM2")) self.com_port.setItemText(2, _translate("mainWindow", "COM3")) self.com_port.setItemText(3, _translate("mainWindow", "COM4")) self.label_2.setText(_translate("mainWindow", "串口检测:")) self.baudrate.setItemText(0, _translate("mainWindow", "9600")) self.baudrate.setItemText(1, _translate("mainWindow", "115200")) self.data_bit.setItemText(0, _translate("mainWindow", "8")) self.data_bit.setItemText(1, _translate("mainWindow", "7")) self.data_bit.setItemText(2, _translate("mainWindow", "6")) self.data_bit.setItemText(3, _translate("mainWindow", "5")) self.check_bit.setItemText(0, _translate("mainWindow", "NONE")) self.check_bit.setItemText(1, _translate("mainWindow", "ODD")) self.ser_test.setText(_translate("mainWindow", "检测串口")) self.groupBox_2.setTitle(_translate("mainWindow", "接收区")) self.groupBox_3.setTitle(_translate("mainWindow", "发送区")) self.groupBox_4.setTitle(_translate("mainWindow", "串口状态")) self.label_9.setText(_translate("mainWindow", "已接收:")) self.label_11.setText(_translate("mainWindow", "已发送:")) self.send_byte.setText(_translate("mainWindow", "0")) self.recv_byte.setText(_translate("mainWindow", "0")) self.recv_hex.setText(_translate("mainWindow", "Hex接收")) self.send_hex.setText(_translate("mainWindow", "Hex发送")) self.recv_clear.setText(_translate("mainWindow", "清除")) self.send_botton.setText(_translate("mainWindow", "发送")) self.send_clear.setText(_translate("mainWindow", "清除")) self.time_send.setText(_translate("mainWindow", "定时发送")) self.time_num.setText(_translate("mainWindow", "1000")) self.label.setText(_translate("mainWindow", "ms/次")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) mainWindow = QtWidgets.QMainWindow() ui = Ui_mainWindow() ui.setupUi(mainWindow) mainWindow.show() sys.exit(app.exec_())
以前就是参照网友设计的一个串口助手小工具。
如有问题,可关注微信公众号进行咨询!