Modbus是开源的通讯协议,使用简单灵活,相关知识容易获取。实际应用中,常常有将各种RS232、RS485等设备联网,供远程服务器读取的需求,这是采用一台边缘的转换网关,连接多台设备,然后转换为Modbus是一个不错的方案。
之前使用过一个NModbus的C#分支版本NModbus4,使用也比较简单,提供数据锁解决并发问题,提供Master连接数量、读取数据请求次数等监控功能。但NModbus4已经7年多没有更新,测试发现读取数据时,如果长度超出Modbus协议约束的长度,会导致异常造成服务退出,而且这个异常是应用层拦截和屏蔽不了。另外,NModbus4的多从站实现方法较为复杂,使用中就改用为NModbus开源库。
多Slave站测试代码段如下:
using NModbus;
using System;
using System.Net.Sockets;
using System.Windows.Forms;
using System.Net;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private TcpListener modbusListener;
IModbusSlave slave1;
IModbusSlave slave2;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//创建通讯绑定端口
modbusListener = new TcpListener(IPAddress.Parse("0.0.0.0"), 502);
modbusListener.Start();
IModbusFactory factory = new ModbusFactory();
IModbusSlaveNetwork modbusSlaveNetwork = factory.CreateSlaveNetwork(modbusListener);
//创建两个Slave设备,Id分别为1和2
slave1 = factory.CreateSlave(1);
slave2 = factory.CreateSlave(2);
modbusSlaveNetwork.AddSlave(slave1);
modbusSlaveNetwork.AddSlave(slave2);
//接受连接
modbusSlaveNetwork.ListenAsync();
timer1.Enabled = true;
}
//数据仿真
ushort uValue = 0;
private void timer1_Tick(object sender, EventArgs e)
{
ushort[] v = new ushort[2];
v[0] = (ushort)(uValue++%10000);
v[1] = (ushort)(uValue++ % 10000);
slave1.DataStore.InputRegisters.WritePoints(0, v);
v[0] = (ushort)(uValue++ % 10000+20000);
v[1] = (ushort)(uValue++ % 10000 + 20000);
slave2.DataStore.InputRegisters.WritePoints(0, v);
}
}
}
NModbus库的读写方法是基于数组的,这样也变相解决int32,float等数据写入时并发读可以能导致的数据更新异常。 实际应用中,可以读完一个仪表的数据,然后分类(bool和其他,其他包括word、int、float等)写入,同类的一次更新完,使用也比较方便。
用Modscan32测试,Device Id分别使用1和2,可以看到数据明显不同。
需要注意的是,NModbus的地址是从0开始,而NModbus4的地址是从1开始。
相关连接: