C#使用NModbus4读写Modbus数据

   Modbus是一个免费的协议,协议设计简单,有很多成熟的库支持。比如C#版本的NModubs4就很好,入门简单,使用方便。

首先,在工程中使用NuGet添加NModbus4的包。

在使用文件中,添加引用。不同的接口模式,引用对象不同,Modbus Slave TCP模型需要以下几项:

using System.Net;
using System.Net.Sockets;

using Modbus.Data;
using Modbus.Device;

初始化大概有几个步骤:创建TCP Listener对象、创建ModbusTcpSalve对象、启动侦听服务。

  TcpListener listener = new TcpListener(IPAddress.Parse("0.0.0.0"), 502);
  listener.Start();
  ModbusTcpSlave modbusSlave = ModbusTcpSlave.CreateTcp(1, listener);
  //创建寄存器存储对象
  modbusSlave.DataStore = DataStoreFactory.CreateDefaultDataStore();

Modbus有个DataStore对象,用来存储数据,对应的状态的地址如下:

//01 Coil Status, Addr: 00001
ModbusDataCollection coilDiscretes = modbusSlave.DataStore.InputDiscretes;

//02 Input Status, Addr: 10001
ModbusDataCollection inputDiscretes = modbusSlave.DataStore.CoilDiscretes;

//03 Holding Register, Addr: 40001
ModbusDataCollection holdingRegisters = modbusSlave.DataStore.HoldingRegisters;

//04 Input Register, Addr: 30001
ModbusDataCollection InputRegisters = modbusSlave.DataStore.InputRegisters;

定义之后,就可以直接通过这些对象读写数据了。

NModbus4库已经封装了对于TCP访问数据的封装,服务端只需要维护数据更新即可。

受Modbus协议限制,HoldingRegisters和InputRegisters每个地址仅16位2个字节长度。当实际数据值超过2个字节时,需要占用多个地址空间。比如int32,float都需要4个字节,两个地址。这些数据怎么存放,高低位怎么对齐,就产生了所谓的ABCD、CDAB等转换,这个Master与Slave一致就可以。

Int32等类型数据更新时,需要同时对多个存储地址进行更新,而master可能还在高速并发读数据,需要注意使用一个同步锁,避免数据更新一半就被读取,产生数据不一致问题。

        //将float类型分解成两个ushort类型
        public void SetValue32(ModbusDataCollectiondata,int offset, float value)
        {
            lock (modbusSlave.DataStore.SyncRoot)
            {
                data[offset] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 0); 
                data[offset + 1] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 2); 
            }
        }
        //将int32类型分解成两个ushort类型
        public void SetValue32(ModbusDataCollection data, int offset, Int32 value)
        {
            lock (modbusSlave.DataStore.SyncRoot)
            {
                data[offset] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 0);
                data[offset + 1] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 2);
            }
        }

Modbus对于字符串,并没有明确约定。推进使用Unicode编码,首先是与OPC的默认字符串编码格式一致,其次的每个中英文都占用一个地址2个字节,方便计算长度。

        public void SetValueString(ModbusDataCollection data, int offset, string value)
        {
            const int maxStringLen = 20;
            lock (modbusSlave.DataStore.SyncRoot)
            {

                byte[] dst = new byte[appConfigModbus.StringLen * 2];
                byte[] bb = Encoding.Unicode.GetBytes(value);
                for (int i = 0; i < bb.Length && i < dst.Length; i++)
                {
                    dst[i] = bb[i];
                }
                for (int i = 0; i < maxStringLen; i += 2)
                {
                    data[offset + i / 2] = BitConverter.ToUInt16(dst, i);
                }
            }
        }

你可能感兴趣的:(IoT,编程,c#,开发语言,网络协议,驱动开发)