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) ,曲线就会自动向前滚动,像心电图一样流畅。


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

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

  1. GUI界面(PyQt)
  2. 数据接收(pyserial + 多线程)
  3. 数据展示(pyqtgraph)
  4. 用户控制(按钮、输入框)

怎么让它们协同工作?

答案还是那个法宝: 信号与槽机制

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

# 连接信号 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,就能亲手打造属于自己的工业级监控面板。

而这,或许就是智能制造最迷人的地方:
技术从未如此平易近人,却又蕴藏着改变现实的力量。

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

Read more

从下载到运行:MySQL 详细安装配置完整教程

从下载到运行:MySQL 详细安装配置完整教程

从下载到运行:MySQL 超详细安装配置完整教程 * 从下载到运行:MySQL 详细安装配置完整教程 * 一、MySQL下载步骤 * 二、MySQL安装流程 * 三、MySQL环境配置与验证 * 1. 配置环境变量 * 2. 验证MySQL是否安装成功 * 四、Navicat链接MySQL * 1. 安装Navicat 从下载到运行:MySQL 详细安装配置完整教程 一、MySQL下载步骤 首先访问MySQL官方下载地址,进入MySQL的官方下载页面。 下载完成后,在本地找到下载好的MySQL安装文件,双击文件启动安装程序。 二、MySQL安装流程 双击安装文件后,会进入MySQL安装类型选择界面,界面中提供5种安装模式,各自功能如下: Developer Default(开发者默认):包含MySQL开发所需的全套组件(如数据库服务、客户端工具、SDK等),适合开发人员使用。Server only(仅服务器):仅安装MySQL数据库服务,适合仅需搭建数据库服务器的场景。Client

By Ne0inhk
4nm移动SoC革命:三星高能效NPU架构解析

4nm移动SoC革命:三星高能效NPU架构解析

面向移动端SoC的高硬件效率神经网络处理单元 临近春节,围炉煮茶之余阅读了三星电子发表在固体电子学顶刊IEEE JSSC上的论文 《A Multi-Mode 8k-MAC HW-Utilization-Aware Neural Processing Unit With a Unified Multi-Precision Datapath in 4-nm Flagship Mobile SoC》 ,三星副总裁Inyup Kang博士 为本文的共同作者。三星电子的研究团队提出了一种应用于4nm移动SoC支持多模式的神经网络处理单元(NPU),专为猎户座移动SoC设计,通过统一多精度数据通路支持INT4/8及FP16运算,实现高能效与高面积效率的平衡。 原文链接 关键词 计算利用率、深度神经网络(DNN)、领域专用架构(DSA)、推理加速器、稀疏感知零跳过、统一乘加(MAC) 全文导图及摘要 针对深度卷积、浅层小通道层等端侧AI应用中的低硬件利用率场景,三星团队结合编译器提供的张量信息,通过重构计算流(包含基于特征图稀疏特性的零值跳过、Scatter-Gather等技术),硬件利用

By Ne0inhk
金仓数据库 MongoDB 兼容:多模融合下的架构之道与实战体验

金仓数据库 MongoDB 兼容:多模融合下的架构之道与实战体验

引言:从“平替”到“超越”的技术跨越 在国产化替代(信创)浪潮下,选择数据库不再只是考量“能否使用”,更多关注其“好用与否”,还要看是否能做到“无缝切换”。提到 MongoDB,想必大家都不生疏,作为 NoSQL 领域的佼佼者,凭借自身灵活的数据架构和飞快的读写效率,斩获诸多互联网及物联网项目,不过须要诚实地表明,一旦关乎到企业核心业务,譬如要确保数据完全一致,执行繁杂的关联查询或者实施统一运作管理时,MongoDB 就常常会有些力不从心。 电科金仓(Kingbase)所给出的多模融合数据库方案颇具趣味,该方案并非仅仅创建一层适配层来博取眼球,其实在架构层面上执行了“降维打击”,经由内核级别的 MongoDB 协议适配 并结合自主研发的 OSON 存储引擎,金仓把“关系型数据库稳定的基础”与“NoSQL 灵活的特性”融合起来,现在,让我们一起探究金仓数据库(KingbaseES,

By Ne0inhk
# Flutter三方库适配OpenHarmony【flutter_libphonenumber】——联合插件(Federated Plugin)架构解析

# Flutter三方库适配OpenHarmony【flutter_libphonenumber】——联合插件(Federated Plugin)架构解析

前言 欢迎来到 Flutter三方库适配OpenHarmony 系列文章!本系列围绕 flutter_libphonenumber 这个 电话号码处理库 的鸿蒙平台适配,进行全面深入的技术分享。 欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 上一篇我们从全局视角介绍了 flutter_libphonenumber 的功能定位和鸿蒙适配成果。本篇将深入解析该库采用的 联合插件(Federated Plugin)架构,这是理解整个适配工作的基础。我们将逐层拆解 platform_interface、MethodChannel、各平台实现包的协作关系,并详细分析鸿蒙平台是如何 无缝接入 这套架构的。 理解联合插件架构是进行任何 Flutter 三方库鸿蒙适配的 第一步,掌握了这套模式,你就能举一反三地适配其他库。 一、什么是联合插件(Federated Plugin) 1.1 传统插件的局限性 在 Flutter 早期,

By Ne0inhk