在工业物联网和自动化控制领域,Modbus 协议依然是最常见的通信方式之一。为了更直观地理解 Modbus TCP 的工作机制,我用AI写了一个小 Demo:同时实现了 从站(Slave) 和 主站(Master),并且能在本地跑通数据交互。
Demo 功能
- 从站每2秒更新寄存器0。
- 主站每3秒读取寄存器0,并写寄存器1。
- 控制台能看到双向交互,证明通信正常。
js
// master.js
const ModbusRTU = require('modbus-serial')
const client = new ModbusRTU()
async function run() {
try {
await client.connectTCP('127.0.0.1', { port: 1502 })
client.setID(1)
console.log('✅ 主站已连接到从站')
setInterval(async () => {
try {
// 读取保持寄存器0
const data = await client.readHoldingRegisters(0, 1)
console.log('📥 主站: 读取寄存器[0] =', data.data[0])
// 写保持寄存器1
const value = Math.floor(Math.random() * 100)
await client.writeRegister(1, value)
console.log('📤 主站: 写寄存器[1] =', value)
} catch (err) {
console.error('读写错误:', err.message)
}
}, 3000)
} catch (err) {
console.error('连接失败:', err.message)
}
}
run()
js
// slave.js
const ModbusRTU = require('modbus-serial')
// 模拟保持寄存器(100个,2字节/个)
let holdingRegisters = Buffer.alloc(100 * 2)
const vector = {
// 读取保持寄存器
getHoldingRegister: function (addr) {
const value = holdingRegisters.readUInt16BE(addr * 2)
console.log(`📥 从站: 读取保持寄存器[${addr}] = ${value}`)
return Promise.resolve(value)
},
// 写保持寄存器
setRegister: function (addr, value) {
holdingRegisters.writeUInt16BE(value, addr * 2)
console.log(`📤 从站: 写保持寄存器[${addr}] = ${value}`)
return Promise.resolve()
},
// 读取线圈
getCoil: function (addr) {
return Promise.resolve(addr % 2 === 0)
},
// 写线圈
setCoil: function (addr, value) {
console.log(`📤 从站: 写线圈[${addr}] = ${value}`)
return Promise.resolve()
}
}
// 启动 Modbus TCP 从站
const customPort = 1502 // 自定义端口,避免与其他服务冲突
const serverTCP = new ModbusRTU.ServerTCP(vector, {
host: '127.0.0.1',
port: customPort,
debug: true,
unitID: 1
})
console.log(`✅ Modbus TCP 从站已启动,监听 127.0.0.1:${customPort}`)
// 模拟寄存器0的值每2秒变化
setInterval(() => {
const randomValue = Math.floor(Math.random() * 1000)
holdingRegisters.writeUInt16BE(randomValue, 0)
console.log('🔄 从站: 更新寄存器[0] =', randomValue)
}, 2000)
运行
npm install modbus-serial
node slave.js
node master.js
结果
