C#工控机作为Modbus从站的方法

        工作需要实现HMI作为Modbus主站,工控机作为modbus从站。在网上找了一些资料,但多数都是使用工控机作为主站的方案,于是自己根据一些网上的说明,再加上一些摸索,实现了工控机作为从站的方法,在这里给大家分享一下。

        首先,工控机作为从站的话,是没有办法去读写主站的,也就是说,工控机端只能读取HMI写进来的数据,或者把数据写如到存储区,等待HMI来读取。这里使用的工具有虚拟串口,modbuspoll,modbusslave,打包下载在这里:

https://download.csdn.net/download/gaooolianggg/12147467

        虚拟串口中添加好端口后,开启modbus poll,因为此时还没有启动从站程序,所以会报time out 的错误,这个先无所谓。

        接下来进入到正题,使用C#建立从站。我们使用的NModbus。NModbus的安装很简单,直接在NuGet包管理中搜索NModbus即可,也可以进入到NModbus的github主页,下载源码自己编译。这里建议从Github下载源码,在NModbus项目中的samples工程里,有很多使用示例,本文所列举的使用方法也是从示例中找到的。如果你想直接使用的话,那么从NuGet安装了NModbus后,直接调用以下方法即可。

        我的测试工程可以从这里下载,其中主要是开源samples,我自己测试用的工程为myTest,开发工具为vs2019社区版。希望可以帮助到有需要的人,如果有问题可以联系我[email protected]

代码下载链接

        private const string PrimarySerialPortName = "COM1";
        private const string SecondarySerialPortName = "COM2";


        public async Task StartModbusSerialRtuSlaveWithCustomStore()
        {

            using (SerialPort slavePort = new SerialPort(PrimarySerialPortName))
            {
                // configure serial port
                slavePort.BaudRate = 9600;
                slavePort.DataBits = 8;
                slavePort.Parity = Parity.None;
                slavePort.StopBits = StopBits.One;
                slavePort.Open();

                var factory = new ModbusFactory();
                var slaveNetwork = factory.CreateRtuSlaveNetwork(slavePort);

                var dataStore = new SlaveStorage();
                dataStore.HoldingRegisters.ReadPoints(0, 10);
                ushort[] d = new ushort[3]{ 3, 4, 5 };
                dataStore.HoldingRegisters.WritePoints(0, d);
                dataStore.CoilDiscretes.StorageOperationOccurred += (sender, args) => textBox1.Invoke(new Action(()=> textBox1.AppendText($"Coil discretes: {args.Operation} starting at {args.StartingAddress},num {args.Points.Length} + from task "+Task.CurrentId+Environment.NewLine)));
                dataStore.CoilInputs.StorageOperationOccurred += (sender, args) => textBox1.Invoke(new Action(() => textBox1.AppendText($"Coil inputs: {args.Operation} starting at {args.StartingAddress},num {args.Points.Length}" + Environment.NewLine)));
                dataStore.InputRegisters.StorageOperationOccurred += (sender, args) => textBox1.Invoke(new Action(() => textBox1.AppendText($"Input registers: {args.Operation} starting at {args.StartingAddress},num {args.Points.Length}" + Environment.NewLine)));
                dataStore.HoldingRegisters.StorageOperationOccurred += (sender, args) => textBox1.Invoke(new Action(() => textBox1.AppendText($"Holding registers: {args.Operation} starting at {args.StartingAddress},num {args.Points.Length} + from task " + Task.CurrentId + Environment.NewLine)));
                IModbusSlave slave1 = factory.CreateSlave(1, dataStore);

                slaveNetwork.AddSlave(slave1);

                await slaveNetwork.ListenAsync();
            }
        }
using NModbus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


    namespace myTest
{

        public class SlaveStorage : ISlaveDataStore
        {
            private readonly SparsePointSource _coilDiscretes;
            private readonly SparsePointSource _coilInputs;
            private readonly SparsePointSource _holdingRegisters;
            private readonly SparsePointSource _inputRegisters;

            public SlaveStorage()
            {
                _coilDiscretes = new SparsePointSource();
                _coilInputs = new SparsePointSource();
                _holdingRegisters = new SparsePointSource();
                _inputRegisters = new SparsePointSource();
            }

            public SparsePointSource CoilDiscretes
            {
                get { return _coilDiscretes; }
            }

            public SparsePointSource CoilInputs
            {
                get { return _coilInputs; }
            }

            public SparsePointSource HoldingRegisters
            {
                get { return _holdingRegisters; }
            }

            public SparsePointSource InputRegisters
            {
                get { return _inputRegisters; }
            }

            IPointSource ISlaveDataStore.CoilDiscretes
            {
                get { return _coilDiscretes; }
            }

            IPointSource ISlaveDataStore.CoilInputs
            {
                get { return _coilInputs; }
            }

            IPointSource ISlaveDataStore.HoldingRegisters
            {
                get { return _holdingRegisters; }
            }

            IPointSource ISlaveDataStore.InputRegisters
            {
                get { return _inputRegisters; }
            }
        }

        /// 
        /// Sparse storage for points.
        /// 
        public class SparsePointSource : IPointSource
        {
            private readonly Dictionary _values = new Dictionary();

            public event EventHandler> StorageOperationOccurred;

            /// 
            /// Gets or sets the value of an individual point wih tout 
            /// 
            /// 
            /// 
            public TPoint this[ushort registerIndex]
            {
                get
                {
                    TPoint value;

                    if (_values.TryGetValue(registerIndex, out value))
                        return value;

                    return default(TPoint);
                }
                set { _values[registerIndex] = value; }
            }

            public TPoint[] ReadPoints(ushort startAddress, ushort numberOfPoints)
            {
                var points = new TPoint[numberOfPoints];

                for (ushort index = 0; index < numberOfPoints; index++)
                {
                    points[index] = this[(ushort)(index + startAddress)];
                }

                StorageOperationOccurred?.Invoke(this,
                    new StorageEventArgs(PointOperation.Read, startAddress, points));

                return points;
            }

            public void WritePoints(ushort startAddress, TPoint[] points)
            {
                for (ushort index = 0; index < points.Length; index++)
                {
                    this[(ushort)(index + startAddress)] = points[index];
                }

                StorageOperationOccurred?.Invoke(this,
                    new StorageEventArgs(PointOperation.Write, startAddress, points));
            }
        }

        public class StorageEventArgs : EventArgs
        {
            private readonly PointOperation _pointOperation;
            private readonly ushort _startingAddress;
            private readonly TPoint[] _points;

            public StorageEventArgs(PointOperation pointOperation, ushort startingAddress, TPoint[] points)
            {
                _pointOperation = pointOperation;
                _startingAddress = startingAddress;
                _points = points;
            }

            public ushort StartingAddress
            {
                get { return _startingAddress; }
            }

            public TPoint[] Points
            {
                get { return _points; }
            }

            public PointOperation Operation
            {
                get { return _pointOperation; }
            }
        }

        public enum PointOperation
        {
            Read,

            Write
        }


    }

你可能感兴趣的:(C#,modbus,C#,工控机做从站,NModbus)