使用python+Pyqt5實現(xiàn)串口調試助手
python可以利用serial模塊來和串口設備進行485或者232通訊。

當然,網(wǎng)上這類串口調試助手的小程序有很多,不過這些程序要么是要收費,只能試用30天,要么是不好用。
況且,別人寫的程序,你只能使用,無法取出其中的數(shù)據(jù)來進行處理,所以,如果可以自己寫一個程序,既方便使用,又可以隨時隨地使用其中的數(shù)據(jù)。
軟件:python3.10
pycharm2021
硬件:window10電腦
串口485設備(國產流量計)
串口轉usb線(電腦不帶串口,只能轉接)


準備好了后,就可以開始寫程序了。
串口通訊程序首先要對串口進行設置,如波特率、數(shù)據(jù)位、停止位、校驗位等??梢苑Q之為初始化:
初始化:
def serial_init(self): #初始化
self.port = self.port_set.currentText()
self.bps = int(self.baud_set.currentText())
self.timeout = float(self.timeout_set.text())
try:
self.ser = serial.Serial(port=self.port,baudrate=self.bps,bytesize=8,parity='N',stopbits=1)
print(self.ser)
if self.ser.is_open:
print('串口正常')
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)
print('異常:', e)初始化完成后,需要將串口打開,只有串口成功打開,才可以進行后面的數(shù)據(jù)傳輸。python中的serial模塊,提供serial.isopen來進行檢查。當然,此處需要注意的是,在串口serial實例化的時候,實際上已經同時打開串口了。所以,如果在初始化程序里建立了實例化:
self.ser = serial.Serial(port=self.port,baudrate=self.bps,bytesize=8,parity='N',stopbits=1)
那么也可以不用在重復打開串口了。
串口打開:
def open_serial(self): #打開串口
try:
self.ser.open()
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)
print('異常:', e)串口關閉:
def close_serial(self): #關閉串口
try:
self.ser.close()
except Exception as e:
QMessageBox.warning(self,'tips!',str(e),QMessageBox.Ok|QMessageBox.Cancel,QMessageBox.Ok)
print('異常:', e)調試完成后,最好關閉串口,有始有終。
在完成上面的初始化和打開步驟后,就可以進行數(shù)據(jù)的讀、寫了,本例中使用了與流量計進行通訊,讀取流量計實時流量。該流量計讀、寫數(shù)據(jù)時有專門的格式:

所以,從電腦端發(fā)送指令時,需要按照流量計的格式發(fā)送,才能得到正確的反饋。485是半雙工傳輸,即同一時間只能進行讀或者寫,讀、寫不能同時進行。
本例中,讀取流量指令格式為:
01 03 00 10 00 02 C5 CE
實際操作中,我將流量計設備地址修改為2,即
02 03 00 10 00 02 C5 CE
發(fā)送數(shù)據(jù):
def send_data(self):
ct = datetime.datetime.now() #獲取當前系統(tǒng)時間
ct_str = ct.strftime("%Y-%m-%d %H:%M:%S") #格式化當前系統(tǒng)時間(字符形式)
try:
self.senddata_s=self.le_senddata.text()
self.senddata=bytes.fromhex(self.senddata_s) #字符轉成字節(jié)
self.ser.write(self.senddata)
#self.senddata_str=self.senddata.hex()
self.senddata_str_fg=self.str_fenge(self.senddata_s)
#self.le_senddata.setText(self.senddata.hex())
self.le_recdata.append('\n' + '[' + ct_str+ ']' + ' ' + self.senddata_str_fg + '\n')
#print(self.senddata)
time.sleep(0.1)
self.read_data_size()
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)讀取數(shù)據(jù):
def read_data_size(self):
ct=datetime.datetime.now()
ct_str=ct.strftime("%Y-%m-%d %H:%M:%S")
try:
#self.size=10
self.read_data=self.ser.read_all()
#print(self.read_data)
self.read_data_str=self.read_data.hex() #字節(jié)轉成16進制字符顯示
#re.findall(r'.{3}',self.read_data_str)
self.read_data_str_fg=self.str_fenge(self.read_data_str)
#print(self.read_data_str)
self.le_recdata.append('\n'+'['+ct_str+']'+' '+self.read_data_str_fg+'\n')
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)
#return self.read_dataserial的讀取數(shù)據(jù)時,有幾種方式,read()、read_all()、readline(),read()就是按照字節(jié)數(shù)size大小讀取緩存區(qū)字節(jié),read_all()即讀取所有數(shù)據(jù),readline()讀取緩存區(qū)最新一行數(shù)據(jù)。
完整程序:
from numpy.lib.function_base import place
import serial
import serial.tools.list_ports
import sys
import re
import os
import time
import datetime
import threading
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Serialwindow(QWidget):
def __init__(self) -> None:
super().__init__()
self.initUI()
def initUI(self):
#self.stylefile = 'E:\\100proworld2021\opencvtestpro01\爬蟲程序\爬蟲-style.qss'
#self.qssstyle = CommonHelper.readQSS(self.stylefile)
self.port = ''
self.bps = 0
self.timeout = 0.0
self.senddata=bytes()
self.read_data=''
self.btn_plist=QPushButton('獲取可用串口',self)
self.btn_plist.setGeometry(20,20,60,20)
self.btn_plist.clicked.connect(self.get_serial_info)
self.btn_plist.adjustSize()
self.btn_ser_init=QPushButton('初始化',self)
self.btn_ser_init.setGeometry(20,50,60,20)
self.btn_ser_init.clicked.connect(self.serial_init)
self.btn_ser_init.adjustSize()
self.btn_open=QPushButton('打開串口',self)
self.btn_open.setGeometry(20,80,60,20)
self.btn_open.clicked.connect(self.open_serial)
self.btn_open.adjustSize()
self.btn_close=QPushButton('關閉串口',self)
self.btn_close.setGeometry(20,110,60,20)
self.btn_close.clicked.connect(self.close_serial)
self.btn_close.adjustSize()
self.btn_read_data=QPushButton('讀取數(shù)據(jù)',self)
self.btn_read_data.setGeometry(20,140,60,20)
self.btn_read_data.clicked.connect(self.read_data_size)
self.btn_read_data.adjustSize()
self.btn_write_data=QPushButton('發(fā)送數(shù)據(jù)',self)
self.btn_write_data.setGeometry(40,460,60,20)
self.btn_write_data.clicked.connect(self.send_data)
self.btn_write_data.adjustSize()
#Qcombobox
self.port_set=QComboBox(self)
self.port_set.setGeometry(500,20,100,20)
self.port_set.addItems(['COM1'])
#self.port_set.activated.connect(self.Qcombo)
self.lbl_port_set=QLabel(self)
self.lbl_port_set.setGeometry(420,20,60,20)
self.lbl_port_set.setText('串口號:')
self.baud_set=QComboBox(self)
self.baud_set.setGeometry(500,50,100,20)
self.baud_set.addItems(['9600','19200','38400','115200'])
self.lbl_baud_set=QLabel(self)
self.lbl_baud_set.setGeometry(420,50,60,20)
self.lbl_baud_set.setText('波特率:')
self.stopbit_set=QComboBox(self)
self.stopbit_set.setGeometry(500,80,100,20)
self.stopbit_set.addItems(['0','1'])
self.lbl_stopbit_set = QLabel(self)
self.lbl_stopbit_set.setGeometry(420, 80, 60, 20)
self.lbl_stopbit_set.setText('停止位:')
self.parity_set=QComboBox(self)
self.parity_set.setGeometry(500,110,100,20)
self.parity_set.addItems(['無','奇校驗','偶校驗'])
self.lbl_parity_set = QLabel(self)
self.lbl_parity_set.setGeometry(420, 110, 60, 20)
self.lbl_parity_set.setText('校驗位:')
self.databit_set=QComboBox(self)
self.databit_set.setGeometry(500,140,100,20)
self.databit_set.addItems(['8','7'])
self.lbl_databit_set=QLabel(self)
self.lbl_databit_set.setGeometry(420,140,60,20)
self.lbl_databit_set.setText('數(shù)據(jù)位:')
self.timeout_set=QLineEdit(self)
self.timeout_set.setGeometry(500,170,100,20)
self.timeout_set.setText('1000')
self.lbl_timeout_set=QLabel(self)
self.lbl_timeout_set.setGeometry(420,170,60,20)
self.lbl_timeout_set.setText('超時設置:')
self.lbl_timeout_set_2=QLabel(self)
self.lbl_timeout_set_2.setGeometry(610,170,60,20)
self.lbl_timeout_set_2.setText('ms')
#
self.le_senddata=QLineEdit(self)
self.le_senddata.setGeometry(120,460,300,20)
self.le_senddata.setText('010300100002C5CE')
self.le_recdata=QTextEdit(self)
self.le_recdata.setGeometry(120,220,600,200)
self.setGeometry(100,100,800,600)
self.setWindowTitle('簡易串口調試助手-菌塵')
# self.setStyleSheet(self.qssstyle)
self.show()
def Qcombo(self):
print(self.port_set.currentText())
print(self.baud_set.currentText())
print(self.stopbit_set.currentText())
print(self.parity_set.currentText())
print(self.databit_set.currentText())
print(self.timeout_set.text())
def get_serial_info(self): #獲取可用串口列表
#打印可用串口列表
#self.need_serial = ''
self.plist = list(serial.tools.list_ports.comports())
if len(self.plist) <= 0:
print('未找到串口')
qm = QMessageBox.warning(self, '提示窗口', '未找到串口!請檢查接線和電腦接口。', QMessageBox.Ok|QMessageBox.Cancel,QMessageBox.Ok)
if qm == QMessageBox.Yes:
print('Yes')
else:
print('No')
else:
for i in list(self.plist):
self.port_set.addItem(i.name)
#return self.need_serial
#print(self.plist)
def serial_init(self): #初始化
self.port = self.port_set.currentText()
self.bps = int(self.baud_set.currentText())
self.timeout = float(self.timeout_set.text())
try:
self.ser = serial.Serial(port=self.port,baudrate=self.bps,bytesize=8,parity='N',stopbits=1)
print(self.ser)
if self.ser.is_open:
print('串口正常')
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)
print('異常:', e)
def open_serial(self): #打開串口
try:
self.ser.open()
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)
print('異常:', e)
def close_serial(self): #關閉串口
try:
self.ser.close()
except Exception as e:
QMessageBox.warning(self,'tips!',str(e),QMessageBox.Ok|QMessageBox.Cancel,QMessageBox.Ok)
print('異常:', e)
def read_data_size(self):
ct=datetime.datetime.now()
ct_str=ct.strftime("%Y-%m-%d %H:%M:%S")
try:
#self.size=10
self.read_data=self.ser.read_all()
#print(self.read_data)
self.read_data_str=self.read_data.hex() #字節(jié)轉成16進制字符顯示
#re.findall(r'.{3}',self.read_data_str)
self.read_data_str_fg=self.str_fenge(self.read_data_str)
#print(self.read_data_str)
self.le_recdata.append('\n'+'['+ct_str+']'+' '+self.read_data_str_fg+'\n')
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)
#return self.read_data
def read_data_line(self):
self.read_data=self.ser.readline()
return self.read_data
def send_data(self):
ct = datetime.datetime.now() #獲取當前系統(tǒng)時間
ct_str = ct.strftime("%Y-%m-%d %H:%M:%S") #格式化當前系統(tǒng)時間(字符形式)
try:
self.senddata_s=self.le_senddata.text()
self.senddata=bytes.fromhex(self.senddata_s) #字符轉成字節(jié)
self.ser.write(self.senddata)
#self.senddata_str=self.senddata.hex()
self.senddata_str_fg=self.str_fenge(self.senddata_s)
#self.le_senddata.setText(self.senddata.hex())
self.le_recdata.append('\n' + '[' + ct_str+ ']' + ' ' + self.senddata_str_fg + '\n')
#print(self.senddata)
time.sleep(0.1)
self.read_data_size()
except Exception as e:
QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok)
def read_data_alway(self, way):
print('開始接受數(shù)據(jù):')
while True:
try:
if self.ser.inWaiting:
if(way == 0 ):
for i in range(self.ser.inWaiting):
print('接收ascII數(shù)據(jù):'+str(self.read_data_size(1)))
data1 = self.read_data_size(1).hex()
data2 = int(data1, 16)
print('接收到16進制數(shù)據(jù):'+data1+'接收到10進制數(shù)據(jù):'+str(data2))
if(way == 1 ):
data = self.ser.read_all()
except Exception as e:
print('異常:', e)
def str_fenge(self,A):
'''
對字符串進行按長度分割,并在中間加入其他字符,如空格、短橫等
'''
b = re.findall(r'.{2}',A)
c = ' '.join(b)
#print(c)
return c
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Serialwindow()
sys.exit(app.exec_())上面的程序經過測試,可以與流量計正常通訊。
到此這篇關于使用python+Pyqt5實現(xiàn)串口調試助手的文章就介紹到這了,更多相關python Pyqt5串口調試助手內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用Python實現(xiàn)在Word中添加或刪除超鏈接
在Word文檔中,超鏈接是一種將文本或圖像連接到其他文檔、網(wǎng)頁或同一文檔中不同部分的功能,本文將為大家介紹一下Python如何實現(xiàn)在Word中添加或刪除超鏈接,需要的可以參考下2025-01-01
Python使用Opencv打開筆記本電腦攝像頭報錯解問題及解決
這篇文章主要介紹了Python使用Opencv打開筆記本電腦攝像頭報錯解問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Pytorch實現(xiàn)常用乘法算子TensorRT的示例代碼
pytorch 用于訓練,TensorRT用于推理是很多AI應用開發(fā)的標配。大家往往更加熟悉 pytorch 的算子,而不太熟悉TensorRT的算子。本文介紹了Pytorch中常用乘法的TensorRT實現(xiàn),感興趣的可以了解一下2022-06-06
Python 裝飾器@,對函數(shù)進行功能擴展操作示例【開閉原則】
這篇文章主要介紹了Python 裝飾器@,對函數(shù)進行功能擴展操作,結合實例形式分析了裝飾器的相關使用技巧,以及開閉原則下的函數(shù)功能擴展,需要的朋友可以參考下2019-10-10

