美文网首页.NET
.NET Modbus Server、Client寄存器读写

.NET Modbus Server、Client寄存器读写

作者: 老中医167788 | 来源:发表于2024-07-04 17:51 被阅读0次

    引入NModbus

    dotnet add package NModbus --version 3.0.81
    

    Program.cs

    using IOT.Common;
    using NModbus;
    using System.Net.Sockets;
    using System.Net;
    
    
    var dataStore = ModbusSlaveDataStore.Instance;
    _ = Task.Run(() => {
        StartListen(dataStore);
    });
    await Task.Delay(1000);
    
    // 循环写入点位值
    _ = Task.Run(async () =>
    {
        do
        {
            ushort startAddr = 0;
    
            var f1 = Random.Shared.Next(1, 500) * 2.25;
            WriteFloatPoints(dataStore.InputRegisters, startAddr, (float)f1);
    
            var f2 = (ushort)Random.Shared.Next(1, 999);
            dataStore.InputRegisters.WritePoints((ushort)(startAddr + 2), [f2]);
    
            await Task.Delay(500);
        } while (true);
    });
    
    
    // 一秒读取一次点位值
    List<string> nodes = [
        "1,0,2","1,2,1"
        ];
    do
    {
        var values = await ModbusTcpHelper.Instance.ReadModbusTcpServer("localhost", nodes);
        foreach (var (k, v) in values)
        {
            if (v.Contains(","))
            {
                var arr = v.Split(",");
                var low = ushort.Parse(arr[0]);
                var high = ushort.Parse(arr[1]);
                var floatValue = ReadFloatPoint(low, high);
                Console.WriteLine($"{k}: {floatValue}");
            }
            else
            {
                Console.WriteLine($"{k}: {v}");
            }
        }
        await Task.Delay(1000);
    } while (true);
    
    
    
    void WriteFloatPoints(IPointSource<ushort> left, ushort startAddress, float value)
    {
        var bytes = BitConverter.GetBytes(value);
        ushort lowOrderValue = BitConverter.ToUInt16(bytes, 0);
        ushort highOrderValue = BitConverter.ToUInt16(bytes, 2);
        ushort[] registers = [lowOrderValue, highOrderValue];
        left.WritePoints(startAddress, registers);
    }
    
    float ReadFloatPoint(ushort low,ushort high)
    {
        var bytes = new byte[4];
        BitConverter.GetBytes(low).CopyTo(bytes, 0);
        BitConverter.GetBytes(high).CopyTo(bytes, 2);
        float value = BitConverter.ToSingle(bytes, 0);
        return value;
    }
    
    void StartListen(ModbusSlaveDataStore slaveDataStore)
    {
        // 创建TCP监听器
        int port = 502;
        TcpListener tcpListener = new TcpListener(IPAddress.Any, port);
        tcpListener.Start();
    
        // 创建Modbus工厂
        IModbusFactory modbusFactory = new ModbusFactory();
    
        // 创建服务器网络流
        var modbusSlaveNetwork = modbusFactory.CreateSlaveNetwork(tcpListener);
    
        // 添加从站ID 1
        var slave = modbusFactory.CreateSlave(1, slaveDataStore);
        modbusSlaveNetwork.AddSlave(slave);
    
        // 启动Modbus服务器
        modbusSlaveNetwork.ListenAsync();
    
        // 打印启动信息
        Console.WriteLine($"Modbus TCP Server is listening on port {port}");
        Console.ReadKey();
    
        // 停止服务器
        tcpListener.Stop();
    }
    
    public class ModbusSlaveDataStore : ISlaveDataStore
    {
        private static readonly object _lock = new object();
        private static ModbusSlaveDataStore? _instance;
        public static ModbusSlaveDataStore Instance
        {
            get
            {
                lock (_lock)
                {
                    _instance = _instance ??= new ModbusSlaveDataStore();
                    return _instance;
                }
            }
        }
    
        private readonly ushort[] _holdingRegisters = new ushort[100];
        private readonly ushort[] _inputRegisters = new ushort[100];
        private readonly bool[] _coilDiscretes = new bool[100];
        private readonly bool[] _inputDiscretes = new bool[100];
    
        public IPointSource<bool> CoilDiscretes => new DiscretePointSource(_coilDiscretes);
    
        public IPointSource<bool> CoilInputs => new DiscretePointSource(_inputDiscretes);
    
        public IPointSource<ushort> HoldingRegisters => new RegisterPointSource(_holdingRegisters);
    
        public IPointSource<ushort> InputRegisters => new RegisterPointSource(_inputRegisters);
    
        private class RegisterPointSource : IPointSource<ushort>
        {
            private readonly ushort[] _registers;
            public RegisterPointSource(ushort[] registers) => _registers = registers;
    
            public ushort[] ReadPoints(ushort startAddress, ushort numberOfPoints)
            {
                ushort[] points = new ushort[numberOfPoints];
                Array.Copy(_registers, startAddress, points, 0, numberOfPoints);
                return points;
            }
    
            public void WritePoints(ushort startAddress, ushort[] values)
            {
                Array.Copy(values, 0, _registers, startAddress, values.Length);
            }
        }
    
    
        private class DiscretePointSource : IPointSource<bool>
        {
            private readonly bool[] _discretes;
            public DiscretePointSource(bool[] discretes) => _discretes = discretes;
    
            public bool[] ReadPoints(ushort startAddress, ushort numberOfPoints)
            {
                bool[] points = new bool[numberOfPoints];
                Array.Copy(_discretes, startAddress, points, 0, numberOfPoints);
                return points;
            }
    
            public void WritePoints(ushort startAddress, bool[] values)
            {
                Array.Copy(values, 0, _discretes, startAddress, values.Length);
            }
        }
    }
    

    ModbusTcpHelper.cs

    using NModbus;
    using NModbus.Device;
    using NModbus.IO;
    using Serilog;
    using System.Net.Sockets;
    
    namespace IOT.Common;
    
    /// <summary>
    /// 单例
    /// </summary>
    public class ModbusTcpHelper
    {
        static readonly object _lock = new object();
        private static ModbusTcpHelper? _instance;
        public static ModbusTcpHelper Instance
        {
            get
            {
                lock (_lock)
                {
                    _instance = _instance ?? new ModbusTcpHelper();
                    return _instance;
                }
            }
        }
    
        public async Task<Dictionary<string, string>> ReadModbusTcpServer(string ipAddress, List<string> attrIds, int port = 502)
        {
            Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
            try
            {
                // 创建Modbus TCP客户端
                TcpClient tcpClient = new TcpClient(ipAddress, port);
                IStreamResource streamResource = new TcpClientAdapter(tcpClient);
                ModbusIpTransport transport = new ModbusIpTransport(streamResource, new ModbusFactory(), new CustomModbusLogger());
                // 创建 Modbus TCP 主站实例
                ModbusIpMaster master = new ModbusIpMaster(transport);
                try
                {
                    Log.Information($"attrIds Value: " + string.Join(",", attrIds));
                    foreach (var attrId in attrIds)
                    {
                        var attrIdArr = attrId.Split(",");
                        if (attrIdArr.Length > 2) {
                            ///从站地址
                            byte slaveId = byte.Parse(attrIdArr[0]);
                            // 寄存器起始地址
                            ushort startAddress = Convert.ToUInt16(attrIdArr[1], 16); // 注意这里是16进制
                            // 寄存器地址长度
                            ushort numOfPoints = ushort.Parse(attrIdArr[2]);
                            // 读取 DI3 对应的寄存器值
                            ushort[] inputs = master.ReadInputRegisters(slaveId, startAddress, numOfPoints);
                            Log.Information($"{nameof(ModbusTcpHelper)}: {startAddress} read is {string.Join(",", inputs)}");
                            keyValuePairs.Add(attrId.ToString(),string.Join(',',inputs));
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.Error($"{nameof(ModbusTcpHelper)}: [{ipAddress}] {ex}");
                }
                finally
                {
                    // 关闭连接
                    tcpClient.Close();
                    master.Dispose();
                }
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(ModbusTcpHelper)}: [{ipAddress}] {ex}");
            }
            return keyValuePairs;
        }
    }
    
    public class CustomModbusLogger : IModbusLogger
    {
        public bool ShouldLog(LoggingLevel level)
        {
            return true;
        }
    
        void IModbusLogger.Log(LoggingLevel level, string message)
        {
            if(level !=  LoggingLevel.Error)return;
    
            Log.Error($"{nameof(ModbusTcpHelper)}: {message}");
            //Console.WriteLine($"Function Code: {level}, Data: {message}");
        }
    }
    

    Preview

    image.png

    相关文章

      网友评论

        本文标题:.NET Modbus Server、Client寄存器读写

        本文链接:https://www.haomeiwen.com/subject/cnxwcjtx.html