一、内容简介
本篇内容主要介绍如何分别用Modbus-Server和Modbus-Flex-Server节点来部署ModbusTCP服务器,并通过buffer-maker节点按一定格式写入数据,如float、double等,然后用Modbus Poll软件来测试写入的数据是否正确。
buffer-maker是node-red-contrib-buffer-parser插件的一个节点,在文章Node-Red怎么解析Modbus数据中有详细的安装说明。
Modbus-Server和Modbus-Flex-Server是node-red-contrib-modbus插件的节点,在文章Node-Red与ModbusTCP设备通信——读数据中也有安装说明。
ModbusPoll软件可以模拟Modbus主站,一般用于测试Modbus从站设备,如没有安装,请先安装该软件,可以按文章末尾提供的方式获取,也可以从官网下载。
二、环境搭建
1.ModbusTCP服务器配置
从左侧面板中拖入一个inject(时间戳)节点、一个Modbus-Server节点、一个debug节点到工作区,并依次连接。
双击Modbus-Server节点,记录下监听端口10502,或者将其修改为其它想要监听的端口。
部署流程后,点击inject(时间戳)节点触发流,调试面板显示如下:
第一条是Modbus-Server第一个输出点输出的数据,表示保持寄存器(holding register)缓存,后面依次为线圈(coils register)缓存、输入寄存器(input register)缓存、离散输入寄存器(discrete inputs register)缓存,缓存中一个元素表示一个字节。
2.ModbusPoll配置
打开软件,点击Connection菜单,在弹出的对话框输入IP“ 127.0.0.1”,填写上面记录的端口“10502”点击“OK”,连接到ModbusTCP服务器。
软件打开会默认新建10个保持寄存器(holding register),需要再新建10个线圈(coils register),点击菜单File->New,默认创建10个保持寄存器,再点击菜单Setup->Read/Write Definition,修改Function为“01 Read Coils (0x)”,点击OK确认。
- Modbus-Server
在Node-Red中通过buffer-maker节点向Modbus-Server写入数据,分别以Bool,Signed、Unsigned、Long、Float、Double等编码格式写入,并通过ModbusPoll软件来测试是否写入正确,以保持寄存器(holding register)和线圈(coils register)为例进行说明,其它寄存器写入方法类似。
1.保持寄存器(holding register)
- 按类型Signed写入
在Modbus-Server节点与inject(时间戳)节点之间插入一个buffer-maker节点和一个function节点,并将其连接。
双击inject(时间戳)节点,将msg.payload的类型修改为“{}JSON”,值为修改“[33,444,5555]”,点击完成按钮确定。
双击buffer-maker节点将Name修改为“Signed”,item1的Type修改为“int16(be)”,Length修改为“-1”,其余保持不变,点击完成按钮确定。
双击function节点,将名称改为“holding”,输入如下内容:
msg.payload = {
'value': msg.payload,
'register': 'holding',
'address': 0,
'disableMsgOutput': 0
};
return msg;
点击完成按钮确定,然后部署流程。
点击inject(时间戳)节触发流进行测试,调试面板显示如下:
缓存显示的是字节流,看起来比较混乱,再来看ModbusPoll中的保持寄存器(holding register):
默认按Signed类型显示,显示正确。
注意:Modbus-Server节点在Node-Red重新部署之后ModbusPoll需要手动断开并重新连接,否则数据不会刷新。
- 按类型Unsigned写入
在Node-Red工作区复制inject([33,444,5555])和buffer-maker(Signed)节点,并将其连接到function(holding)节点。
修改inject([33,444,5555])节点msg.payload的值为[888,32768],点击完成按钮确定。
将buffer-maker(Signed)节点的Name修改为“Unsigned”,item1的Type修改为“uint16(be)”,点击完成按钮确定。
部署流程。
触发流进行测试,ModbusPoll显示为负数:
这是由于类型不匹配而导致,鼠标拖动选中所有寄存器,点击菜单Display->Unsigned,将显示类型设置为Unsigned:
数据显示正确。
3.按类型Long写入
在Node-Red工作区复制inject([888,32768])和buffer-maker(Unsigned)节点,并将其连接到function(holding)节点。
将buffer-maker(Unsigned)节点的Name修改为“LongABCD”,item1的Type修改为“int32(be)”,点击完成按钮确定。
部署流程之后触发该流,
在ModbusPoll中将显示类型切换到LongABCD,结果显示正确。
在Node-Red工作区将节点inject([888,32768])和buffer-maker(LongABCD)复制三遍,分别依次连接到function(holding)节点,将复制的第一个buffer-maker(LongABCD)节点的名称修改为“LongCDAB”,item1的Type改为“int32(le)”,Bype swap选择“16”,点击完成按钮确认。
再将复制的第二个buffer-maker(LongABCD)节点的名称修改为“LongBADC”,Bype swap选择“16”,点击完成按钮确认。
最后将复制的第三个buffer-maker(LongABCD)节点的名称修改为“LongDCBA”,item1的Type改为“int32(le)”,确认修改之后部署流程。
分别触发复制的流,在ModbusPoll中切换到对应的类型,数据均解析正确。
4.按类型Float写入
在Node-Red工作区复制属于Long类型所有节点,将复制的buffer-maker(LongABCD)节点的名称修改为“FloatABCD”,item1的Type改为“float(be)”并确定
将buffer-maker(LongCDAB)节点的名称修改为“FloatCDAB”,item1的Type改为“float(le)”,确认修改。
再将buffer-maker(LongBADC)节点的名称修改为“FloatBADC”,item1的Type改为“float(be)”,点击完成按钮确定。
最后将buffer-maker(LongDCBA)节点的名称修改为“FloatDCBA”,item1的Type改为“float(le)”
确定之后部署流程。
依次触发Float流,在ModbusPoll设置对应的类型,显示结果全部正确。
- 按类型Double写入
在Node-Red工作区复制属于Float类型所有节点,将复制的buffer-maker(FloatABCD)节点的名称修改为“DoubleABCDEFGH”,item1的Type改为“double(be)”并确定
将buffer-maker(FloatCDAB)节点的名称修改为“DoubleGHEFCDAB”,item1的Type改为“double(le)”,确定修改。
再将buffer-maker(FloatBADC)节点的名称修改为“DoubleBADCFEHG”,item1的Type改为“double(be)”,确定。
最后将buffer-maker(FloatDCBA)节点的名称修改为“DoubleHGFEDCBA”,item1的Type改为“double(le)”
确定之后部署流程。
依次触发Double类型所属的流,在ModbusPoll设置对应的类型,显示结果正确无误。
2.线圈(coils register)
在Node-Red工作区复制第一行,也就是inject([33,444,5555])、buffer-maker(Signed)节点 和function(holding)节点,并将其连接到Modbus-Server节点,将inject([33,444,5555])节点的值改为“[true,false,true]”并确定
将buffer-maker(Signed)节点命名为“Bool”,item1的Type选择“bool”,其余不变
再将function(holding)节点命名为“coils”,在函数标签输入如下代码:
msg.payload = {
'value': msg.payload,
'register': 'coils',
'address': 0,
'disableMsgOutput': 0
};
return msg;
确定修改并部署流程。
触发流后,ModbusPoll显示正确。
- Modbus-Flex-Server
点击Node-Red右上角的主菜单->流程->增加,增加一个流程
复制Modbus-Server所属流程的所有节点到新增流程,并将Modbus-Server节点替换为Modbus-Flex-Server节点。
双击Modbus-Flex-Server节点,记录下端口11502,
切换到标签页面Get Coil,将代码替换为:
function getFlexCoil(addr, unitID) {
if (unitID === node.unitId &&
addr >= node.minAddress &&
addr <= node.splitAddress) {
let bytes = Math.trunc(addr / 8);
let bits = Math.trunc(addr % 8);
let mask = 1 << bits;
let value = node.coils.readUInt8(bytes) & mask;
return value;
}
}
切换到标签页面Get Discrete,将代码替换为:
function getFlexDiscreteInput(addr, unitID) {
addr += node.splitAddress
if (unitID === node.unitId &&
addr >= node.splitAddress &&
addr <= node.splitAddress * 2) {
let address = addr - node.splitAddress;
let bytes = Math.trunc(address / 8);
let bits = Math.trunc(address % 8);
let mask = 1 << bits;
let value = node.coils.readUInt8(node.bufferFactor * node.splitAddress + bytes) & mask;
return value
}
}
切换到标签页面Get Input,将代码替换为:
function getFlexInputRegister(addr, unitID) {
if (unitID === node.unitId &&
addr >= node.minAddress &&
addr <= node.splitAddress) {
return node.registers.readUInt16BE(addr * 2)
}
}
切换到标签页面Get holding,将代码替换为:
function getFlexHoldingRegsiter(addr, unitID) {
addr += node.splitAddress
if (unitID === node.unitId &&
addr >= node.splitAddress &&
addr <= node.splitAddress * 2) {
return node.registers.readUInt16BE(node.splitAddress * node.bufferFactor + (addr - node.splitAddress) * 2)
}
}
切换到标签页面Set Coil,将代码替换为:
function setFlexCoil(addr, value, unitID) {
if (unitID === node.unitId &&
addr >= node.minAddress &&
addr <= node.splitAddress) {
let bytes = Math.trunc(addr / 8);
let bits = Math.trunc(addr % 8);
let val = node.coils.readUInt8(bytes);
let mask = 1 << bits;
if(value){
val |= mask;
}
else
{
mask = ~mask;
val &= mask;
}
node.coils.writeUInt8(val, bytes)
}
}
切换到标签页面Set Register,将代码替换为:
function setFlexRegister(addr, value, unitID) {
addr += node.splitAddress
if (unitID === node.unitId &&
addr >= node.splitAddress &&
addr <= node.splitAddress * 2) {
node.registers.writeUInt16BE(value, node.splitAddress * node.bufferFactor + (addr - node.splitAddress) * 2)
}
}
点击完成按钮确定,部署流程。
将ModbusPoll重新连接到Modbus-Flex-Server的11502端口,在Node-Red逐一触发流进行测试,设置ModbusPoll以相应的类型显示,数据均正确。
Modbus-Flex-Server节点在Node-Red重新部署之后ModbusPoll不需要重连,这一点要比Modbus-Server节点用起来方便。
如果您想获取文章相关的代码、工具等资料,关注公众号“NodeRed物联网”,回复“nr”即可。