NModbus4是一个比较好用的c#版modbus库,既实现了client也实现了Server端(slave)。
可以用其实现一个modbus服务器。注意不是NModbus。这不是一个库。
源码位于 https://github.com/NModbus4/NModbus4
参考:https://github.com/NModbus4/NModbus4/blob/portable-3.0/Samples/Program.cs 中的实现
_slaveId是设备的id,一般默认是1
_dataStore是存储Modbus数据的对象,可以调用内部函数创建。
_dataStore = DataStoreFactory.CreateDefaultDataStore();
try
{
_ip = new IPAddress(new byte[] {0,0,0,0}); //new IPAddress(new byte[] { 127, 0, 0, 1 });
_listener = new TcpListener(_ip, _port);
_modbusSlave = ModbusTcpSlave.CreateTcp(_slaveId, _listener);
_modbusSlave.DataStore = _dataStore;
_modbusSlave.ModbusSlaveRequestReceived += requestReceiveHandler;
_thread = new Thread(_modbusSlave.Listen) { Name = _port.ToString() };
_thread.Start();
_status = "服务运行中";
_isRunning = true;
}
catch(Exception)
{
string errorStr = "[" + _name + "]" + "风机启动失败";
MessageBox.Show(errorStr, "出错了", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
执行Dispose()命令就可以,线程停止就可以了。
_modbusSlave.Dispose();
_thread.Abort();
modbus服务器的数据都存储在 _dataStore 中,一般常用的是组3和组4
switch(groupindex)
{
case 3: return _dataStore.HoldingRegisters; //可修改
case 4: return _dataStore.InputRegisters; //不可通过modbus修改
default: return _dataStore.InputRegisters;
}
modbus协议的地址比实际地址多1,_dataStore的地址从1开始,如果写0地址会出异常。
modbus协议中以寄存器为单位,一个寄存器是16位,如果一次要设置int32的值,需要分别对应到2个寄存器上。
public void setValue32(int groupindex, int offset, int value)
{
byte[] valueBuf = BitConverter.GetBytes(value);
ushort lowOrderValue = BitConverter.ToUInt16(valueBuf, 0);
ushort highOrderValue = BitConverter.ToUInt16(valueBuf, 2);
ModbusDataCollection data = getRegisterGroup(groupindex);
data[offset] = lowOrderValue;
data[offset + 1] = highOrderValue;
}
ModbusDataCollection getRegisterGroup(int groupindex)//根据3或4返回适合的寄存器
{
switch(groupindex)
{
case 3: return _dataStore.HoldingRegisters; //可修改
case 4: return _dataStore.InputRegisters; //不可通过modbus修改
default: return _dataStore.InputRegisters;
}
}
_modbusSlave.Dispose();在服务器工作中可能会出异常,解决办法是修改源码。
修改ModbusMasterTcpConnection.cs中CatchExceptionAndRemoveMasterEndPoint函数
把throw注释掉。
if (!(ex is IOException || ex is FormatException || ex is ObjectDisposedException))
{
//throw;
}
附上一份完整的源码:
https://github.com/alongL/modbusPlcSimulator