1. Node.js与Modbus RTU通信实战指南
在工业自动化领域,Modbus协议因其简单可靠的特点成为设备通信的事实标准。而Node.js凭借其异步非阻塞的特性,非常适合用于构建高效的设备监控和数据采集系统。本文将详细介绍如何使用Node.js通过Modbus RTU协议与RS485设备进行通信。
2. 环境准备与模块安装
2.1 硬件连接准备
RS485通信需要以下硬件组件:
- RS485转USB转换器(如CH340芯片方案)
- 双绞线(建议使用屏蔽双绞线)
- 终端电阻(120Ω,用于长距离通信)
接线注意事项:
- A+(正极)接设备的A+/D+
- B-(负极)接设备的B-/D-
- 确保所有设备共地
- 总线两端需接入终端电阻
2.2 Node.js环境配置
推荐使用Node.js LTS版本(当前为18.x):
bash复制# 使用nvm管理Node版本
nvm install 18
nvm use 18
# 验证安装
node -v
npm -v
2.3 安装modbus-serial模块
bash复制npm install modbus-serial
如果遇到串口权限问题(Linux系统):
bash复制# 将用户加入dialout组
sudo usermod -a -G dialout $USER
3. 基础通信实现
3.1 建立串口连接
javascript复制const ModbusRTU = require("modbus-serial");
const client = new ModbusRTU();
// 串口连接配置
const serialConfig = {
baudRate: 9600, // 波特率
dataBits: 8, // 数据位
stopBits: 1, // 停止位
parity: 'none', // 校验位
timeout: 2000 // 超时(ms)
};
// 建立连接
client.connectRTUBuffered("/dev/ttyUSB0", serialConfig)
.then(() => {
console.log("串口连接成功");
readDeviceData();
})
.catch(err => {
console.error("连接失败:", err);
});
3.2 读取保持寄存器
javascript复制async function readDeviceData() {
try {
client.setID(1); // 设置从站地址
// 读取地址0开始的10个保持寄存器
const data = await client.readHoldingRegisters(0, 10);
console.log("读取结果:", data.data);
// 解析数据(假设前两个寄存器为32位浮点数)
const buffer = Buffer.alloc(4);
buffer.writeUInt16BE(data.data[0], 0);
buffer.writeUInt16BE(data.data[1], 2);
const floatValue = buffer.readFloatBE(0);
console.log("解析值:", floatValue);
} catch (err) {
console.error("读取失败:", err);
}
}
3.3 写入单个寄存器
javascript复制async function writeSingleRegister() {
try {
client.setID(1);
// 向地址5写入值1234
await client.writeRegister(5, 1234);
console.log("写入成功");
} catch (err) {
console.error("写入失败:", err);
}
}
4. 高级功能实现
4.1 多设备轮询
javascript复制const deviceList = [1, 2, 3]; // 从站地址列表
const pollInterval = 1000; // 轮询间隔(ms)
async function pollDevices() {
for (const deviceId of deviceList) {
try {
client.setID(deviceId);
const data = await client.readInputRegisters(0, 5);
console.log(`设备${deviceId}数据:`, data.data);
} catch (err) {
console.error(`设备${deviceId}读取失败:`, err.message);
}
await new Promise(resolve => setTimeout(resolve, 100));
}
setTimeout(pollDevices, pollInterval);
}
// 启动轮询
client.connectRTUBuffered("/dev/ttyUSB0", serialConfig)
.then(pollDevices);
4.2 异常处理与重连机制
javascript复制let retryCount = 0;
const maxRetries = 3;
async function connectWithRetry() {
try {
await client.connectRTUBuffered("/dev/ttyUSB0", serialConfig);
retryCount = 0;
console.log("连接成功");
pollDevices();
} catch (err) {
retryCount++;
if (retryCount <= maxRetries) {
console.log(`尝试重新连接(${retryCount}/${maxRetries})...`);
setTimeout(connectWithRetry, 2000);
} else {
console.error("达到最大重试次数,请检查设备连接");
}
}
}
// 监听错误事件
client.on('error', (err) => {
console.error("通信错误:", err);
if (!client.isOpen) {
connectWithRetry();
}
});
5. 性能优化与调试技巧
5.1 通信参数优化
-
超时设置:根据网络延迟调整
javascript复制client.setTimeout(1500); // 1.5秒超时 -
缓冲区大小:大数据量传输时调整
javascript复制client.connectRTUBuffered("/dev/ttyUSB0", { baudRate: 115200, highWaterMark: 1024 * 8 // 8KB缓冲区 });
5.2 调试工具推荐
- Modbus Poll:Windows平台调试工具
- QModMaster:开源跨平台调试工具
- serialport-list:查看可用串口
bash复制
npx @serialport/list
5.3 常见问题排查
-
无响应:
- 检查接线是否正确(A+/B-是否接反)
- 确认从站地址设置正确
- 验证波特率、校验位等参数匹配
-
CRC校验错误:
- 检查线路是否受到干扰
- 尝试降低波特率
- 确保总线两端有终端电阻
-
数据错乱:
- 检查字节序设置
- 验证数据类型(16位/32位)
- 确认寄存器映射表正确
6. 实际应用案例
6.1 工业传感器数据采集
javascript复制// 温度传感器数据解析
async function readTemperature() {
client.setID(1);
const data = await client.readInputRegisters(0, 2);
// 假设数据格式:寄存器0为整数部分,寄存器1为小数部分
const temp = data.data[0] + (data.data[1] / 100);
console.log(`当前温度: ${temp}°C`);
return temp;
}
// 定时采集
setInterval(readTemperature, 5000);
6.2 PLC控制指令发送
javascript复制async function controlMotor(speed, direction) {
try {
client.setID(2);
// 写入速度值到地址10
await client.writeRegister(10, speed);
// 写入方向控制到地址11的bit0
await client.writeCoil(11, direction === 'forward');
console.log("控制指令发送成功");
} catch (err) {
console.error("控制失败:", err);
}
}
// 示例:以50%速度正向转动
controlMotor(50, 'forward');
7. 安全注意事项
-
物理安全:
- RS485总线应远离强电线路
- 使用屏蔽线并确保屏蔽层单点接地
- 避免总线长度超过1200米(9600bps时)
-
数据安全:
- 关键控制指令应添加校验机制
- 重要参数写入前进行范围检查
- 考虑添加操作日志记录
-
系统安全:
- 实现心跳检测机制
- 添加异常自动恢复功能
- 关键操作需要二次确认
重要提示:在工业现场实施前,务必在测试环境中充分验证所有功能。Modbus RTU协议本身没有加密机制,敏感控制指令应考虑额外的安全措施。
