Ver Fonte

20250915003 ModelBusTCP通讯工具添加

向羽 孟 há 3 semanas atrás
pai
commit
313398e297

+ 496 - 0
MvvmScaffoldFrame48.DLL/CommunicationTools/ModbusTcpClient.cs

@@ -0,0 +1,496 @@
+using NModbus;
+using System;
+using System.Net.Sockets;
+
+namespace MvvmScaffoldFrame48.DLL.CommunicationTools
+{
+    public class ModbusTcpClient
+    {
+        #region 实例
+        private TcpClient _tcpClient;
+        private IModbusMaster _modbusMaster;
+        #endregion
+
+        #region 连接方法
+
+        /// <summary>
+        /// 判断 TCP 连接是否已断开
+        /// </summary>
+        /// <returns></returns>
+        public bool IsTcpClientConnected()
+        {
+            if (_tcpClient == null || _tcpClient.Client == null)
+                return false;
+            try
+            {
+                Socket socket = _tcpClient.Client;
+                bool isReadable = socket.Poll(0, SelectMode.SelectRead);
+                bool hasNoData = (socket.Available == 0);
+
+                // 可读且无数据 = 连接已断开
+                return !(isReadable && hasNoData);
+            }
+            catch (SocketException) { return false; }
+            catch (ObjectDisposedException) { return false; }
+        }
+
+        /// <summary>
+        /// 连接 Modbus TCP 服务器
+        /// </summary>
+        /// <param name="ipAddress"></param>
+        /// <param name="port"></param>
+        /// <returns></returns>
+        public bool Connect(string ipAddress, int port = 502)
+        {
+            try
+            {
+                _tcpClient = new TcpClient(ipAddress, port)
+                {
+                    SendTimeout = 2000,
+                    ReceiveTimeout = 2000
+                };
+                // 使用 ModbusFactory 创建 Master(新版本 API)
+                var factory = new ModbusFactory();
+                _modbusMaster = factory.CreateMaster(_tcpClient);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"连接失败: {ex.Message}");
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 断开连接
+        /// </summary>
+        public void Disconnect()
+        {
+            _modbusMaster?.Dispose();
+            _tcpClient?.Close();
+        }
+        #endregion
+
+        #region 读取方法
+        /// <summary>
+        /// 读取线圈(功能码01)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="startAddress"></param>
+        /// <param name="numRegisters"></param>
+        /// <returns></returns>
+        /// <exception cref="InvalidOperationException"></exception>
+        public bool[] ReadCoilsRegister(byte slaveId, ushort startAddress, ushort numRegisters)
+        {
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-ReadCoilsRegister failed:未连接到服务器");
+                return null;
+            }
+            try
+            {
+                return _modbusMaster.ReadCoils(slaveId, startAddress, numRegisters);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"读取线圈失败,ModbusTcpClient-ReadCoilsRegister failed: {ex.Message}");
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 读取保持寄存器(功能码03)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="startAddress"></param>
+        /// <param name="numRegisters"></param>
+        /// <returns></returns>
+        /// <exception cref="InvalidOperationException"></exception>
+        public ushort[] ReadHoldingRegisters(byte slaveId, ushort startAddress, ushort numRegisters)
+        {
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-ReadHoldingRegistersAsReal failed:未连接到服务器");
+                return null;
+            }
+            try
+            {
+                return _modbusMaster.ReadHoldingRegisters(slaveId, startAddress, numRegisters);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"读取保持寄存器失败,ModbusTcpClient-ReadHoldingRegisters failed: {ex.Message}");
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 读取保持寄存器中的REAL值(功能码03)
+        /// </summary>
+        /// <param name="slaveId">从站ID</param>
+        /// <param name="startAddress">起始地址</param>
+        /// <param name="count">REAL值的数量</param>
+        /// <param name="byteOrder">字节序 (ABCD, CDAB, BADC, DCBA)</param>
+        /// <returns>REAL值数组</returns>
+        public float[] ReadHoldingRegistersAsReal(byte slaveId, ushort startAddress, ushort count, string byteOrder = "BADC")
+        {
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-ReadHoldingRegistersAsReal failed:未连接到服务器");
+                return null;
+            }
+
+            try
+            {
+                // 每个REAL值占用2个寄存器
+                ushort[] registers = _modbusMaster.ReadHoldingRegisters(slaveId, startAddress, (ushort)(count * 2));
+                float[] realValues = new float[count];
+
+                for (int i = 0; i < count; i++)
+                {
+                    ushort highRegister = registers[i * 2];
+                    ushort lowRegister = registers[i * 2 + 1];
+
+                    byte[] bytes = ConvertToByteArray(lowRegister, highRegister, byteOrder);
+                    realValues[i] = BitConverter.ToSingle(bytes, 0);
+                }
+
+                return realValues;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"读取REAL值失败,ModbusTcpClient-ReadHoldingRegistersAsReal failed:{ex.Message}");
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 读取保持寄存器中的Int32值(功能码03)
+        /// </summary>
+        /// <param name="slaveId">从站ID</param>
+        /// <param name="startAddress">起始地址</param>
+        /// <param name="count">REAL值的数量</param>
+        /// <returns>REAL值数组</returns>
+        public UInt32[] ReadHoldingRegistersAsInt32(byte slaveId, ushort startAddress, ushort count, string byteOrder = "BADC")
+        {
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-ReadHoldingRegistersAsInt32 failed:未连接到服务器");
+                return null;
+            }
+
+            try
+            {
+                // 每个REAL值占用2个寄存器
+                ushort[] registers = _modbusMaster.ReadHoldingRegisters(slaveId, startAddress, (ushort)(count * 2));
+                UInt32[] realValues = new UInt32[count];
+
+                for (int i = 0; i < count; i++)
+                {
+                    // 获取两个连续的寄存器值
+                    ushort highRegister = registers[i * 2];
+                    ushort lowRegister = registers[i * 2 + 1];
+
+
+                    byte[] bytes = ConvertToByteArray(lowRegister, highRegister, byteOrder);
+
+                    // 转换为float
+                    realValues[i] = (UInt32)BitConverter.ToInt32(bytes, 0);
+                }
+
+                return realValues;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"读取Int32值失败: {ex.Message}");
+                return null;
+            }
+        }
+        #endregion
+
+        #region 写入方法
+        /// <summary>
+        /// 写入线圈(功能码05)
+        /// </summary>
+        /// <param name="slaveId">Slave编号</param>
+        /// <param name="CoilsAddress">写入地址</param>
+        /// <param name="values">写入值</param>
+        /// <exception cref="InvalidOperationException"></exception>
+        public bool WriteCoilsRegister(byte slaveId, ushort CoilsAddress, bool values)
+        {
+            bool result = false;
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-WriteCoilsRegister failed:未连接到服务器");
+                result = false;
+            }
+            try
+            {
+                _modbusMaster.WriteSingleCoil(slaveId, CoilsAddress, values);
+                result = true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"ModbusTcpClient-WriteCoilsRegister-WriteCoilsRegister failed:{ex.Message}");
+                result = false;
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 写入单个寄存器(功能码06)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="registerAddress"></param>
+        /// <param name="value"></param>
+        /// <exception cref="InvalidOperationException"></exception>
+        public bool WriteSingleRegister(byte slaveId, ushort registerAddress, ushort value)
+        {
+            bool result = false;
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-WriteSingleRegister failed:未连接到服务器");
+                result = false;
+                return result;
+            }
+            try
+            {
+                _modbusMaster.WriteSingleRegister(slaveId, registerAddress, value);
+                result = true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"写入单个寄存器失败,ModbusTcpClient-WriteSingleRegister failed:{ex.Message}");
+                result = false;
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 写入多个寄存器(功能码16)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="startAddress"></param>
+        /// <param name="values"></param>
+        /// <exception cref="InvalidOperationException"></exception>
+        public bool WriteMultipleRegisters(byte slaveId, ushort startAddress, ushort[] values)
+        {
+            bool result = false;
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-WriteMultipleRegisters failed:未连接到服务器");
+                return false;
+            }
+            try
+            {
+                _modbusMaster.WriteMultipleRegisters(slaveId, startAddress, values);
+                result = true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"写入多个寄存器失败,ModbusTcpClient-WriteMultipleRegisters failed:{ex.Message}");
+                result = false;
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 写入单个REAL值到保持寄存器(功能码16)
+        /// </summary>
+        /// <param name="slaveId">从站ID</param>
+        /// <param name="startAddress">起始地址</param>
+        /// <param name="value">REAL值</param>
+        /// <param name="byteOrder">字节序 (ABCD, CDAB, BADC, DCBA)</param>
+        public bool WriteSingleReal(byte slaveId, ushort startAddress, float value, string byteOrder = "BADC")
+        {
+            bool result = false;
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-WriteSingleReal failed:未连接到服务器");
+                return false;
+            }
+            try
+            {
+                // 将float转换为字节数组
+                byte[] bytes = BitConverter.GetBytes(value);
+
+                // 根据字节序重新排列字节
+                ushort[] registers = ConvertBytesToRegisters(bytes, byteOrder);
+
+                // 写入连续的寄存器
+                result = WriteMultipleRegisters(slaveId, startAddress, registers);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"写入REAL值失败,ModbusTcpClient-WriteSingleReal failed:{ex.Message}");
+                result = false;
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 写入多个REAL值到保持寄存器(功能码16)
+        /// </summary>
+        /// <param name="slaveId">从站ID</param>
+        /// <param name="startAddress">起始地址</param>
+        /// <param name="values">REAL值数组</param>
+        /// <param name="byteOrder">字节序 (ABCD, CDAB, BADC, DCBA)</param>
+        public bool WriteMultipleReals(byte slaveId, ushort startAddress, float[] values, string byteOrder = "BADC")
+        {
+            bool result = false;
+            if (_modbusMaster == null)
+            {
+                Console.WriteLine($"ModbusTcpClient-WriteMultipleReals failed:未连接到服务器");
+                return false;
+            }
+            if (values == null || values.Length == 0)
+            {
+                Console.WriteLine("写入多个REAL值到保持寄存器-值数组不能为空", 0);
+                return false;
+            }
+
+            try
+            {
+                // 每个REAL值需要2个寄存器,所以总寄存器数是REAL值数量的2倍
+                ushort[] registers = new ushort[values.Length * 2];
+
+                for (int i = 0; i < values.Length; i++)
+                {
+                    // 将每个float转换为字节数组
+                    byte[] bytes = BitConverter.GetBytes(values[i]);
+
+                    // 根据字节序转换为寄存器值
+                    ushort[] regPair = ConvertBytesToRegisters(bytes, byteOrder);
+
+                    // 将寄存器值放入数组
+                    registers[i * 2] = regPair[0];
+                    registers[i * 2 + 1] = regPair[1];
+                }
+
+                // 写入所有寄存器
+                _modbusMaster.WriteMultipleRegisters(slaveId, startAddress, registers);
+                result = true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"写入多个REAL值失败: {ex.Message}");
+                result = false;
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 写入单个Int32值到保持寄存器(功能码16)
+        /// </summary>
+        /// <param name="slaveId">从站ID</param>
+        /// <param name="startAddress">起始地址</param>
+        /// <param name="value">REAL值</param>
+        /// <param name="byteOrder">字节序 (ABCD, CDAB, BADC, DCBA)</param>
+        public bool WriteSingleInt32(byte slaveId, ushort startAddress, UInt32 value, string byteOrder = "BADC")
+        {
+            // 将32位整数拆分为两个16位寄存器值
+            byte[] bytes = BitConverter.GetBytes(value);
+            ushort[] registers = new ushort[2];
+
+            ushort[] regPair = ConvertBytesToRegisters(bytes, byteOrder);
+
+            // 将寄存器值放入数组
+            registers[0] = regPair[0];
+            registers[1] = regPair[1];
+
+            return WriteMultipleRegisters(slaveId, startAddress, registers);
+        }
+        #endregion
+
+        #region 辅助方法
+        /// <summary>
+        /// 将寄存器数组换为字节数组转(根据指定字节序)
+        /// </summary>
+        /// <param name="lowRegister">低位寄存器</param>
+        /// <param name="highRegister">高位寄存器</param>
+        /// <param name="byteOrder">字节序</param>
+        /// <returns>字节数组</returns>
+        private byte[] ConvertToByteArray(ushort lowRegister, ushort highRegister, string byteOrder)
+        {
+            byte[] bytes = new byte[4];
+
+            switch (byteOrder.ToUpper())
+            {
+                case "ABCD": // 大端序
+                    bytes[0] = (byte)(highRegister >> 8);
+                    bytes[1] = (byte)(highRegister & 0xFF);
+                    bytes[2] = (byte)(lowRegister >> 8);
+                    bytes[3] = (byte)(lowRegister & 0xFF);
+                    break;
+                case "CDAB": // 小端序
+                    bytes[0] = (byte)(lowRegister >> 8);
+                    bytes[1] = (byte)(lowRegister & 0xFF);
+                    bytes[2] = (byte)(highRegister >> 8);
+                    bytes[3] = (byte)(highRegister & 0xFF);
+                    break;
+                case "BADC":
+                    bytes[0] = (byte)(highRegister & 0xFF);
+                    bytes[1] = (byte)(highRegister >> 8);
+                    bytes[2] = (byte)(lowRegister & 0xFF);
+                    bytes[3] = (byte)(lowRegister >> 8);
+                    break;
+                case "DCBA":
+                    bytes[0] = (byte)(lowRegister & 0xFF);
+                    bytes[1] = (byte)(lowRegister >> 8);
+                    bytes[2] = (byte)(highRegister & 0xFF);
+                    bytes[3] = (byte)(highRegister >> 8);
+                    break;
+                default:
+                    // 默认使用ABCD顺序
+                    bytes[0] = (byte)(highRegister >> 8);
+                    bytes[1] = (byte)(highRegister & 0xFF);
+                    bytes[2] = (byte)(lowRegister >> 8);
+                    bytes[3] = (byte)(lowRegister & 0xFF);
+                    break;
+            }
+            return bytes;
+        }
+
+        /// <summary>
+        /// 将字节数组转换为寄存器数组(根据指定字节序)
+        /// </summary>
+        /// <param name="bytes">字节数组(4字节)</param>
+        /// <param name="byteOrder">字节序</param>
+        /// <returns>寄存器数组(2个ushort)</returns>
+        private ushort[] ConvertBytesToRegisters(byte[] bytes, string byteOrder)
+        {
+            if (bytes.Length != 4)
+                throw new ArgumentException("字节数组必须包含4个字节用于REAL值转换");
+
+            ushort[] registers = new ushort[2];
+
+            switch (byteOrder.ToUpper())
+            {
+                case "ABCD": // 大端序
+                    registers[0] = (ushort)((bytes[0] << 8) | bytes[1]); // 高位寄存器
+                    registers[1] = (ushort)((bytes[2] << 8) | bytes[3]); // 低位寄存器
+                    break;
+                case "CDAB": // 小端序
+                    registers[0] = (ushort)((bytes[2] << 8) | bytes[3]); // 高位寄存器
+                    registers[1] = (ushort)((bytes[0] << 8) | bytes[1]); // 低位寄存器
+                    break;
+                case "BADC":
+                    registers[0] = (ushort)((bytes[1] << 8) | bytes[0]); // 高位寄存器
+                    registers[1] = (ushort)((bytes[3] << 8) | bytes[2]); // 低位寄存器
+                    break;
+                case "DCBA":
+                    registers[0] = (ushort)((bytes[3] << 8) | bytes[2]); // 高位寄存器
+                    registers[1] = (ushort)((bytes[1] << 8) | bytes[0]); // 低位寄存器
+                    break;
+                default:
+                    // 默认使用ABCD顺序
+                    registers[0] = (ushort)((bytes[0] << 8) | bytes[1]);
+                    registers[1] = (ushort)((bytes[2] << 8) | bytes[3]);
+                    break;
+            }
+            return registers;
+        }
+        #endregion
+
+    }
+}

+ 6 - 0
MvvmScaffoldFrame48.DLL/MvvmScaffoldFrame48.Dll.csproj

@@ -51,6 +51,7 @@
   <ItemGroup>
     <Compile Include="CameraTools\HikCamera.cs" />
     <Compile Include="CameraTools\HikVision.cs" />
+    <Compile Include="CommunicationTools\ModbusTcpClient.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="UserManager.cs" />
   </ItemGroup>
@@ -64,5 +65,10 @@
     <Content Include="DLL\MvCameraControl.Net.dll" />
     <Content Include="DLL\MvFGCtrlC.Net.dll" />
   </ItemGroup>
+  <ItemGroup>
+    <PackageReference Include="NModbus">
+      <Version>3.0.81</Version>
+    </PackageReference>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>

+ 3 - 1
README.md

@@ -4,9 +4,11 @@
         App.xaml(初始界面引导页):主界面开始前的界面,一般无图像。
         MainWindow.xaml(主界面):用于框架测试以及框架演示的主界面
     MvvmScaffoldFrame48.Dll(项目功能逻辑层):用于制作项目的功能逻辑
-        CameraTools(相机工具文件夹):相机相关工具和控制逻辑的存放处
+        CameraTools(相机工具文件夹):相机相关工具的存放处
             HikCamera.cs(海康相机操作类):海康相机操作类,用于对相机的实例化以及控制
             HikVision.cs(海康相机类):海康相机静态类,用于对海康相机的静态操作,如获取相机列表
+        CommunicationTools(通讯工具文件夹):通讯相关工具的存放处
+            ModbusTcpClient.cs(ModbusTcp通讯类):ModbusTcp通讯类,用于对ModbusTcp通讯的实现
         DLL(第三方DLL文件夹):存放第三方DLL文件
         UserManager.cs(用户管理类):用于框架测试以及框架演示的演示类
     MvvmScaffoldFrame48.Model(项目模板层):用于存放项目模板,如:用户模板、相机模板、设备模板等