通过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
相关产品推荐
相关产品推荐

