MODBUS TCP/IP与Node.js:PLC重启后无法读取浮点值的解决方案需求
解决MODBUS PLC断开重连后无法读取浮点值的问题
你的问题核心是MODBUS客户端缺少连接失效后的自动重连逻辑:服务器启动时PLC在线,成功建立连接;但PLC断开后,原有连接失效且未触发重新连接,导致后续读取请求全部失败。
下面是完整的可运行代码,基于modbus-serial和express实现自动重连+实时读取功能:
后端(Node.js)实现
首先安装依赖:
npm install modbus-serial express cors
创建server.js:
const ModbusRTU = require("modbus-serial"); const express = require("express"); const cors = require("cors"); const app = express(); app.use(cors()); app.use(express.json()); // PLC配置信息,根据实际情况修改 const PLC_SETTINGS = { host: "192.168.1.100", // 替换为你的PLC IP port: 502, // MODBUS TCP默认端口 slaveId: 1, // PLC从站ID pollInterval: 2000, // 数据轮询间隔(毫秒) floatRegisterAddr: 0, // 浮点值对应的起始寄存器地址 registerCount: 2 // 浮点值占用2个16位寄存器 }; const client = new ModbusRTU(); let isPLCConnected = false; let latestFloatValue = null; // 连接PLC的封装函数 async function connectToPLC() { try { // 先关闭已有连接(如果存在) if (client.isOpen) await client.close(); await client.connectTCP(PLC_SETTINGS.host, { port: PLC_SETTINGS.port }); client.setID(PLC_SETTINGS.slaveId); isPLCConnected = true; console.log("PLC连接成功"); } catch (error) { isPLCConnected = false; console.error(`PLC连接失败: ${error.message}`); // 1秒后自动重试连接 setTimeout(connectToPLC, 1000); } } // 轮询读取PLC浮点值 async function pollPLCData() { if (!isPLCConnected) { await connectToPLC(); setTimeout(pollPLCData, 1000); return; } try { // 读取保持寄存器 const response = await client.readHoldingRegisters(PLC_SETTINGS.floatRegisterAddr, PLC_SETTINGS.registerCount); // 转换为32位浮点值(大端模式,若PLC是小端则交换两个寄存器的位置) latestFloatValue = ModbusRTU.utils.toFloat(response.data[0], response.data[1]); console.log(`读取到浮点值: ${latestFloatValue}`); } catch (error) { isPLCConnected = false; console.error(`读取PLC数据失败: ${error.message}`); } finally { // 无论成功失败,按设定间隔继续轮询 setTimeout(pollPLCData, PLC_SETTINGS.pollInterval); } } // 提供给前端的API接口 app.get("/api/plc-data", (req, res) => { res.json({ connected: isPLCConnected, floatValue: latestFloatValue, timestamp: new Date().toISOString() }); }); // 启动服务器并初始化轮询 const SERVER_PORT = 3000; app.listen(SERVER_PORT, () => { console.log(`服务器运行在 http://localhost:${SERVER_PORT}`); pollPLCData(); });
前端(HTML/CSS/JS)实现
创建index.html:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>PLC浮点值监控</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: system-ui, -apple-system, sans-serif; max-width: 500px; margin: 3rem auto; padding: 0 1rem; } .status-card { padding: 1.2rem; border-radius: 8px; margin-bottom: 1.5rem; text-align: center; } .connected { background-color: #ecfdf5; color: #065f46; border: 1px solid #a7f3d0; } .disconnected { background-color: #fef2f2; color: #991b1b; border: 1px solid #fecaca; } .value-display { font-size: 2.5rem; font-weight: 600; text-align: center; color: #1f2937; } </style> </head> <body> <div class="status-card" id="connectionStatus"> 正在连接PLC... </div> <div class="value-display" id="floatValue">--</div> <script> const STATUS_ELEMENT = document.getElementById("connectionStatus"); const VALUE_ELEMENT = document.getElementById("floatValue"); const FETCH_INTERVAL = 2000; // 和后端轮询间隔保持一致 async function updatePLCData() { try { const response = await fetch("http://localhost:3000/api/plc-data"); const data = await response.json(); // 更新连接状态显示 if (data.connected) { STATUS_ELEMENT.className = "status-card connected"; STATUS_ELEMENT.textContent = "PLC已连接"; VALUE_ELEMENT.textContent = data.floatValue ? data.floatValue.toFixed(2) : "--"; } else { STATUS_ELEMENT.className = "status-card disconnected"; STATUS_ELEMENT.textContent = "PLC未连接"; VALUE_ELEMENT.textContent = "--"; } } catch (error) { STATUS_ELEMENT.className = "status-card disconnected"; STATUS_ELEMENT.textContent = "服务器连接异常"; VALUE_ELEMENT.textContent = "--"; } finally { setTimeout(updatePLCData, FETCH_INTERVAL); } } // 启动前端数据更新 updatePLCData(); </script> </body> </html>
关键说明
- 自动重连逻辑:
connectToPLC函数在连接失败后会自动重试,pollPLCData每次轮询前都会检查连接状态,确保断开后能重新建立连接。 - 浮点值转换:根据PLC的字节序调整
toFloat的参数顺序,大部分PLC默认大端模式,若读取值异常,可改为ModbusRTU.utils.toFloat(response.data[1], response.data[0])。 - 状态同步:前后端都维护连接状态,前端实时显示连接情况和最新数据,提升用户体验。
内容的提问来源于stack exchange,提问作者Suriya S
相关产品推荐
相关产品推荐

