1、先介紹一下軟件的運(yùn)行環(huán)境,python3.6.1(32位) ,pyinstaller 3.3版本, pyserial 3.4版本, pyqt5 5.8.2版本,這些是主要用到的軟件包。 在windosw的 cmd命令行下輸入pip list可以查看
C:\Users\xxxxn>pip list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
altgraph (0.14)
colorama (0.3.7)
configparser (3.5.0)
freeze (1.0.10)
future (0.16.0)
futures (3.0.5)
gevent (1.2.1)
greenlet (0.4.12)
iso8601 (0.1.12)
macholib (1.8)
ntplib (0.3.3)
pefile (2017.9.3)
pigar (0.6.10)
pip (9.0.1)
py2exe (0.9.2.2)
PyInstaller (3.3)
pypiwin32 (220)
PyQt5 (5.8.2)
pyserial (3.4)
pywinusb (0.4.2)
PyYAML (3.12)
setuptools (28.8.0)
sip (4.19.2)
six (1.10.0)
wheel (0.29.0)
C:\Users\zhaoshimin>python
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 17:54:52) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
2、pycom串口助手實(shí)現(xiàn)的功能,十六進(jìn)制數(shù)據(jù)發(fā)送,接收,字符發(fā)送,接收,定時(shí)發(fā)送,增加一個(gè)刷新串口設(shè)備按鈕,可以不用關(guān)閉軟件,刷新一下新安裝的串口。串口助手運(yùn)行過(guò)程中USB轉(zhuǎn)串口的設(shè)備斷開(kāi)軟件不會(huì)死機(jī),相比一些其他工具有提高。
3、程序主要由pycom.py和mainwindow.py組成,窗口代碼使用QtCreat自動(dòng)生成。pycom.py實(shí)現(xiàn)了串口的操作和菜單邏輯
pycom.py的源代碼如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QTimer
from mainwindow import Ui_MainWindow
import sys
#from datetime import datetime
import serial
import serial.tools.list_ports
from pyico import *
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
# 設(shè)置應(yīng)用程序的窗口圖標(biāo)
self.setWindowIcon(QIcon(":/com.png"))
#串口無(wú)效
self.ser = None
self.send_num = 0
self.receive_num = 0
#顯示發(fā)送與接收的字符數(shù)量
dis = '發(fā)送:'+ '{:d}'.format(self.send_num) + ' 接收:' + '{:d}'.format(self.receive_num)
self.statusBar.showMessage(dis)
#刷新一下串口的列表
self.refresh()
#波特率控件
self.comboBox_2.addItem('115200')
self.comboBox_2.addItem('57600')
self.comboBox_2.addItem('56000')
self.comboBox_2.addItem('38400')
self.comboBox_2.addItem('19200')
self.comboBox_2.addItem('14400')
self.comboBox_2.addItem('9600')
self.comboBox_2.addItem('4800')
self.comboBox_2.addItem('2400')
self.comboBox_2.addItem('1200')
#數(shù)據(jù)位控件
self.comboBox_3.addItem('8')
self.comboBox_3.addItem('7')
self.comboBox_3.addItem('6')
self.comboBox_3.addItem('5')
#停止位控件
self.comboBox_4.addItem('1')
self.comboBox_4.addItem('1.5')
self.comboBox_4.addItem('2')
#校驗(yàn)位控件
self.comboBox_5.addItem('NONE')
self.comboBox_5.addItem('ODD')
self.comboBox_5.addItem('EVEN')
#對(duì)testEdit進(jìn)行事件過(guò)濾
self.textEdit.installEventFilter(self)
#實(shí)例化一個(gè)定時(shí)器
self.timer = QTimer(self)
self.timer_send= QTimer(self)
#定時(shí)器調(diào)用讀取串口接收數(shù)據(jù)
self.timer.timeout.connect(self.recv)
#定時(shí)發(fā)送
self.timer_send.timeout.connect(self.send)
#發(fā)送數(shù)據(jù)按鈕
self.pushButton.clicked.connect(self.send)
#打開(kāi)關(guān)閉串口按鈕
self.pushButton_2.clicked.connect(self.open_close)
#刷新串口外設(shè)按鈕
self.pushButton_4.clicked.connect(self.refresh)
#清除窗口
self.pushButton_3.clicked.connect(self.clear)
#定時(shí)發(fā)送
self.checkBox_4.clicked.connect(self.send_timer_box)
#刷新一下串口
def refresh(self):
#查詢可用的串口
plist=list(serial.tools.list_ports.comports())
if len(plist) <= 0:
print("No used com!");
self.statusBar.showMessage('沒(méi)有可用的串口')
else:
#把所有的可用的串口輸出到comboBox中去
self.comboBox.clear()
for i in range(0, len(plist)):
plist_0 = list(plist[i])
self.comboBox.addItem(str(plist_0[0]))
#事件過(guò)濾
def eventFilter(self, obj, event):
#處理textEdit的鍵盤按下事件
if event.type() == event.KeyPress:
if self.ser != None:
#獲取按鍵對(duì)應(yīng)的字符
char = event.text()
num = self.ser.write(char.encode('utf-8'))
self.send_num = self.send_num + num
dis = '發(fā)送:'+ '{:d}'.format(self.send_num) + ' 接收:' + '{:d}'.format(self.receive_num)
self.statusBar.showMessage(dis)
else:
pass
return True
else:
return False
#重載窗口關(guān)閉事件
def closeEvent(self,e):
#關(guān)閉定時(shí)器,停止讀取接收數(shù)據(jù)
self.timer_send.stop()
self.timer.stop()
#關(guān)閉串口
if self.ser != None:
self.ser.close()
#定時(shí)發(fā)送數(shù)據(jù)
def send_timer_box(self):
if self.checkBox_4.checkState():
time = self.lineEdit_2.text()
try:
time_val = int(time, 10)
except ValueError:
QMessageBox.critical(self, 'pycom','請(qǐng)輸入有效的定時(shí)時(shí)間!')
return None
if time_val == 0:
QMessageBox.critical(self, 'pycom','定時(shí)時(shí)間必須大于零!')
return None
#定時(shí)間隔發(fā)送
self.timer_send.start(time_val)
else:
self.timer_send.stop()
#清除窗口操作
def clear(self):
self.textEdit.clear()
self.send_num = 0
self.receive_num = 0
dis = '發(fā)送:'+ '{:d}'.format(self.send_num) + ' 接收:' + '{:d}'.format(self.receive_num)
self.statusBar.showMessage(dis)
#串口接收數(shù)據(jù)處理
def recv(self):
try:
num = self.ser.inWaiting()
except:
self.timer_send.stop()
self.timer.stop()
#串口拔出錯(cuò)誤,關(guān)閉定時(shí)器
self.ser.close()
self.ser = None
#設(shè)置為打開(kāi)按鈕狀態(tài)
self.pushButton_2.setChecked(False)
self.pushButton_2.setText("打開(kāi)串口")
print('serial error!')
return None
if(num > 0):
#有時(shí)間會(huì)出現(xiàn)少讀到一個(gè)字符的情況,還得進(jìn)行讀取第二次,所以多讀一個(gè)
data = self.ser.read(num)
#調(diào)試打印輸出數(shù)據(jù)
#print(data)
num = len(data)
#十六進(jìn)制顯示
if self.checkBox_3.checkState():
out_s=''
for i in range(0, len(data)):
out_s = out_s + '{:02X}'.format(data[i]) + ' '
self.textEdit.insertPlainText(out_s)
else:
#串口接收到的字符串為b'123',要轉(zhuǎn)化成unicode字符串才能輸出到窗口中去
self.textEdit.insertPlainText(data.decode('iso-8859-1'))
#統(tǒng)計(jì)接收字符的數(shù)量
self.receive_num = self.receive_num + num
dis = '發(fā)送:'+ '{:d}'.format(self.send_num) + ' 接收:' + '{:d}'.format(self.receive_num)
self.statusBar.showMessage(dis)
#獲取到text光標(biāo)
textCursor = self.textEdit.textCursor()
#滾動(dòng)到底部
textCursor.movePosition(textCursor.End)
#設(shè)置光標(biāo)到text中去
self.textEdit.setTextCursor(textCursor)
else:
pass
#串口發(fā)送數(shù)據(jù)處理
def send(self):
if self.ser != None:
input_s = self.lineEdit.text()
if input_s != "":
#發(fā)送字符
if (self.checkBox.checkState() == False):
if self.checkBox_2.checkState():
#發(fā)送新行
input_s = input_s + '\r\n'
input_s = input_s.encode('utf-8')
else:
#發(fā)送十六進(jìn)制數(shù)據(jù)
input_s = input_s.strip() #刪除前后的空格
send_list=[]
while input_s != '':
try:
num = int(input_s[0:2], 16)
except ValueError:
print('input hex data!')
QMessageBox.critical(self, 'pycom','請(qǐng)輸入十六進(jìn)制數(shù)據(jù),以空格分開(kāi)!')
return None
input_s = input_s[2:]
input_s = input_s.strip()
#添加到發(fā)送列表中
send_list.append(num)
input_s = bytes(send_list)
print(input_s)
#發(fā)送數(shù)據(jù)
try:
num = self.ser.write(input_s)
except:
self.timer_send.stop()
self.timer.stop()
#串口拔出錯(cuò)誤,關(guān)閉定時(shí)器
self.ser.close()
self.ser = None
#設(shè)置為打開(kāi)按鈕狀態(tài)
self.pushButton_2.setChecked(False)
self.pushButton_2.setText("打開(kāi)串口")
print('serial error send!')
return None
self.send_num = self.send_num + num
dis = '發(fā)送:'+ '{:d}'.format(self.send_num) + ' 接收:' + '{:d}'.format(self.receive_num)
self.statusBar.showMessage(dis)
#print('send!')
else:
print('none data input!')
else:
#停止發(fā)送定時(shí)器
self.timer_send.stop()
QMessageBox.critical(self, 'pycom','請(qǐng)打開(kāi)串口')
#打開(kāi)關(guān)閉串口
def open_close(self, btn_sta):
if btn_sta == True:
try:
#輸入?yún)?shù)'COM13',115200
print(int(self.comboBox_2.currentText()))
self.ser = serial.Serial(self.comboBox.currentText(), int(self.comboBox_2.currentText()), timeout=0.1)
except:
QMessageBox.critical(self, 'pycom','沒(méi)有可用的串口或當(dāng)前串口被占用')
return None
#字符間隔超時(shí)時(shí)間設(shè)置
self.ser.interCharTimeout = 0.001
#1ms的測(cè)試周期
self.timer.start(2)
self.pushButton_2.setText("關(guān)閉串口")
print('open!')
else:
#關(guān)閉定時(shí)器,停止讀取接收數(shù)據(jù)
self.timer_send.stop()
self.timer.stop()
try:
#關(guān)閉串口
self.ser.close()
except:
QMessageBox.critical(self, 'pycom','關(guān)閉串口失敗')
return None
self.ser = None
self.pushButton_2.setText("打開(kāi)串口")
print('close!')
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
4、界面程序的源代碼如下:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.8.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(494, 418)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setAutoFillBackground(False)
self.centralWidget.setObjectName("centralWidget")
self.textEdit = QtWidgets.QTextEdit(self.centralWidget)
self.textEdit.setGeometry(QtCore.QRect(10, 0, 471, 201))
self.textEdit.setObjectName("textEdit")
self.label = QtWidgets.QLabel(self.centralWidget)
self.label.setGeometry(QtCore.QRect(10, 210, 51, 21))
self.label.setObjectName("label")
self.label_2 = QtWidgets.QLabel(self.centralWidget)
self.label_2.setGeometry(QtCore.QRect(10, 240, 51, 21))
self.label_2.setObjectName("label_2")
self.comboBox = QtWidgets.QComboBox(self.centralWidget)
self.comboBox.setGeometry(QtCore.QRect(50, 210, 69, 22))
self.comboBox.setObjectName("comboBox")
self.comboBox_2 = QtWidgets.QComboBox(self.centralWidget)
self.comboBox_2.setGeometry(QtCore.QRect(50, 240, 69, 22))
self.comboBox_2.setObjectName("comboBox_2")
self.lineEdit = QtWidgets.QLineEdit(self.centralWidget)
self.lineEdit.setGeometry(QtCore.QRect(130, 280, 341, 20))
self.lineEdit.setObjectName("lineEdit")
self.label_3 = QtWidgets.QLabel(self.centralWidget)
self.label_3.setGeometry(QtCore.QRect(130, 250, 91, 31))
self.label_3.setObjectName("label_3")
self.pushButton = QtWidgets.QPushButton(self.centralWidget)
self.pushButton.setGeometry(QtCore.QRect(390, 250, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(self.centralWidget)
self.pushButton_2.setGeometry(QtCore.QRect(140, 210, 75, 23))
self.pushButton_2.setCheckable(True)
self.pushButton_2.setObjectName("pushButton_2")
self.comboBox_3 = QtWidgets.QComboBox(self.centralWidget)
self.comboBox_3.setGeometry(QtCore.QRect(50, 270, 69, 22))
self.comboBox_3.setObjectName("comboBox_3")
self.comboBox_4 = QtWidgets.QComboBox(self.centralWidget)
self.comboBox_4.setGeometry(QtCore.QRect(50, 300, 69, 22))
self.comboBox_4.setObjectName("comboBox_4")
self.label_4 = QtWidgets.QLabel(self.centralWidget)
self.label_4.setGeometry(QtCore.QRect(10, 270, 51, 21))
self.label_4.setObjectName("label_4")
self.label_5 = QtWidgets.QLabel(self.centralWidget)
self.label_5.setGeometry(QtCore.QRect(10, 300, 51, 21))
self.label_5.setObjectName("label_5")
self.comboBox_5 = QtWidgets.QComboBox(self.centralWidget)
self.comboBox_5.setGeometry(QtCore.QRect(50, 330, 69, 22))
self.comboBox_5.setObjectName("comboBox_5")
self.label_6 = QtWidgets.QLabel(self.centralWidget)
self.label_6.setGeometry(QtCore.QRect(10, 330, 51, 21))
self.label_6.setObjectName("label_6")
self.pushButton_3 = QtWidgets.QPushButton(self.centralWidget)
self.pushButton_3.setGeometry(QtCore.QRect(390, 210, 75, 23))
self.pushButton_3.setObjectName("pushButton_3")
self.checkBox = QtWidgets.QCheckBox(self.centralWidget)
self.checkBox.setGeometry(QtCore.QRect(130, 310, 71, 16))
self.checkBox.setObjectName("checkBox")
self.checkBox_2 = QtWidgets.QCheckBox(self.centralWidget)
self.checkBox_2.setGeometry(QtCore.QRect(210, 310, 71, 16))
self.checkBox_2.setObjectName("checkBox_2")
self.pushButton_4 = QtWidgets.QPushButton(self.centralWidget)
self.pushButton_4.setGeometry(QtCore.QRect(220, 210, 81, 23))
self.pushButton_4.setObjectName("pushButton_4")
self.checkBox_3 = QtWidgets.QCheckBox(self.centralWidget)
self.checkBox_3.setGeometry(QtCore.QRect(310, 210, 71, 21))
self.checkBox_3.setObjectName("checkBox_3")
self.checkBox_4 = QtWidgets.QCheckBox(self.centralWidget)
self.checkBox_4.setGeometry(QtCore.QRect(140, 240, 71, 16))
self.checkBox_4.setObjectName("checkBox_4")
self.lineEdit_2 = QtWidgets.QLineEdit(self.centralWidget)
self.lineEdit_2.setGeometry(QtCore.QRect(220, 240, 51, 16))
self.lineEdit_2.setObjectName("lineEdit_2")
self.label_7 = QtWidgets.QLabel(self.centralWidget)
self.label_7.setGeometry(QtCore.QRect(280, 240, 54, 12))
self.label_7.setObjectName("label_7")
self.gridLayoutWidget = QtWidgets.QWidget(self.centralWidget)
self.gridLayoutWidget.setGeometry(QtCore.QRect(0, 0, 2, 2))
self.gridLayoutWidget.setObjectName("gridLayoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(11, 11, 11, 11)
self.gridLayout.setSpacing(6)
self.gridLayout.setObjectName("gridLayout")
MainWindow.setCentralWidget(self.centralWidget)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 494, 23))
self.menuBar.setObjectName("menuBar")
MainWindow.setMenuBar(self.menuBar)
self.mainToolBar = QtWidgets.QToolBar(MainWindow)
self.mainToolBar.setObjectName("mainToolBar")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar)
self.statusBar = QtWidgets.QStatusBar(MainWindow)
self.statusBar.setObjectName("statusBar")
MainWindow.setStatusBar(self.statusBar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "pycom串口助手(作者:龍騰 fhqlongteng@163.com)"))
self.label.setText(_translate("MainWindow", "串口號(hào)"))
self.label_2.setText(_translate("MainWindow", "波特率"))
self.lineEdit.setText(_translate("MainWindow", "123"))
self.label_3.setText(_translate("MainWindow", "字符串輸入框:"))
self.pushButton.setText(_translate("MainWindow", "發(fā)送"))
self.pushButton_2.setText(_translate("MainWindow", "打開(kāi)串口"))
self.label_4.setText(_translate("MainWindow", "數(shù)據(jù)位"))
self.label_5.setText(_translate("MainWindow", "停止位"))
self.label_6.setText(_translate("MainWindow", "校驗(yàn)位"))
self.pushButton_3.setText(_translate("MainWindow", "清除窗口"))
self.checkBox.setText(_translate("MainWindow", "HEX發(fā)送"))
self.checkBox_2.setText(_translate("MainWindow", "發(fā)送新行"))
self.pushButton_4.setText(_translate("MainWindow", "刷新串口設(shè)備"))
self.checkBox_3.setText(_translate("MainWindow", "HEX顯示"))
self.checkBox_4.setText(_translate("MainWindow", "定時(shí)發(fā)送"))
self.lineEdit_2.setText(_translate("MainWindow", "1000"))
self.label_7.setText(_translate("MainWindow", "ms/次"))
以上pycom串口軟件程序經(jīng)過(guò)常時(shí)間使用和評(píng)測(cè),已經(jīng)十分穩(wěn)定,請(qǐng)放心使用或修改。
5、軟件圖標(biāo)的程序文件,軟件上顯示的LOGO要生成pyico.py文件供窗口應(yīng)用程序調(diào)用來(lái)顯示出來(lái),pyico文件是從圖片資源文件自動(dòng)生成的。
最后提供一個(gè)完整工程的下載鏈接:https://pan.baidu.com/s/1uNHH_nAa5deGizRCuN2cTQ
您還可以掃碼支付寶轉(zhuǎn)帳10元
最新版本的接收數(shù)據(jù)中使用了QT線程來(lái)接收,線程中使用了延時(shí)函數(shù)self.sleep(0.002),表示延時(shí)2ms,由于新版本的pyqt此函數(shù)的功能發(fā)生了變化,不支持參數(shù)為小數(shù),所以你使用此代碼,引用新版本的pyqt代碼可能會(huì)出現(xiàn)問(wèn)題,請(qǐng)修改成self.sleep(1)來(lái)確認(rèn)可以運(yùn)行就是這個(gè)問(wèn)題。確認(rèn)后查找一下新版本pyqt中的延時(shí)函數(shù)self.msleep(2),使用這個(gè)代替就可以運(yùn)行了。
聯(lián)系客服