news 2026/6/10 8:21:57

基于qserialport的温度监控系统:完整示例实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于qserialport的温度监控系统:完整示例实现

用QSerialPort打造一个真正能跑的温度监控系统:从串口读数到动态图表全实战

你有没有过这样的经历?手头有个DS18B20或DHT22,接在Arduino上,数据明明已经在串口助手里“啪啪”地跳着出来,但就是不知道怎么把它变成一个像模像样、能实时画曲线、带报警、还能记住历史的桌面程序?

别再用记事本复制粘贴温度值了。今天我们就来干一票大的——用Qt + QSerialPort,从零开始构建一个工业级可用的温度监控系统。不是玩具Demo,是那种你可以拿去给老板演示、写进简历项目的完整工程。


别再被“串口卡顿”折磨了:为什么你的上位机总是不流畅?

先说个真相:很多人做的“温度监控”,其实就是一个串口助手加个LCD控件,点一下刷新一次。界面卡顿、数据丢失、偶尔崩溃……根本没法连续运行超过十分钟。

问题出在哪?同步阻塞读取 + 主线程搞通信

而我们今天的方案,核心就一句话:

让QSerialPort在后台默默监听,数据来了自动通知UI,GUI永远丝滑如初。

这背后靠的就是 Qt 的两大法宝:信号与槽(Signals & Slots)事件驱动机制(Event-Driven Architecture)


QSerialPort 不是“读写文件”,它是你和硬件之间的“对讲机”

别看QSerialPort继承自QIODevice,就能用read()write(),但它的工作方式和读文件完全不同。

想象一下,你在工地现场,工人(MCU)每隔几秒通过 walkie-talkie 报告一次温度:“报告!当前温度25.3度!”
你不需要一直举着对讲机听——那样太累。你应该做的是:把对讲机调成响铃模式,等它“嘀”一声,再拿起来说:“哦,知道了,更新面板。”

这就是readyRead()信号的本质。

connect(serial, &QSerialPort::readyRead, this, &TemperatureMonitor::readSerialData);

只要串口缓冲区有新数据,这个信号就会触发,你的readSerialData()函数就会被执行——完全异步,不占用主线程,GUI不卡顿


硬核配置:如何打开一个“稳定不死”的串口?

很多初学者一上来就serial->open(QIODevice::ReadOnly),结果弹出“Permission error”或者“Resource busy”。为什么?

因为你没做好端口配置。下面这段代码,是你必须掌握的“串口初始化模板”:

void TemperatureMonitor::openSerialPort() { serial->setPortName(ui->portComboBox->currentText()); serial->setBaudRate(115200); // 高速传输,减少延迟 serial->setDataBits(QSerialPort::Data8); // 8个数据位 serial->setParity(QSerialPort::NoParity); // 无校验 serial->setStopBits(QSerialPort::OneStop); // 1个停止位 serial->setFlowControl(QSerialPort::NoFlowControl); // 无流控(除非硬件支持) if (serial->open(QIODevice::ReadOnly)) { ui->statusLabel->setText("✅ 已连接"); ui->openButton->setEnabled(false); } else { ui->statusLabel->setText("❌ 打开失败: " + serial->errorString()); } }

经验之谈:波特率优先选115200。9600 太慢,尤其当你想每秒采样多次时,数据会堆积、延迟飙升。


数据来了,但你怎么知道它是一帧完整的报文?

这是最坑新手的地方:你用readAll()一口气读了100字节,结果只收到了半包数据,比如:

TEMP:24.

下一次才收到:

7\r\n

这就是典型的粘包/断包问题

怎么办?两种思路:

方案一:文本协议 + 分隔符(推荐新手)

假设下位机发送格式为:

TEMP:25.3\r\n

我们就可以按\r\n拆分,逐行解析:

void TemperatureMonitor::readSerialData() { static QByteArray buffer; // 缓存未完整接收的数据 buffer += serial->readAll(); while (buffer.contains("\r\n")) { int index = buffer.indexOf("\r\n"); QByteArray line = buffer.left(index); buffer = buffer.mid(index + 2); parseTemperatureLine(line); } // 防止 buffer 无限增长 if (buffer.length() > 1024) { buffer.clear(); } } void TemperatureMonitor::parseTemperatureLine(const QByteArray &line) { QString str = QString::fromUtf8(line).trimmed(); if (str.startsWith("TEMP:")) { bool ok; double temp = str.mid(5).toDouble(&ok); if (ok) { updateTemperatureDisplay(temp); } } }

看到没?加了个static buffer,专门用来拼接不完整的帧。这才是工业级做法。


UI更新:不只是显示数字,还要“动起来”

光在LCD上显示个数字?太静态了。我们要的是趋势图

虽然 Qt 官方Qt Charts模块有点重,但对付温度监控绰绰有余。你只需要几行代码,就能画出实时曲线:

// 假设你有一个 QChartView *chartView 成员 QLineSeries *series = new QLineSeries(); QChart *chart = new QChart(); chart->addSeries(series); chart->createDefaultAxes(); chart->axisX()->setRange(0, 50); // 显示最近50个点 chart->axisY()->setRange(0, 100); // 温度范围0~100℃ chartView->setChart(chart); // 在收到温度时添加点 void TemperatureMonitor::updateTemperatureDisplay(double temp) { static int x = 0; series->append(x++, temp); // 只保留最近50个点 if (series->count() > 50) { QLineSeries *toRemove = series->points().first(); series->remove(toRemove); } ui->lcdNumber->display(temp); }

效果如下:

[📈 实时曲线] ↗️↗️↘️↗️... [🌡️ 当前温度] 25.3°C

是不是瞬间专业感拉满?


下位机怎么配?给你一份Arduino参考代码

别忘了,上位机做得再好,下位机不配合也白搭。下面是 Arduino 发送温度的标准范式:

#include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 2 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); void setup() { Serial.begin(115200); sensors.begin(); } void loop() { sensors.requestTemperatures(); float temperatureC = sensors.getTempCByIndex(0); if (temperatureC != DEVICE_DISCONNECTED_C) { Serial.print("TEMP:"); Serial.print(temperatureC, 1); // 保留1位小数 Serial.println("°C"); } else { Serial.println("TEMP:ERR"); } delay(1000); // 每秒上报一次 }

⚠️ 注意:Serial.println()自动加\r\n,正好匹配我们的帧解析逻辑。


那些你迟早会踩的坑,现在就避开

❌ 坑1:频繁调用readAll()导致CPU飙到100%

原因:你在QTimer里轮询读串口,比如每10ms读一次。

正确做法:删掉定时器!只依赖readyRead()信号。有数据才处理,没有就歇着。

❌ 坑2:串口打不开,提示“权限不足”

Linux/macOS 用户注意:USB转TTL设备通常属于dialout组。解决方法:

sudo usermod -aG dialout $USER

重启生效。

❌ 坑3:程序退出后串口“被占用”

忘记close()会导致下次无法打开。务必在析构函数中关闭:

TemperatureMonitor::~TemperatureMonitor() { if (serial->isOpen()) { serial->close(); } delete ui; }

进阶玩法:让它更像一个“工业产品”

你现在有了基础版本,接下来可以轻松扩展这些功能:

🔔 超温报警

if (temp > 80.0) { QApplication::beep(); // 蜂鸣器 ui->alarmLabel->setText("⚠️ 高温警告!"); }

💾 记录日志到文件

QFile log("temp_log.txt"); if (log.open(QIODevice::Append)) { QTextStream out(&log); out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << " - " << temp << "°C" << "\n"; log.close(); }

🧩 多通道支持

修改协议为:

CH1:25.3,CH2:26.1\r\n

然后拆解字段即可。

🛠️ 配置记忆

QSettings保存上次用的串口和波特率:

QSettings settings("MyCompany", "TempMonitor"); settings.setValue("port", ui->portComboBox->currentText()); // 下次启动时读取 ui->portComboBox->setCurrentText(settings.value("port").toString());

写在最后:这不仅仅是个温度监控

你今天学会的,是一套通用的嵌入式上位机开发范式

  • 串口通信QSerialPort + readyRead
  • 协议解析→ 缓冲 + 分帧 + 校验
  • UI更新→ 信号驱动,非阻塞刷新
  • 健壮性→ 异常捕获、资源释放、配置持久化

这套模式,换一个传感器(湿度、压力、电压),换一个协议(Modbus、自定义二进制),就能复用90%的代码。

QSerialPort 是你通往工业控制世界的第一把钥匙。它不炫酷,但足够可靠;它不复杂,但足以支撑起真正的工程项目。

如果你正在找工作,把这个项目放进简历,面试官问:“你能独立开发上位机吗?”
你可以直接打开电脑,说:“我做过一个温度监控系统,要看看吗?”


📌关键词:qserialport、串口通信、温度监控、Qt、实时数据采集、信号槽、事件驱动、跨平台、arduino、传感器、工业测控、数据解析、gui、嵌入式、mcu

如果你实现了这个系统,欢迎在评论区晒图交流!下一个功能你想加什么?数据库?远程报警?MQTT上传?我们一起搞。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 21:04:30

Anaconda配置PyTorch环境后CUDA不可用?检查nvidia-smi

Anaconda配置PyTorch环境后CUDA不可用&#xff1f;先看nvidia-smi 在搭建深度学习开发环境时&#xff0c;你是否也遇到过这样的场景&#xff1a;满怀期待地装好PyTorch GPU版本&#xff0c;运行一行 torch.cuda.is_available()&#xff0c;结果却冷冷地返回 False&#xff1f;…

作者头像 李华
网站建设 2026/6/10 22:04:55

MuSiC单细胞反卷积完整指南:从入门到精通

MuSiC单细胞反卷积完整指南&#xff1a;从入门到精通 【免费下载链接】MuSiC Multi-subject Single Cell Deconvolution 项目地址: https://gitcode.com/gh_mirrors/music2/MuSiC 还在为单细胞RNA测序数据分析而烦恼吗&#xff1f;面对复杂的细胞类型鉴定和比例估计&…

作者头像 李华
网站建设 2026/6/10 11:19:56

如何让直播观众看清你的每一个操作?终极input-overlay指南

如何让直播观众看清你的每一个操作&#xff1f;终极input-overlay指南 【免费下载链接】input-overlay Show keyboard, gamepad and mouse input on stream 项目地址: https://gitcode.com/gh_mirrors/in/input-overlay 还在为直播时观众看不到你的精彩操作而烦恼吗&…

作者头像 李华
网站建设 2026/6/10 20:36:18

音乐解锁终极指南:3分钟搞定网易云QQ音乐加密文件转换

音乐解锁终极指南&#xff1a;3分钟搞定网易云QQ音乐加密文件转换 【免费下载链接】unlock-music 音乐解锁&#xff1a;移除已购音乐的加密保护。 目前支持网易云音乐(ncm)、QQ音乐(qmc, mflac, tkm, ogg) 。原作者也不知道是谁&#xff08;&#xff09; 项目地址: https://g…

作者头像 李华
网站建设 2026/6/10 21:28:45

Nucleus Co-op:单机游戏分屏技术深度解析与实战指南

Nucleus Co-op&#xff1a;单机游戏分屏技术深度解析与实战指南 【免费下载链接】splitscreenme-nucleus Nucleus Co-op is an application that starts multiple instances of a game for split-screen multiplayer gaming! 项目地址: https://gitcode.com/gh_mirrors/spl/s…

作者头像 李华
网站建设 2026/6/10 21:12:16

PyTorch安装完成后运行ResNet图像分类Demo

PyTorch安装完成后运行ResNet图像分类Demo 在深度学习项目中&#xff0c;最令人沮丧的场景之一莫过于&#xff1a;代码写完了&#xff0c;模型结构也调好了&#xff0c;结果一运行却报错——“torch not found”或者“版本冲突”。这种问题不是出在算法上&#xff0c;而是败在了…

作者头像 李华