使用python+Pyqt5實(shí)現(xiàn)串口調(diào)試助手
python可以利用serial模塊來(lái)和串口設(shè)備進(jìn)行485或者232通訊。
當(dāng)然,網(wǎng)上這類(lèi)串口調(diào)試助手的小程序有很多,不過(guò)這些程序要么是要收費(fèi),只能試用30天,要么是不好用。
況且,別人寫(xiě)的程序,你只能使用,無(wú)法取出其中的數(shù)據(jù)來(lái)進(jìn)行處理,所以,如果可以自己寫(xiě)一個(gè)程序,既方便使用,又可以隨時(shí)隨地使用其中的數(shù)據(jù)。
軟件:python3.10
pycharm2021
硬件:window10電腦
串口485設(shè)備(國(guó)產(chǎn)流量計(jì))
串口轉(zhuǎn)usb線(電腦不帶串口,只能轉(zhuǎn)接)
準(zhǔn)備好了后,就可以開(kāi)始寫(xiě)程序了。
串口通訊程序首先要對(duì)串口進(jìn)行設(shè)置,如波特率、數(shù)據(jù)位、停止位、校驗(yàn)位等。可以稱之為初始化:
初始化:
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)
初始化完成后,需要將串口打開(kāi),只有串口成功打開(kāi),才可以進(jìn)行后面的數(shù)據(jù)傳輸。python中的serial模塊,提供serial.isopen來(lái)進(jìn)行檢查。當(dāng)然,此處需要注意的是,在串口serial實(shí)例化的時(shí)候,實(shí)際上已經(jīng)同時(shí)打開(kāi)串口了。所以,如果在初始化程序里建立了實(shí)例化:
self.ser = serial.Serial(port=self.port,baudrate=self.bps,bytesize=8,parity='N',stopbits=1)
那么也可以不用在重復(fù)打開(kāi)串口了。
串口打開(kāi):
def open_serial(self): #打開(kāi)串口 try: self.ser.open() except Exception as e: QMessageBox.warning(self, 'tips!', str(e), QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Ok) print('異常:', e)
串口關(guān)閉:
def close_serial(self): #關(guān)閉串口 try: self.ser.close() except Exception as e: QMessageBox.warning(self,'tips!',str(e),QMessageBox.Ok|QMessageBox.Cancel,QMessageBox.Ok) print('異常:', e)
調(diào)試完成后,最好關(guān)閉串口,有始有終。
在完成上面的初始化和打開(kāi)步驟后,就可以進(jìn)行數(shù)據(jù)的讀、寫(xiě)了,本例中使用了與流量計(jì)進(jìn)行通訊,讀取流量計(jì)實(shí)時(shí)流量。該流量計(jì)讀、寫(xiě)數(shù)據(jù)時(shí)有專(zhuān)門(mén)的格式:
所以,從電腦端發(fā)送指令時(shí),需要按照流量計(jì)的格式發(fā)送,才能得到正確的反饋。485是半雙工傳輸,即同一時(shí)間只能進(jìn)行讀或者寫(xiě),讀、寫(xiě)不能同時(shí)進(jìn)行。
本例中,讀取流量指令格式為:
01 03 00 10 00 02 C5 CE
實(shí)際操作中,我將流量計(jì)設(shè)備地址修改為2,即
02 03 00 10 00 02 C5 CE
發(fā)送數(shù)據(jù):
def send_data(self): ct = datetime.datetime.now() #獲取當(dāng)前系統(tǒng)時(shí)間 ct_str = ct.strftime("%Y-%m-%d %H:%M:%S") #格式化當(dāng)前系統(tǒng)時(shí)間(字符形式) try: self.senddata_s=self.le_senddata.text() self.senddata=bytes.fromhex(self.senddata_s) #字符轉(zhuǎn)成字節(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é)轉(zhuǎn)成16進(jìn)制字符顯示 #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
serial的讀取數(shù)據(jù)時(shí),有幾種方式,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\爬蟲(chóng)程序\爬蟲(chóng)-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('打開(kāi)串口',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('關(guān)閉串口',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('串口號(hào):') 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(['無(wú)','奇校驗(yàn)','偶校驗(yàn)']) self.lbl_parity_set = QLabel(self) self.lbl_parity_set.setGeometry(420, 110, 60, 20) self.lbl_parity_set.setText('校驗(yàn)位:') 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('超時(shí)設(shè)置:') 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('簡(jiǎn)易串口調(diào)試助手-菌塵') # 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, '提示窗口', '未找到串口!請(qǐng)檢查接線和電腦接口。', 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): #打開(kāi)串口 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): #關(guān)閉串口 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é)轉(zhuǎn)成16進(jìn)制字符顯示 #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() #獲取當(dāng)前系統(tǒng)時(shí)間 ct_str = ct.strftime("%Y-%m-%d %H:%M:%S") #格式化當(dāng)前系統(tǒng)時(shí)間(字符形式) try: self.senddata_s=self.le_senddata.text() self.senddata=bytes.fromhex(self.senddata_s) #字符轉(zhuǎn)成字節(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('開(kāi)始接受數(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進(jìn)制數(shù)據(jù):'+data1+'接收到10進(jìn)制數(shù)據(jù):'+str(data2)) if(way == 1 ): data = self.ser.read_all() except Exception as e: print('異常:', e) def str_fenge(self,A): ''' 對(duì)字符串進(jìn)行按長(zhǎng)度分割,并在中間加入其他字符,如空格、短橫等 ''' 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_())
上面的程序經(jīng)過(guò)測(cè)試,可以與流量計(jì)正常通訊。
到此這篇關(guān)于使用python+Pyqt5實(shí)現(xiàn)串口調(diào)試助手的文章就介紹到這了,更多相關(guān)python Pyqt5串口調(diào)試助手內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 如何優(yōu)雅的將數(shù)字轉(zhuǎn)化為時(shí)間格式的方法
這篇文章主要介紹了Python 如何優(yōu)雅的將數(shù)字轉(zhuǎn)化為時(shí)間格式的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Python常見(jiàn)庫(kù)matplotlib學(xué)習(xí)筆記之多個(gè)子圖繪圖
Matplotlib是Python提供的一個(gè)繪圖庫(kù),通過(guò)該庫(kù)我們可以很容易的繪制出折線圖、直方圖、散點(diǎn)圖、餅圖等豐富的統(tǒng)計(jì)圖,下面這篇文章主要給大家介紹了關(guān)于Python常見(jiàn)庫(kù)matplotlib學(xué)習(xí)筆記之多個(gè)子圖繪圖的相關(guān)資料,需要的朋友可以參考下2023-05-05python實(shí)現(xiàn)BackPropagation算法
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)BackPropagation算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12matplotlib共享坐標(biāo)軸的實(shí)現(xiàn)(X或Y坐標(biāo)軸)
在作圖的過(guò)程中,我們經(jīng)常會(huì)遇到子圖共用坐標(biāo)軸的情況,或是共用橫軸標(biāo)軸,也可能是縱坐標(biāo)軸。本文就介紹了matplotlib共享坐標(biāo)軸,感興趣的可以了解一下2021-05-05Python實(shí)現(xiàn)導(dǎo)出數(shù)據(jù)生成excel報(bào)表的方法示例
這篇文章主要介紹了Python實(shí)現(xiàn)導(dǎo)出數(shù)據(jù)生成excel報(bào)表的方法,結(jié)合完整實(shí)例形式分析了Python連接、查詢mysql數(shù)據(jù)庫(kù)并導(dǎo)出Excel報(bào)表的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-07-07