实现功能:
- 实时显示近3分钟温度随时间的变化曲线
- 实时显示当前温度、温度均值、温度波动
- 根据温度数据实时调整纵坐标轴范围
使用的工具:
- 硬件使用树莓派4B,烧录的是Raspberry Pi OS系统
- 使用Qt Creator软件中UI Designer工具设计界面
- 使用python语言编写逻辑,主要使用python中的pyqt5包以及其中的pyqtchart模块
程序原理:
- 下位机每0.1秒采集1次温度并实时上传
- 上位机创建0.1秒周期的定时器,定时检查收到的数据并处理,添加到显示序列后更新曲线
- 同时进行3分钟温度均值与波动的计算并显示。
下载QT creator,使用里面的UI designer工具创建界面,如下图:
下位机数据格式,ADC值加回车换行
使用pyqt自带工具将.ui文件转换为.py文件,转化后的py文件如下:
# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'widget.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_TemperatureDispaly(object):def setupUi(self, TemperatureDispaly):TemperatureDispaly.setObjectName("TemperatureDispaly")TemperatureDispaly.resize(1024, 600)self.gridLayout = QtWidgets.QGridLayout(TemperatureDispaly)self.gridLayout.setObjectName("gridLayout")self.verticalLayout_2 = QtWidgets.QVBoxLayout()self.verticalLayout_2.setObjectName("verticalLayout_2")self.horizontalLayout_3 = QtWidgets.QHBoxLayout()self.horizontalLayout_3.setObjectName("horizontalLayout_3")self.pushButton = QtWidgets.QPushButton(TemperatureDispaly)font = QtGui.QFont()font.setPointSize(41)self.pushButton.setFont(font)self.pushButton.setObjectName("pushButton")self.horizontalLayout_3.addWidget(self.pushButton)self.TEMP = QtWidgets.QLineEdit(TemperatureDispaly)font = QtGui.QFont()font.setPointSize(44)font.setBold(False)self.TEMP.setFont(font)self.TEMP.setObjectName("TEMP")self.horizontalLayout_3.addWidget(self.TEMP)spacerItem = QtWidgets.QSpacerItem(200, 100, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_3.addItem(spacerItem)self.verticalLayout = QtWidgets.QVBoxLayout()self.verticalLayout.setObjectName("verticalLayout")self.horizontalLayout = QtWidgets.QHBoxLayout()self.horizontalLayout.setObjectName("horizontalLayout")self.Average_label = QtWidgets.QLabel(TemperatureDispaly)font = QtGui.QFont()font.setPointSize(16)font.setBold(False)font.setKerning(True)self.Average_label.setFont(font)self.Average_label.setAutoFillBackground(False)self.Average_label.setObjectName("Average_label")self.horizontalLayout.addWidget(self.Average_label)self.Average_lineEdit = QtWidgets.QLineEdit(TemperatureDispaly)font = QtGui.QFont()font.setPointSize(17)self.Average_lineEdit.setFont(font)self.Average_lineEdit.setObjectName("Average_lineEdit")self.horizontalLayout.addWidget(self.Average_lineEdit)spacerItem1 = QtWidgets.QSpacerItem(150, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout.addItem(spacerItem1)self.verticalLayout.addLayout(self.horizontalLayout)self.horizontalLayout_2 = QtWidgets.QHBoxLayout()self.horizontalLayout_2.setObjectName("horizontalLayout_2")self.Fluctuate_label = QtWidgets.QLabel(TemperatureDispaly)font = QtGui.QFont()font.setPointSize(16)self.Fluctuate_label.setFont(font)self.Fluctuate_label.setObjectName("Fluctuate_label")self.horizontalLayout_2.addWidget(self.Fluctuate_label)self.Fluctuate_lineEdit = QtWidgets.QLineEdit(TemperatureDispaly)font = QtGui.QFont()font.setPointSize(17)self.Fluctuate_lineEdit.setFont(font)self.Fluctuate_lineEdit.setObjectName("Fluctuate_lineEdit")self.horizontalLayout_2.addWidget(self.Fluctuate_lineEdit)spacerItem2 = QtWidgets.QSpacerItem(150, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)self.horizontalLayout_2.addItem(spacerItem2)self.verticalLayout.addLayout(self.horizontalLayout_2)self.horizontalLayout_3.addLayout(self.verticalLayout)self.verticalLayout_2.addLayout(self.horizontalLayout_3)self.frame = QtWidgets.QFrame(TemperatureDispaly)self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)self.frame.setFrameShadow(QtWidgets.QFrame.Raised)self.frame.setObjectName("frame")self.gridLayout_2 = QtWidgets.QGridLayout(self.frame)self.gridLayout_2.setObjectName("gridLayout_2")self.QgraphicsView = QChartView(self.frame)self.QgraphicsView.setObjectName("QgraphicsView")self.gridLayout_2.addWidget(self.QgraphicsView, 0, 0, 1, 1)self.verticalLayout_2.addWidget(self.frame)self.gridLayout.addLayout(self.verticalLayout_2, 0, 0, 1, 1)self.retranslateUi(TemperatureDispaly)self.pushButton.clicked.connect(TemperatureDispaly.close) # type: ignoreQtCore.QMetaObject.connectSlotsByName(TemperatureDispaly)def retranslateUi(self, TemperatureDispaly):_translate = QtCore.QCoreApplication.translateTemperatureDispaly.setWindowTitle(_translate("TemperatureDispaly", "IKKEM-温度曲线"))self.pushButton.setText(_translate("TemperatureDispaly", "退出"))self.Average_label.setText(_translate("TemperatureDispaly", "3分钟温度均值"))self.Fluctuate_label.setText(_translate("TemperatureDispaly", "3分钟温度波动"))
from PyQt5.QtChart import QChartView
编写逻辑代码如下:
#温度可视化展示import sys, math, random
import numpy as np
import serial
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtChart import QChart, QLineSeries, QValueAxis,QChartView
from PyQt5 import QtGui, QtWidgets
from ui_widget import Ui_TemperatureDispaly
from PyQt5.QtGui import QPainter,QPen
from PyQt5.QtCore import Qt
from PyQt5.QtCore import QTimerclass QmyWidget(QWidget):def __init__(self, parent=None):super().__init__(parent) #调用父类构造函数,创建QWidget窗口self.ui = Ui_TemperatureDispaly() # 创建UI对象self.ui.setupUi(self) # 构造UI界面self.timer = QTimer() # 初始化定时器self.timer.timeout.connect(self.my_timer_cb)#将定时器连接到回调函数self.chart = None # 图表self.axisY = QValueAxis()self.counter=0self.createChart()#调用创建图标方法self.timer.start(100)#定时器开始,400ms回调一次self.ser = serial.Serial("/dev/ttyAMA0", 9600) # 打开串口,波特率9600def createChart(self):self.chart = QChart()self.chart.legend().hide()self.ui.QgraphicsView.setChart(self.chart)self.ui.QgraphicsView.setRenderHint(QPainter.Antialiasing)self.ui.QgraphicsView.setRubberBand(QChartView.RectangleRubberBand)font1 = QtGui.QFont() # 创建字体对象font,用QFont类font1.setPointSize(50) # 设置字体大小font1.setBold(True) # 设置为粗体self.ui.TEMP.setFont(font1)self.ui.TEMP.setStyleSheet("color:blue")self.ui.TEMP.setAlignment(Qt.AlignCenter)self.ui.Average_lineEdit.setAlignment(Qt.AlignCenter)self.ui.Fluctuate_lineEdit.setAlignment(Qt.AlignCenter)#居中对其op = QtWidgets.QGraphicsOpacityEffect()# 设置透明度的值,0.0到1.0,最小值0是透明,1是不透明op.setOpacity(0)self.ui.pushButton.setGraphicsEffect(op)#设置退出按钮透明series = QLineSeries()series.setUseOpenGL(True)self.chart.addSeries(series)pen = QPen(Qt.red)pen.setStyle(Qt.SolidLine) # SolidLine, DashLine, DotLine, DashDotLinepen.setWidth(2)series.setPen(pen) # 序列的线条设置font2 = QtGui.QFont() # 创建字体对象font,用QFont类font2.setPointSize(11) # 设置字体大小font2.setBold(True) # 设置为粗体axisX = QValueAxis()axisX.setRange(0, 3)axisX.setLabelFormat("%.1f") # 标签格式axisX.setLabelsFont(font2)axisX.setTickCount(7) # 主分隔个数axisX.setMinorTickCount(1)axisX.setGridLineVisible(True)axisX.setMinorGridLineVisible(True)self.axisY.setLabelFormat("%.3f") # 标签格式self.axisY.setLabelsFont(font2)self.axisY.setTickCount(8)self.axisY.setGridLineVisible(True)self.axisY.setMinorGridLineVisible(False)self.chart.addAxis(axisX, Qt.AlignBottom) # 坐标轴添加到图表,并指定方向self.chart.addAxis(self.axisY, Qt.AlignLeft)series.attachAxis(axisX) # 序列 series坐标轴series.attachAxis(self.axisY)def my_timer_cb(self, temp_average=None):chart = self.ui.QgraphicsView.chart() # 获取chartView中的QChart对象series = chart.series()[0] # 获取第1个序列,QLineSeriesreceived_data = self.ser.read() # 读取串口端口data_left = self.ser.inWaiting() # 检查串口数据received_data += self.ser.read(data_left)#将串口数据添加到变量里if len(received_data)>9:#这里处理两个数据连接在一起的情况re_data = int(received_data[-9:-1:1])else:re_data = int(received_data)#标定后修改下一句代码re_data = round((re_data * 4000 / 8388607-1000)/3.85, 4)#将AD值处理成温度self.ui.TEMP.setText('%.4f' % re_data+"℃") #改变当前温度窗口数据if self.counter < 3:series.append(self.counter, re_data)self.counter+=3/1800else:points = series.pointsVector()for i in range(1800):points[i].setY(points[i + 1].y())points[-1].setY(re_data)series.replace(points)num=[]p = series.pointsVector()y_min = min(p, key=lambda point: point.y()).y()y_max = max(p, key=lambda point: point.y()).y()for i in range(len(p)):num.append(p[i].y())temp_average = np.average(num)self.ui.Average_lineEdit.setText('%.4f' % temp_average)self.ui.Fluctuate_lineEdit.setText('%.4f' % (y_max-y_min))self.axisY.setRange(y_min, y_max)if __name__ == "__main__": #用于当前窗体测试app = QApplication(sys.argv) #创建GUI应用程序form=QmyWidget() #创建窗体form.showFullScreen() #全屏展示form.show()sys.exit(app.exec_())
实现功能:
本文链接:https://my.lmcjl.com/post/19320.html
展开阅读全文
4 评论