You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过RTU模拟Modbus从站时jsmodbus服务端事件无法触发问题

首先明确你的两个猜想都不成立:

  • 兼容性问题不存在:Modbus RTU是通用标准协议,只要主从站报文符合规范,不同库之间不会有兼容问题
  • 程序未保持运行也不成立:你能监听到串口的readable事件说明Node.js进程一直在运行监听串口,没有退出

问题根因与解决方法

1. 从站ID配置不匹配

jsmodbus的RTU服务端默认会校验请求报文中的从站地址,如果你没有显式配置服务端的从站ID,或者主站请求的从站ID和服务端配置的不一致,服务端会直接丢弃报文,不会触发任何业务事件。
解决方法:初始化服务端时指定和主站一致的从站ID,示例:

const server = new modbus.server.RTU(socket, {
  unitId: 1 // 该值必须和主站请求的从站地址完全相同
})

2. 串口参数不全不匹配

你仅配置了波特率,还需要确认主站的校验位、数据位、停止位三个参数和从站完全一致,只要有一个参数不对,jsmodbus解析报文时会判定CRC校验失败,直接丢弃报文,不会触发事件。而直接监听readable只能拿到原始字节,不会做协议校验,所以能打印数据。
解决方法:串口初始化时补全所有参数,和主站配置完全对齐:

const options = {
    baudRate: 115200,
    dataBits: 8, // 常用值8,需和主站一致
    stopBits: 1, // 常用值1,需和主站一致
    parity: 'none' // 常用值none,可选even/odd,需和主站一致
}
const socket = new SerialPort("COM4", options)

3. 未初始化对应寄存器存储区

jsmodbus的服务端需要提前初始化对应功能码的寄存器缓冲区,否则收到读请求时会直接返回异常,也不会触发readHoldingRegisters事件。
解决方法:提前给对应寄存器区分配空间,示例:

// 初始化保持寄存器区,每个寄存器占2字节,示例初始化100个保持寄存器
server.holdingRegisters = Buffer.alloc(100 * 2)

// 如需预设寄存器值,示例给地址0的保持寄存器赋值为123
server.holdingRegisters.writeUInt16BE(123, 0)

4. 事件绑定时机问题

需确保所有事件绑定完成后再启动主站请求,可增加串口打开成功的回调确认服务初始化完成:

socket.on('open', () => {
  console.log('串口已打开,从站服务启动完成')
})

效果验证

完成上述配置后重启从站程序,再启动主站发送读保持寄存器请求,即可触发对应的readHoldingRegisters事件,jsmodbus会自动把server.holdingRegisters中存储的数值返回给主站。如果需要动态修改返回值,直接在事件回调中修改server.holdingRegisters对应位置的数值即可。

内容的提问来源于stack exchange,提问作者GreenSaber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 19:18:00