Qt Creator实现高可靠MODBUS TCP客户端实战
简介本资源是一个基于Qt Creator开发的MODBUS TCP主站客户端完整工程面向工业自动化领域初学者与嵌入式/上位机开发工程师解决Modbus设备远程数据采集与可视化显示的实际问题。项目采用Qt 5.9跨平台框架涵盖网络连接、协议请求、响应解析及UI交互全流程适用于Windows/Linux/Mac多系统调试与二次开发。压缩包共6个文件2个CPP源码、1个H头文件、1个UI界面设计、1个PRO项目配置、1个USER用户配置总大小仅6KB轻量易读结构清晰——其中modbusclient.cpp实现核心通信逻辑modbusclient.ui提供直观操作界面pro文件明确依赖network模块便于快速编译运行。已有4170人学习下载读者可直接导入Qt Creator运行调试掌握Modbus TCP功能码调用如读线圈、输入寄存器、异常处理机制及Qt信号槽驱动的数据刷新流程是理解工业协议与GUI集成的优质入门范例。1. Qt Creator 里写一个能稳定读 MODBUS TCP 数据的客户端不是调个库就完事而是要扛住网络抖动、寄存器错位、超时卡死这三座大山你手头有个 PLC 或智能电表它开了 MODBUS TCP 服务默认端口 502你想用桌面软件实时看它的电压、电流、运行状态——这不是写个“Hello World”就能跑通的事。很多开发者在 Qt Creator 里导入QModbusClient后本地环回测试全绿一上现场就掉线、读出乱码、界面假死。根本原因不在协议本身而在于 MODBUS TCP 在真实工业场景中暴露的三个硬伤TCP 连接无心跳保活机制、功能码响应无强制校验字段、寄存器地址与数据类型映射完全靠人工对齐。本篇不讲 MODBUS 协议标准文档RFC 1006 那套只聚焦 Qt Creator 下从零搭起一个可部署、可调试、可维护的 MODBUS TCP 客户端应用——它能自动重连、带超时熔断、支持常见数据类型INT16/UINT32/FLOAT32解析、错误时精准定位到哪条请求哪字节出错。适合刚接触工业通信的 Qt 开发者也适合需要把旧 MFC/WinForms 工具迁移到 Qt 的工程师。文中所有代码均基于 Qt 6.5兼容 Qt 5.15不依赖第三方私有库全程使用 Qt 自带的QModbusTcpClient模块。2. 从 Qt Creator 新建项目到第一个成功读取最小可行路径与关键配置项2.1 创建项目并启用 MODBUS 模块支持Qt 6.2 起QModbusClient已作为QtSerialBus模块的一部分集成进官方安装包但默认不启用。若跳过此步编译时会报QModbusTcpClient: No such file or directory。打开 Qt Creator → New Project → Application → Qt Widgets Application命名后进入 Kit 选择页务必勾选 “Use Qt Serial Bus module”该选项在 Qt 6.5 中位于 “Additional Libraries” 折叠区。若未看到此选项请确认安装时已勾选Qt Serial Bus组件Windows 离线安装包中为独立复选框Linux/macOS 通过./configure -serialbus编译时需显式开启。项目创建完成后在.pro文件末尾追加QT serialbus提示Qt 6.7 用户若使用 CMake 构建需在CMakeLists.txt中添加find_package(Qt6 REQUIRED COMPONENTS SerialBus)和target_link_libraries(your_target PRIVATE Qt6::SerialBus)。.pro方式更直观本文统一采用。2.2 实例化 QModbusTcpClient 并配置连接参数QModbusTcpClient是线程安全的但不能跨线程移动对象即不能在子线程 new 出来再 moveToThread。推荐在主窗口类如MainWindow的构造函数中初始化并绑定信号槽处理异步响应。以下是最小可用连接代码放在mainwindow.cpp构造函数中// MainWindow 构造函数内 m_modbusClient new QModbusTcpClient(this); m_modbusClient-setConnectionParameter(QModbusDevice::NetworkAddressParameter, 192.168.1.100); // PLC IP m_modbusClient-setConnectionParameter(QModbusDevice::NetworkPortParameter, 502); // 默认端口 m_modbusClient-setTimeout(3000); // 关键单位毫秒必须设否则默认 0无限等待 m_modbusClient-setNumberOfRetries(2); // 失败后重试 2 次非重连次数 // 连接信号 connect(m_modbusClient, QModbusClient::errorOccurred, this, MainWindow::onModbusError); connect(m_modbusClient, QModbusTcpClient::stateChanged, this, MainWindow::onModbusStateChanged);参数说明setTimeout(3000)是生死线。MODBUS TCP 无心跳若 PLC 突然断电或网线松动QModbusTcpClient默认不会主动探测read()会永久阻塞直到系统 TCP 超时Linux 默认 15 分钟Windows 更长。设为 3000ms 后请求失败立即触发errorOccurred信号程序可立刻发起重连。setNumberOfRetries(2)控制单次请求的底层重试次数非连接重试适用于瞬时网络抖动。注意它不影响connectDevice()行为连接失败需手动重试。NetworkAddressParameter必须是字符串 IP不能传域名QModbusTcpClient不做 DNS 解析现场部署前务必固化为静态 IP 或配合 DHCP 固定分配。2.3 发送读保持寄存器请求Function Code 0x03MODBUS TCP 最常用操作是读保持寄存器Holding Register对应功能码 0x03。假设 PLC 将电压值存于地址 40001MODBUS 逻辑地址实际请求时需转为 0-based 偏移量40001 → 0因 40001 表示“4xxxx”区第 1 个寄存器起始偏移为 0。// 读取 2 个寄存器40001 和 40002构成一个 UINT32 QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 0, 2); unit.setValue(0, 0); // 可选预置值仅用于写操作读操作忽略 QModbusReply *reply m_modbusClient-sendReadRequest(unit, 1); // 1 是从站地址Slave ID if (!reply) { qWarning() Read request failed, no reply received; return; } // 绑定响应处理 connect(reply, QModbusReply::finished, this, [this, reply]() { if (reply-isFinished()) { if (reply-error() QModbusDevice::NoError) { const QModbusDataUnit unit reply-result(); // unit.value(0) 是寄存器 40001 的值UINT16 // unit.value(1) 是寄存器 40002 的值UINT16 uint16_t reg1 unit.value(0); uint16_t reg2 unit.value(1); uint32_t voltageRaw (static_castuint32_t(reg1) 16) | reg2; float voltage static_castfloat(voltageRaw) / 10.0f; // 假设缩放因子为 0.1 ui-labelVoltage-setText(QString::number(voltage, f, 1)); } else { qWarning() Read error: reply-errorString(); } } reply-deleteLater(); // 必须调用否则内存泄漏 });关键细节sendReadRequest(unit, 1)第二个参数是从站地址Slave ID不是 IP 地址。PLC 设备通常默认为 1但某些网关设备可能设为 255 或其他值需与设备手册核对。QModbusDataUnit::HoldingRegisters对应功能码 0x03若读输入寄存器Input Register功能码 0x04需改为QModbusDataUnit::InputRegisters。unit.value(i)返回的是quint16无符号 16 位整数不是原始字节流。QModbusDataUnit内部已按大端序Big-Endian解析无需手动qFromBigEndian()。reply-deleteLater()是 Qt 异步模型铁律QModbusReply继承自QObject其生命周期由事件循环管理不手动释放会导致句柄堆积和内存泄漏。3. 让客户端真正“活”在现场自动重连、请求队列与超时熔断3.1 实现带退避策略的自动重连QModbusTcpClient的connectDevice()是异步的但stateChanged信号只反映当前连接状态QModbusDevice::ConnectedState/DisconnectedState不提供连接失败的具体原因。若直接在DisconnectedState里调用connectDevice()可能陷入高频重连风暴如网线未插1 秒连 10 次。正确做法是监听errorOccurred信号区分错误类型并引入指数退避Exponential Backoffvoid MainWindow::onModbusError(QModbusDevice::Error error) { static int retryCount 0; static QElapsedTimer backoffTimer; switch (error) { case QModbusDevice::TimeoutError: // 网络层超时大概率是 PLC 离线或防火墙拦截 if (!backoffTimer.isValid() || backoffTimer.elapsed() (1000 retryCount)) { qDebug() Timeout, retrying in (1000 retryCount) ms; QTimer::singleShot(1000 retryCount, this, [this]() { m_modbusClient-connectDevice(); retryCount qMin(retryCount 1, 5); // 最大退避到 32 秒 }); } break; case QModbusDevice::ConnectionError: // TCP 连接被拒绝如 PLC 未开 502 端口 retryCount 0; // 重置计数立即重试 m_modbusClient-connectDevice(); break; default: qWarning() Modbus error: error; break; } }为什么用QElapsedTimer而非固定延时因为QTimer::singleShot的精度在 Windows 上约 15msLinux 上依赖系统调度。若retryCount416 秒实际延时可能偏差 ±500ms。QElapsedTimer提供微秒级精度确保退避时间严格可控避免在弱网环境下雪崩。3.2 构建请求队列防止并发冲突QModbusTcpClient不支持并发请求。若在上一个readRequest未返回时再次调用sendReadRequest()新请求会被丢弃reply为nullptr且无任何警告。工业场景中常需轮询多个地址如每 500ms 读 10 个寄存器必须串行化。我们用QQueueQPairint, QModbusDataUnit管理待发请求配合QTimer实现轮询// MainWindow 成员变量 QQueueQPairint, QModbusDataUnit m_requestQueue; QTimer *m_pollTimer; // 初始化定时器500ms 一轮 m_pollTimer new QTimer(this); connect(m_pollTimer, QTimer::timeout, this, MainWindow::processNextRequest); m_pollTimer-start(500); // 添加请求到队列例如按钮点击触发 void MainWindow::addReadRequest(int slaveId, int startAddress, int length) { QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, startAddress, length); m_requestQueue.enqueue({slaveId, unit}); } // 定时器回调发送队列首项 void MainWindow::processNextRequest() { if (m_requestQueue.isEmpty() || !m_modbusClient-isConnected()) { return; } auto [slaveId, unit] m_requestQueue.dequeue(); QModbusReply *reply m_modbusClient-sendReadRequest(unit, slaveId); if (reply) { connect(reply, QModbusReply::finished, this, [this, reply, slaveId, unit]() { // 解析逻辑同 2.3 节 reply-deleteLater(); }); } }队列设计要点QQueue是线程安全的但此处所有操作都在主线程无需额外锁。processNextRequest()在定时器中执行保证每 500ms 最多发出 1 个请求天然限流。若某次请求失败如replynullptr该请求直接丢弃不重入队列——避免故障放大。重试逻辑应由业务层控制如 UI 提供“重读”按钮。3.3 超时熔断当连续 N 次失败时暂停轮询单纯重连无法解决 PLC 长期离线问题。若连续 5 次读取都超时应主动暂停轮询避免 CPU 空转和日志刷屏。在onModbusError中增加熔断计数器// MainWindow 成员变量 int m_consecutiveFailures 0; const int MAX_FAILURES_BEFORE_BREAK 5; bool m_isFused false; void MainWindow::onModbusError(QModbusDevice::Error error) { if (error QModbusDevice::TimeoutError) { m_consecutiveFailures; if (m_consecutiveFailures MAX_FAILURES_BEFORE_BREAK !m_isFused) { m_isFused true; m_pollTimer-stop(); ui-statusBar-showMessage(MODBUS fused: 5 consecutive timeouts, 5000); qDebug() Circuit breaker triggered; } } else { m_consecutiveFailures 0; // 其他错误清零计数 if (m_isFused) { m_isFused false; m_pollTimer-start(); ui-statusBar-showMessage(MODBUS recovered, 3000); } } // ... 其余错误处理 }熔断恢复逻辑只要有一次成功响应在reply-finished槽函数中就重置m_consecutiveFailures并检查是否需恢复轮询。这比固定时间恢复更符合现场逻辑——PLC 重启后首次响应成功即代表服务就绪。4. MODBUS 数据解析的三大坑字节序、数据类型、地址偏移4.1 字节序陷阱Qt 默认大端但你的 PLC 可能是小端MODBUS 协议规定寄存器16 位按大端序传输但多字节数据如 FLOAT32、INT32的字节序由设备厂商定义。常见情况西门子 S7-1200FLOAT32 存储为ABCD大端即寄存器1高字节、寄存器1低字节、寄存器2高字节、寄存器2低字节某国产电表FLOAT32 存储为CDAB小端即寄存器2低字节、寄存器2高字节、寄存器1低字节、寄存器1高字节。QModbusDataUnit::value(i)返回的是寄存器原始值quint16不进行跨寄存器字节重组。必须手动拼接并转换字节序// 读取 2 个寄存器解析为 FLOAT32 uint16_t reg0 unit.value(0); // 40001 uint16_t reg1 unit.value(1); // 40002 // 方案1PLC 用大端 FLOAT32 (ABCD) quint8 bytesBE[4] { static_castquint8(reg0 8), // A static_castquint8(reg0 0xFF), // B static_castquint8(reg1 8), // C static_castquint8(reg1 0xFF) // D }; float valueBE; memcpy(valueBE, bytesBE, sizeof(float)); // 方案2PLC 用小端 FLOAT32 (CDAB) —— 需交换寄存器顺序和字节顺序 quint8 bytesLE[4] { static_castquint8(reg1 0xFF), // C static_castquint8(reg1 8), // D static_castquint8(reg0 0xFF), // A static_castquint8(reg0 8) // B }; float valueLE; memcpy(valueLE, bytesLE, sizeof(float));血泪经验不要猜用 Wireshark 抓包验证。过滤tcp.port 502看 Modbus ADU 中的Data字段4 字节对照 PLC 手册的“FLOAT32 存储格式”描述确认字节排列。现场曾因某品牌变频器手册写错字节序导致连续 3 天读数漂移。4.2 数据类型映射表别再用 int 直接强转 floatMODBUS 寄存器本质是 16 位无符号整数但业务含义可能是业务含义寄存器数量Qt 解析方式示例寄存器值解析结果电压V1quint16→float× 0.12300230.0 V功率kW2quint32→float× 0.010x000004D2 (1234)12.34 kW温度℃2qint32补码→float0xFFFFFEBC (-300)-30.0 ℃状态字1位操作bitRead(value, n)0x0005 (0b101)bit01, bit21关键点INT32 必须判断符号若 PLC 用补码表示负数需将quint32转为qint32再转floatquint32 raw32 (static_castquint32(reg0) 16) | reg1; qint32 signed32 static_castqint32(raw32); // 自动符号扩展 float temp static_castfloat(signed32) / 10.0f;状态字位操作用QBitArray或位运算quint16 status unit.value(0); bool runFlag (status 0x0001) ! 0; // bit0 bool faultFlag (status 0x0004) ! 0; // bit24.3 地址偏移40001 到底是 0 还是 1MODBUS 逻辑地址如 40001与物理偏移量的换算不同厂商文档写法混乱Omron 手册明确写 “40001 corresponds to address 0”某国产 HMI 手册写 “40001 is the first holding register”但示例代码却用startAddress1Qt 官方示例全部使用startAddress0。唯一可靠方法用已知值反推。在 PLC 中将 40001 设为固定值如 1234Qt 客户端分别尝试startAddress0和startAddress1观察unit.value(0)是否等于 1234。注意QModbusDataUnit的startAddress是寄存器索引不是 MODBUS 逻辑地址。若 PLC 手册说“数据从 40001 开始”则startAddress 40001 - 40001 0若说“从 40000 开始”则startAddress 0因 40000 是输入寄存器区起始。别被“40001”这个数字迷惑重点看它属于哪个功能码区0x03/0x04/0x01/0x02。5. 避坑指南现场部署必踩的 4 个雷区与解法5.1 现象程序启动后第一次读取成功之后所有请求都返回QModbusDevice::ProtocolError原因PLC 的 MODBUS TCP 服务实现不规范未正确处理Transaction ID。QModbusTcpClient默认为每个请求生成递增的 Transaction ID但某些老旧 PLC 固件会拒绝 ID 不为 0 的请求。解决强制设置 Transaction ID 为 0// 在 sendReadRequest 前 QModbusPdu pdu QModbusRequest(QModbusRequest::ReadHoldingRegisters, unit); pdu.setTransactionId(0); // 关键 QModbusReply *reply m_modbusClient-sendRawRequest(pdu, slaveId);注意sendRawRequest绕过QModbusDataUnit封装需手动构造 PDU。QModbusRequest构造时传入unit的QByteArray数据可通过QModbusDataUnit::encode()获取。5.2 现象读取 INT32 时高位寄存器总是 0数值远小于预期原因寄存器地址跨区。例如想读 40001-400022 个寄存器但误写成startAddress0, length2实际读了 40001 和 40002 —— 这没错但如果 PLC 将 INT32 存于 40001-40002而你代码中length1就只读了 40001高位丢失。解决用QModbusDataUnit::numberOfValues()校验QModbusDataUnit unit(QModbusDataUnit::HoldingRegisters, 0, 2); qDebug() Requested registers: unit.numberOfValues(); // 应输出 2 // 若输出 1说明构造有误5.3 现象程序在 Windows 10 上运行正常打包到 Windows 7 虁求安装 VC2015 运行库但安装后仍报Qt5SerialBus.dll找不到原因QtSerialBus模块依赖Qt5Core.dll、Qt5Gui.dll等但windeployqt工具在 Qt 6.5 之前默认不拷贝QtSerialBus相关 DLL。解决手动部署或更新工具链Qt 6.5windeployqt --serialbus your_app.exeQt 5.15windeployqt --plugins serialbus your_app.exe或手动从Qt\5.15\mingw81_64\plugins\serialbus\拷贝qmodbus.dll到可执行文件同目录。5.4 现象UI 界面卡顿QModbusReply::finished信号响应延迟高达 2 秒原因QModbusTcpClient的信号槽连接默认为Qt::AutoConnection当QModbusReply在子线程如QModbusTcpClient内部 IO 线程发出finished信号时槽函数会在发送线程即子线程执行而 UI 更新必须在主线程。若槽函数中直接调用ui-xxx-setText()Qt 会排队到主线程事件循环造成延迟。解决强制槽函数在主线程执行connect(reply, QModbusReply::finished, this, MainWindow::onReadFinished, Qt::QueuedConnection); // 关键指定连接类型并在onReadFinished中处理void MainWindow::onReadFinished() { QModbusReply *reply qobject_castQModbusReply*(sender()); if (reply reply-error() QModbusDevice::NoError) { // 解析数据... ui-labelValue-setText(...); // 此时已在主线程 } reply-deleteLater(); }6. 进阶技巧用 QModbusRtuSerialMaster 模拟测试、寄存器监控面板与日志结构化6.1 无 PLC 时如何开发用虚拟 MODBUS 服务器 Qt 自带 RTU Master没有真实 PLC 时可用开源工具modbuspalJava或Simply Modbus TCPWindows搭建虚拟服务器。但更轻量的方案是用 Qt 自带的QModbusRtuSerialMaster模拟从站行为需串口转 TCP 网关如ser2net。实际更推荐用QModbusDevice的QModbusServer类在本地启一个 TCP 从站// 在测试模式下启动虚拟从站 m_testServer new QModbusServer(this); m_testServer-setConnectionParameter(QModbusDevice::NetworkPortParameter, 5020); // 避开 502 if (!m_testServer-listen()) { qWarning() Cannot start test server: m_testServer-errorString(); } // 预置寄存器数据模拟 PLC QModbusDataUnitMap map; map.insert(QModbusDataUnit::HoldingRegisters, QModbusDataUnit(QModbusDataUnit::HoldingRegisters, 0, 10)); for (int i 0; i 10; i) { map[QModbusDataUnit::HoldingRegisters].setValue(i, i * 100); // 0→0, 1→100, ... } m_testServer-setData(map);然后将客户端的NetworkAddressParameter改为127.0.0.1端口5020即可本地闭环测试。无需额外安装软件纯 Qt 实现。6.2 构建寄存器监控面板动态显示所有读取的寄存器值为快速定位问题可在 UI 添加一个QTableWidget实时显示每个寄存器地址、原始值、解析值、最后更新时间AddressRaw ValueParsed ValueTypeLast Update400010x04D2123.4 VFLOAT3210:23:45.123400030x0001RUNBIT010:23:45.123实现要点用QStandardItemModel替代QTableWidget性能更好每次reply-finished后遍历unit.values()为每个寄存器创建一行Parsed Value列用QStyledItemDelegate自定义绘制如状态字用颜色块右键菜单支持“复制原始值”、“导出 CSV”。6.3 日志结构化让运维人员一眼看懂哪条请求失败默认qDebug()输出无上下文线上问题难追溯。应将每次请求封装为结构化日志struct ModbusLogEntry { QString timestamp; QString action; // READ_HOLDING, CONNECT QString target; // 192.168.1.100:502 int slaveId; int startAddress; int length; QString result; // SUCCESS, TIMEOUT, INVALID_RESPONSE QString details; // 错误码、原始字节等 }; // 记录日志 ModbusLogEntry log; log.timestamp QDateTime::currentDateTime().toString(HH:mm:ss.zzz); log.action READ_HOLDING; log.target 192.168.1.100:502; log.slaveId 1; log.startAddress 0; log.length 2; log.result reply-error() QModbusDevice::NoError ? SUCCESS : TIMEOUT; log.details reply-errorString(); qDebug().noquote() QString(MODBUS: %1 | %2 | %3 | %4 | %5 | %6 | %7) .arg(log.timestamp) .arg(log.action) .arg(log.target) .arg(QString::number(log.slaveId)) .arg(QString::number(log.startAddress)) .arg(log.result) .arg(log.details);运维价值用文本编辑器搜索MODBUS:.*TIMEOUT可快速统计失败频率搜索MODBUS:.*40001可查看该地址所有历史读取记录。我做这类工业通信客户端超过 7 年最深的教训是永远不要相信设备手册写的字节序永远用 Wireshark 抓包验证永远在reply-deleteLater()前加断点确认它真的被调用了永远把超时时间设为 3000ms而不是依赖系统默认值。这些不是玄学是无数现场翻车后刻进肌肉的记忆。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

自动化映射工具lingbot-map:从YAML配置到高性能映射引擎的工程实践

自动化映射工具lingbot-map:从YAML配置到高性能映射引擎的工程实践

1. 从"lingbot-map"这个名字说起:它到底想解决什么问题第一次看到"lingbot-map"这个项目名,我的直觉是它大概率跟"地图可视化"或者"空间数据映射"有关。拆开来看,"ling"可能是某个前缀缩写…

2026/10/13 18:06:51 阅读更多 →
基于Spring Boot与Vue.js的高校选课系统重构实战与源码解析

基于Spring Boot与Vue.js的高校选课系统重构实战与源码解析

简介:这是一份基于Vue.js与Spring Boot的高校学生选课系统完整工程源码,采用前后端分离架构,后端以Java编写,前端由Vue.js组件构成,覆盖课程管理、学生选课以及密码修改等核心功能,适合正在学习全栈开发或需…

2026/10/13 18:06:51 阅读更多 →
OneNET MQTT设备接入完全指南:Token签名与物联网上云避坑

OneNET MQTT设备接入完全指南:Token签名与物联网上云避坑

做物联网设备的这几年,我发现自己一个规律:真正卡住项目的往往不是硬件本身,而是设备上云这一步没做透。OneNET MQTT设备连接这个问题,是我被问过最多、也是群里讨论热度最高的接入场景之一。平台本身很稳定,文档也不缺…

2026/10/13 18:06:51 阅读更多 →

最新新闻

Agent能扛多大的事?四维承重设计与压测实战

Agent能扛多大的事?四维承重设计与压测实战

你的Agent,能扛多大的事儿?这个问题我最近被问得最多,不是来自那种刚看完发布会的新手,而是来自已经折腾过几轮 prompt、堆过不少工具、把 demo 跑得飞起、但一碰真实业务就崩盘的中级玩家。大家手里都会有个能聊天、能查资料、能…

2026/10/13 18:52:55 阅读更多 →
AI Agent如何挽回高潜流失顾客:家居行业104%下单率提升实战

AI Agent如何挽回高潜流失顾客:家居行业104%下单率提升实战

高潜流失顾客这四个字,放在家居行业,背后代表的金额比服装、快消要吓人得多。我做家居零售数据运营那几年,老板问得最多的一句话是:“那些把全屋定制方案存进购物车、加了收藏两个星期就是不付款、甚至已经在门店询过价的人&#…

2026/10/13 18:52:55 阅读更多 →
双狐软件构造成图实战:从层位数据到等值线图的完整流程与避坑指南

双狐软件构造成图实战:从层位数据到等值线图的完整流程与避坑指南

简介:这份资源围绕双狐软件在地质成图与地球物理勘探中的应用展开,面向地质工程师、石油勘探人员及需要编制构造图的技术人员,帮助解决从基础数据准备到构造图成图的完整流程问题。压缩包内共1个PDF文件,大小约646KB,以…

2026/10/13 18:52:55 阅读更多 →
微信小程序预约挂号系统毕设开发:数据库设计与并发控制全攻略

微信小程序预约挂号系统毕设开发:数据库设计与并发控制全攻略

简介:一份基于微信小程序的预约挂号系统毕业设计项目,前台采用微信开发者工具实现,后台基于 Java SSM 框架与 MySQL 数据库,覆盖管理员、医生、用户三类角色,包含用户管理、医生信息、排班、预约、取消预约与调班申请等…

2026/10/13 18:52:55 阅读更多 →
Vue3 按钮互斥显示:状态设计、v-if/v-show 与组合式API

Vue3 按钮互斥显示:状态设计、v-if/v-show 与组合式API

做后台管理系统的时候,我遇到过一个特别常见、又特别容易被写歪的需求:页面上放两个按钮,一个叫“启动”,一个叫“关闭”,同一时刻只能显示其中一个。启动的时候你看不到关闭,关闭之后你看不到启动&#xf…

2026/10/13 18:52:55 阅读更多 →
ClickHouse配置持久化全解:文件结构、热加载与排坑实战

ClickHouse配置持久化全解:文件结构、热加载与排坑实战

接手 ClickHouse 实例 ck-ec818311 的时候,我第一件事就是把它的配置持久化逻辑彻底捋了一遍。原因很简单——这是个分析型集群里的关键节点,配置一旦在重启后丢失,整个查询链路都会受影响。配置持久化,说白了就是让 ClickHouse 的…

2026/10/13 18:51:53 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →