欢迎光临
我们一直在努力

Python PyQt上位机项目应用:温控系统监控实例

用Python+PyQt打造工业级温控监控上位机:从零到实战

在工厂车间的一角,一台老式温控箱正默默运行。它的前面板只有几个闪烁的数码管和按钮,操作员每隔一小时就要手动记录一次温度数据——这种场景你是否似曾相识?而在隔壁的新产线,同样的设备却已接入了一套可视化监控系统:实时曲线、越限报警、历史回放、远程配置……所有信息尽在眼前。

这背后的关键,就是

上位机软件

今天,我们就以一个真实的温控系统监控项目为蓝本,手把手带你用

Python + PyQt

搭建一套功能完整、稳定可靠的工业监控界面。不讲空话,只聊实战。


为什么选择PyQt做上位机?

很多人第一反应是:“不是有组态王、WinCC这些专业工具吗?”确实,大型系统离不开它们。但对中小型项目、教学实验或快速原型开发来说,这些商业软件显得“杀鸡用牛刀”了。

而 Python 配合 PyQt,则提供了另一种可能:

  • 开发效率高:语法简洁,代码量少
  • 跨平台运行:Windows/Linux/macOS 通吃
  • 成本几乎为零:开源免费,无需授权
  • 社区资源丰富:大量第三方库支持
  • 易于集成AI与数据分析模块

更重要的是,它足够“轻”,却又足够“强”。

我们这次要做的,就是一个典型的温控监控系统:PC通过串口读取下位机(比如STM32)上传的温度数据,实时显示并绘图,支持报警、参数设置和数据存储。整个过程完全由你自己掌控,没有黑盒。


界面搭建:用PyQt画出第一个窗口

先别急着接硬件,咱们先把脸面做好。

PyQt 是 Qt 框架的 Python 封装,其中 PyQt5 目前仍是主流选择。它基于事件驱动模型,核心是一个

QApplication

实例,负责管理整个程序的生命周环。

下面这段代码,创建了一个最基础的监控窗口:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton

class TemperatureMonitor(QWidget):
def __init__(self):
super().__init__()
self.init_ui()

def init_ui(self):
layout = QVBoxLayout()

# 当前温度显示
self.temp_label = QLabel("当前温度:–℃")
self.temp_label.setStyleSheet("font-size: 18px; color: #333;")

# 报警提示按钮(初始隐藏)
self.alert_button = QPushButton("⚠️ 超温报警!")
self.alert_button.setStyleSheet("background-color: red; color: white; font-weight: bold;")
self.alert_button.hide() # 默认不显示

layout.addWidget(self.temp_label)
layout.addWidget(self.alert_button)

self.setLayout(layout)
self.setWindowTitle("温控系统监控 – 上位机")
self.resize(400, 200)
self.show()

if __name__ == '__main__':
app = QApplication(sys.argv)
window = TemperatureMonitor()
sys.exit(app.exec_())

就这么几十行,你就有了一个带标签和按钮的窗口。而且用了

QVBoxLayout

布局管理器,哪怕你拉伸窗口大小,控件也会自动对齐排列。

但这只是个“壳”。真正让它活起来的,是接下来的

串口通信


串口通信:让上位机“听见”下位机的声音

工业现场最常见的通信方式是什么?不是Wi-Fi,也不是蓝牙,而是——

串口

RS-232、TTL、Modbus RTU……这些名词听起来古老,但在抗干扰性、稳定性、成本方面依然无可替代。我们的任务,就是让 Python 听懂这串“嘀嘀嘀”的数据流。

这里要用到一个神器:

pyserial

安装很简单:

pip install pyserial

然后写一个独立工作的“监听工人”——我们把它放进子线程里,避免卡住主界面:

import serial
import threading
from PyQt5.QtCore import QObject, pyqtSignal

class SerialWorker(QObject):
data_received = pyqtSignal(float) # 自定义信号,用于传温度值

def __init__(self, port='COM3', baudrate=9600):
super().__init__()
try:
self.ser = serial.Serial(port, baudrate, timeout=1)
self.running = True
except Exception as e:
print(f"无法打开串口 {port}: {e}")
self.running = False

def start_reading(self):
while self.running and self.ser.is_open:
if self.ser.in_waiting > 0:
line = self.ser.readline().decode('utf-8').strip()
try:
temp = float(line)
self.data_received.emit(temp) # 发射信号给主线程
except ValueError:
continue # 忽略非法数据

def send_command(self, cmd):
"""向下位机发送指令"""
if self.ser.is_open:
self.ser.write(f"{cmd}\\r\\n".encode())

def stop(self):
self.running = False
if self.ser.is_open:
self.ser.close()

注意几个关键点:

  • 多线程安全

    :串口读取不能放在主线程!否则一旦阻塞,整个GUI就会卡死。

  • 信号传递

    :使用

    pyqtSignal

    在线程间通信,这是 Qt 推荐的安全做法。

  • 异常处理

    :串口可能被占用、断开或收到乱码,必须加

    try-except

    保护。

  • 协议容错

    :实际项目中建议增加帧头识别、CRC校验等机制。

启动时,你可以这样用:

worker = SerialWorker('COM3', 115200)
thread = threading.Thread(target=worker.start_reading, daemon=True)
thread.start()

设成

daemon=True

表示主线程退出时自动结束子线程,防止程序关不掉。


实时绘图:让数据“动”起来

光看数字不过瘾,我们要看到趋势变化。这就轮到

pyqtgraph

登场了。

相比 Matplotlib,

pyqtgraph

是专为实时数据设计的绘图库,基于 OpenGL 加速,轻松实现每秒数千点的刷新率,CPU 占用还低。

安装命令:

pip install pyqtgraph

来,我们封装一个滚动波形图组件:

import pyqtgraph as pg
from PyQt5.QtCore import QTimer

class RealTimePlot:
def __init__(self, plot_widget: pg.PlotWidget):
self.plot_widget = plot_widget
self.plot_widget.setLabel('left', '温度 (°C)')
self.plot_widget.setLabel('bottom', '时间 (s)')
self.plot_widget.setTitle('实时温度曲线')
self.plot_widget.setYRange(0, 100) # 初始范围
self.plot_widget.showGrid(x=True, y=True)

self.curve = self.plot_widget.plot(pen='g') # 绿色曲线

self.buffer_size = 100
self.x_data = list(range(self.buffer_size))
self.y_data = [0] * self.buffer_size

self.timer = QTimer()
self.timer.timeout.connect(self.update_plot)

def update_data(self, new_temp):
"""接收新数据"""
self.y_data = self.y_data[1:] + [new_temp]
# 动态调整Y轴范围
min_y = max(0, min(self.y_data) – 5)
max_y = max(self.y_data) + 5
self.plot_widget.setYRange(min_y, max_y)

def update_plot(self):
"""定时刷新图像"""
self.curve.setData(self.x_data, self.y_data)

def start(self):
self.timer.start(100) # 每100ms刷新一次,即10FPS

使用也很简单,在UI中嵌入一个

PlotWidget

from pyqtgraph import PlotWidget

# 在 init_ui 中添加
plot_widget = PlotWidget()
layout.addWidget(plot_widget)

self.plotter = RealTimePlot(plot_widget)
self.plotter.start()

SerialWorker

收到温度后,调用

self.plotter.update_data(temp)

,曲线就会自动向前滚动,像心电图一样流畅。


完整交互逻辑:把所有模块串起来

现在四个核心部件都有了:

  • GUI界面(PyQt)
  • 数据接收(pyserial + 多线程)
  • 数据展示(pyqtgraph)
  • 用户控制(按钮、输入框)
  • 怎么让它们协同工作?

    答案还是那个法宝:

    信号与槽机制

    举个例子,当下位机传来温度数据时:

    # 连接信号
    worker.data_received.connect(self.on_temperature_update)

    def on_temperature_update(self, temp):
    # 更新LCD显示
    self.temp_label.setText(f"当前温度:{temp:.1f}℃")

    # 检查是否超限
    if temp > 80 or temp < 30:
    self.alert_button.show()
    else:
    self.alert_button.hide()

    # 更新图表
    self.plotter.update_data(temp)

    # 存入日志文件
    self.log_data(temp)

    用户点击“设置目标温度”按钮时:

    def set_target_temp(self):
    target = self.target_input.text() # 来自 QLineEdit
    try:
    value = float(target)
    worker.send_command(f"SET_TEMP:{value}")
    except ValueError:
    QMessageBox.warning(self, "输入错误", "请输入有效数值")

    整个系统就像一台精密的钟表,每个齿轮各司其职,靠“信号”咬合转动。


    工程级细节:那些教科书不会告诉你的坑

    你以为跑起来就万事大吉?真正的挑战才刚开始。

    ⚠️ 坑点1:程序退出后串口打不开?

    原因:没正确关闭资源。一定要在退出前调用

    worker.stop()

    并等待线程结束。

    解决方案:

    def closeEvent(self, event):
    if hasattr(self, 'worker'):
    self.worker.stop()
    event.accept()

    ⚠️ 坑点2:数据显示跳变、乱码?

    原因:串口收到不完整帧或噪声干扰。

    秘籍:

    – 添加帧头检测,如以

    $TEMP:

    开头

    – 使用环形缓冲区重组数据包

    – 对关键指令启用 CRC 校验

    ⚠️ 坑点3:长时间运行内存暴涨?

    原因:列表不断追加,未限制长度。

    对策:

    – 使用固定长度的 deque 缓冲区

    – 或定期清理旧数据

    from collections import deque
    self.y_data = deque([0]*100, maxlen=100)

    ✅ 秘籍加分项:

    • QSettings

      保存上次使用的串口号和波特率,用户体验直接拉满;

    • 日志文件按日期命名,格式为

      temp_log_20250405.csv

      ,便于后期分析;

    • 加一个“静音报警”按钮,别让蜂鸣器吵翻天。

    架构再思考:我们到底在做什么?

    回头看这个系统的结构:

    [下位机]
    ↓ (UART)
    [SerialWorker]
    ↓ (signal)
    [Central Logic]
    ↙ ↘
    [UI Update] [Data Logging]
    ↘ ↙
    [RealTimePlot]

    我们其实在构建一个微型的

    数据中枢

    :采集 → 解析 → 分发 → 展示 → 存储。

    这正是现代工业系统的基本范式。只不过今天我们用几百行 Python 就实现了。

    未来你能做什么?

    • 接数据库(SQLite/MySQL),支持海量查询
    • 加网络服务,用 Flask 或 WebSocket 实现远程监控
    • 引入机器学习模型,预测温度趋势提前预警
    • 打包成exe,发给客户一键安装

    一切皆有可能。


    如果你也在做类似的自动化项目,或者正被老旧HMI折磨得夜不能寐,不妨试试这条路。

    不需要精通C++,也不必购买昂贵授权,只要你会写Python,就能亲手打造属于自己的工业级监控面板。

    而这,或许就是智能制造最迷人的地方:

    技术从未如此平易近人,却又蕴藏着改变现实的力量。

    你在哪一刻,感受到了这种力量?欢迎留言分享。

    赞(0)
    未经允许不得转载:171主机测评 » Python PyQt上位机项目应用:温控系统监控实例
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址