基于PyQt5實(shí)現(xiàn)一個(gè)串口接數(shù)據(jù)波形顯示工具
工具簡(jiǎn)述
基于PyQt5開(kāi)發(fā)UI界面使用QtDesigner設(shè)計(jì),需要使用到serial模塊(串口庫(kù))和pyqtgraph(圖形庫(kù))。上位機(jī)通過(guò)串口接收來(lái)自MCU發(fā)送數(shù)據(jù),解析出每一個(gè)數(shù)據(jù)項(xiàng)并以波形圖的方式顯示。本例程下位機(jī)是Raspberry Pi Pico發(fā)送HMC5883L地磁模塊數(shù)據(jù),數(shù)據(jù)項(xiàng)有x,y,z,h等,數(shù)據(jù)格式’$$:x,y,z,h’。
主程序代碼
import sys
import numpy as np
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import serial
import serial.tools.list_ports
from ui_main import Ui_MainWindow
import pyqtgraph as pg
class AppMainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(AppMainWindow, self).__init__(parent)
self.setupUi(self)
self.setWindowTitle("串口數(shù)據(jù)波形顯示工具")
self.PosX = 0
self.dataIndex = 0 # 數(shù)據(jù)列表當(dāng)前索引
self.dataMaxLength = 10000 # 數(shù)據(jù)列表最大長(zhǎng)度
self.dataheader = b'$$:' # 數(shù)據(jù)幀開(kāi)頭
self.dataX = np.zeros(self.dataMaxLength, dtype=float)
self.dataY = np.zeros(self.dataMaxLength, dtype=float)
self.dataZ = np.zeros(self.dataMaxLength, dtype=float)
self.dataH = np.zeros(self.dataMaxLength, dtype=float)
self.mSerial = serial.Serial()
self.ScanComPort()
self.SelectComPort()
self.btnScanPort.clicked.connect(self.ScanComPort)
self.btnOpenPort.clicked.connect(self.OpenComPort)
self.btnClosePort.clicked.connect(self.CloseComPort)
self.cmbComPort.currentIndexChanged.connect(self.SelectComPort)
self.mTimer = QTimer()
self.mTimer.timeout.connect(self.ReceiverPortData)
self.plotM.setAntialiasing(True)
# self.plotM.setBackground()
self.canvasX = self.plotM.plot(self.dataX, pen=pg.mkPen(color='r', width=1))
self.canvasY = self.plotM.plot(self.dataY, pen=pg.mkPen(color='g', width=1))
self.canvasZ = self.plotM.plot(self.dataZ, pen=pg.mkPen(color='b', width=1))
self.canvasH = self.plotM.plot(self.dataH, pen=pg.mkPen(color='y', width=1))
def ScanComPort(self):
self.cmbComPort.clear()
self.portDict = {}
portlist = list(serial.tools.list_ports.comports())
for port in portlist:
self.portDict["%s" % port[0]] = "%s" % port[1]
self.cmbComPort.addItem(port[0])
if len(self.portDict) == 0:
QMessageBox.critical(self, "警告", "未找到串口設(shè)備!", QMessageBox.Cancel, QMessageBox.Cancel)
pass
def SelectComPort(self):
if len(self.portDict) > 0 :
self.labComPortName.setText(self.portDict[self.cmbComPort.currentText()])
else:
self.labComPortName.setText("未檢測(cè)到串口設(shè)備!")
pass
def OpenComPort(self):
self.mSerial.port = self.cmbComPort.currentText()
self.mSerial.baudrate = int(self.cmbBaudrate.currentText())
if self.mSerial.isOpen():
QMessageBox.warning(self, "警告", "串口已打開(kāi)", QMessageBox.Cancel, QMessageBox.Cancel)
else:
try:
self.btnOpenPort.setEnabled(False)
self.mSerial.open()
self.mSerial.flushInput()
self.mSerial.flushOutput()
self.mTimer.start(1)
except:
QMessageBox.critical(self, "警告", "串口打開(kāi)失??!", QMessageBox.Cancel, QMessageBox.Cancel)
self.btnOpenPort.setEnabled(True)
print(self.mSerial)
pass
def CloseComPort(self):
self.mTimer.stop()
if self.mSerial.isOpen():
self.btnOpenPort.setEnabled(True)
self.mSerial.flushInput()
self.mSerial.flushOutput()
self.mSerial.close()
pass
def ReceiverPortData(self):
'''
接收串口數(shù)據(jù),并解析出每一個(gè)數(shù)據(jù)項(xiàng)更新到波形圖
數(shù)據(jù)幀格式'$$:95.68,195.04,-184.0\r\n'
每個(gè)數(shù)據(jù)幀以b'$$:'開(kāi)頭,每個(gè)數(shù)據(jù)項(xiàng)以','分割
'''
try:
n = self.mSerial.inWaiting()
except:
self.CloseComPort()
if n > 0:
# 端口緩存內(nèi)有數(shù)據(jù)
try:
self.recvdata = self.mSerial.readline(1024) # 讀取一行數(shù)據(jù)最大長(zhǎng)度1024字節(jié)
if self.recvdata.decode('UTF-8').startswith(self.dataheader.decode('UTF-8')):
rawdata = self.recvdata[len(self.dataheader) : len(self.recvdata) - 2]
data = rawdata.split(b',')
# print(rawdata)
if self.dataIndex < self.dataMaxLength:
# 接收到的數(shù)據(jù)長(zhǎng)度小于最大數(shù)據(jù)緩存長(zhǎng)度,直接按索引賦值,索引自增1
# print(rawdata, rawdata[0], rawdata[1], rawdata[2], self.dataX[self.dataIndex], self.dataY[self.dataIndex], self.dataZ[self.dataIndex])
self.dataX[self.dataIndex] = float(data[0])
self.dataY[self.dataIndex] = float(data[1])
self.dataZ[self.dataIndex] = float(data[2])
self.dataH[self.dataIndex] = float(data[3])
self.dataIndex = self.dataIndex + 1
else:
# 寄收到的數(shù)據(jù)長(zhǎng)度大于或等于最大數(shù)據(jù)緩存長(zhǎng)度,丟棄最前一個(gè)數(shù)據(jù)新數(shù)據(jù)添加到數(shù)據(jù)列尾
self.dataX[:-1] = self.dataX[1:]
self.dataY[:-1] = self.dataY[1:]
self.dataZ[:-1] = self.dataZ[1:]
self.dataH[:-1] = self.dataH[1:]
self.dataX[self.dataIndex - 1] = float(data[0])
self.dataY[self.dataIndex - 1] = float(data[1])
self.dataZ[self.dataIndex - 1] = float(data[2])
self.dataH[self.dataIndex - 1] = float(data[3])
# 更新波形數(shù)據(jù)
self.canvasX.setData(self.dataX)
self.canvasY.setData(self.dataY)
self.canvasZ.setData(self.dataZ)
self.canvasH.setData(self.dataH)
# self.canvasX.setPos(self.PosX, 0)
# self.canvasY.setPos(self.PosX, 0)
# self.canvasZ.setPos(self.PosX, 0)
except:
pass
pass
def SendPortData(self):
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
win = AppMainWindow()
win.show()
sys.exit(app.exec_())
Qt Designer設(shè)計(jì)UI界面

程序運(yùn)行效果

到此這篇關(guān)于基于PyQt5實(shí)現(xiàn)一個(gè)串口接數(shù)據(jù)波形顯示工具的文章就介紹到這了,更多相關(guān)PyQt5數(shù)據(jù)波形顯示工具內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python常見(jiàn)格式化字符串方法小結(jié)【百分號(hào)與format方法】
這篇文章主要介紹了Python常見(jiàn)格式化字符串方法,結(jié)合實(shí)例形式分析了百分號(hào)方法和format函數(shù)進(jìn)行字符串格式化的具體使用技巧,需要的朋友可以參考下2016-09-09
python制作爬蟲(chóng)并將抓取結(jié)果保存到excel中
本文給大家記錄的是使用Python制作爬蟲(chóng)爬取拉勾網(wǎng)信息并將結(jié)果保存到Excel中的實(shí)現(xiàn)思路及方法,并附上最終源碼,有需要的小伙伴可以參考下2016-04-04
教你如何用python開(kāi)發(fā)一款數(shù)字推盤(pán)小游戲
這篇文章主要介紹了教你如何用python開(kāi)發(fā)一款數(shù)字推盤(pán)小游戲,文中有非常詳細(xì)的代碼示例,喜對(duì)歡玩小游戲的或者正在學(xué)習(xí)python小游戲開(kāi)發(fā)的小伙伴們有很好的幫助,需要的朋友可以參考下2021-04-04
pytest內(nèi)置fixture使用臨時(shí)目錄流程詳解
fixture是在測(cè)試函數(shù)運(yùn)行前后,由pytest執(zhí)行的外殼函數(shù)。fixture中的代碼可以定制,滿足多變的測(cè)試需求,包括定義傳入測(cè)試中的數(shù)據(jù)集、配置測(cè)試前系統(tǒng)的初始狀態(tài)、為批量測(cè)試提供數(shù)據(jù)源等等。fixture是pytest的精髓所在2022-12-12
啟動(dòng)targetcli時(shí)遇到錯(cuò)誤解決辦法
這篇文章主要介紹了啟動(dòng)targetcli時(shí)遇到錯(cuò)誤解決辦法的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家遇到這樣的錯(cuò)誤解決,需要的朋友可以參考下2017-10-10
關(guān)于Pyinstaller閃退的補(bǔ)救措施
這篇文章主要介紹了關(guān)于Pyinstaller閃退的補(bǔ)救措施,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
Python使用Keras庫(kù)中的LSTM模型生成新文本內(nèi)容教程
Python語(yǔ)言使用金庸小說(shuō)文本庫(kù),對(duì)文本進(jìn)行預(yù)處理,然后使用Keras庫(kù)中的LSTM模型創(chuàng)建和訓(xùn)練了模型,根據(jù)這個(gè)模型,我們可以生成新的文本,并探索小說(shuō)的不同應(yīng)用2024-01-01
pycharm中出現(xiàn)no module named xlwt的原因及解決
這篇文章主要介紹了pycharm中出現(xiàn)no module named xlwt的原因及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2023-05-05
python 字典(dict)遍歷的四種方法性能測(cè)試報(bào)告
本文主要是針對(duì)Python的字典dict遍歷的4種方法進(jìn)行了性能測(cè)試,以便分析得出效率最高的一種方法2014-06-06

