diff --git a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs index 7cb97d9..4d7d01b 100644 --- a/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs +++ b/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs @@ -1,7 +1,9 @@ using IoTClient.Clients.Modbus; using IoTClient.Enums; using IoTClient.Models; +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Net; using System.Threading.Tasks; using Xunit; @@ -19,6 +21,106 @@ namespace IoTClient.Tests.Modbus client = new ModbusTcpClient(new IPEndPoint(ip, port)); } + [Fact] + public async Task 短连接自动开关() + { + Random rnd = new Random((int)Stopwatch.GetTimestamp()); + for (int i = 0; i < 10; i++) + { + #region 生产随机数 + short short_number = (short)rnd.Next(short.MinValue, short.MaxValue); + ushort ushort_number = (ushort)rnd.Next(ushort.MinValue, ushort.MaxValue); + int int_number = rnd.Next(int.MinValue, int.MaxValue); + uint uint_number = (uint)Math.Abs(rnd.Next(int.MinValue, int.MaxValue)); + long long_number = rnd.Next(int.MinValue, int.MaxValue); + ulong ulong_number = (ulong)Math.Abs(rnd.Next(int.MinValue, int.MaxValue)); + float float_number = rnd.Next(int.MinValue, int.MaxValue) / 100; + double double_number = (double)rnd.Next(int.MinValue, int.MaxValue) / 100; + bool coil = int_number % 2 == 0; + #endregion + + //写入地址:0 值为:short_number 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码) + client.Write("0", short_number, stationNumber, 16); + client.Write("4", ushort_number, stationNumber, 16); + client.Write("8", int_number, stationNumber, 16); + client.Write("12", uint_number, stationNumber, 16); + client.Write("16", long_number, stationNumber, 16); + client.Write("20", ulong_number, stationNumber, 16); + client.Write("24", float_number, stationNumber, 16); + client.Write("28", double_number, stationNumber, 16); + + client.Write("32", coil, stationNumber, 5); + + //写入可能有一定的延时,500毫秒后检验 + await Task.Delay(500); + + //读取地址:0 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码) + var read_short_number = client.ReadInt16("0", stationNumber, 3).Value; + Assert.True(read_short_number == short_number); + Assert.True(client.ReadUInt16("4", stationNumber, 3).Value == ushort_number); + Assert.True(client.ReadInt32("8", stationNumber, 3).Value == int_number); + Assert.True(client.ReadUInt32("12", stationNumber, 3).Value == uint_number); + Assert.True(client.ReadInt64("16", stationNumber, 3).Value == long_number); + Assert.True(client.ReadUInt64("20", stationNumber, 3).Value == ulong_number); + Assert.True(client.ReadFloat("24", stationNumber, 3).Value == float_number); + Assert.True(client.ReadDouble("28", stationNumber, 3).Value == double_number); + + Assert.True(client.ReadCoil("32", stationNumber, 1).Value == coil); + } + } + + [Fact] + public async Task 长连接主动开关() + { + client.Open(); + + Random rnd = new Random((int)Stopwatch.GetTimestamp()); + for (int i = 0; i < 10; i++) + { + #region 生产随机数 + short short_number = (short)rnd.Next(short.MinValue, short.MaxValue); + ushort ushort_number = (ushort)rnd.Next(ushort.MinValue, ushort.MaxValue); + int int_number = rnd.Next(int.MinValue, int.MaxValue); + uint uint_number = (uint)Math.Abs(rnd.Next(int.MinValue, int.MaxValue)); + long long_number = rnd.Next(int.MinValue, int.MaxValue); + ulong ulong_number = (ulong)Math.Abs(rnd.Next(int.MinValue, int.MaxValue)); + float float_number = rnd.Next(int.MinValue, int.MaxValue) / 100; + double double_number = (double)rnd.Next(int.MinValue, int.MaxValue) / 100; + bool coil = int_number % 2 == 0; + #endregion + + //写入地址:0 值为:short_number 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码) + client.Write("0", short_number, stationNumber, 16); + client.Write("4", ushort_number, stationNumber, 16); + client.Write("8", int_number, stationNumber, 16); + client.Write("12", uint_number, stationNumber, 16); + client.Write("16", long_number, stationNumber, 16); + client.Write("20", ulong_number, stationNumber, 16); + client.Write("24", float_number, stationNumber, 16); + client.Write("28", double_number, stationNumber, 16); + + client.Write("32", coil, stationNumber, 5); + + //写入可能有一定的延时,500毫秒后检验 + await Task.Delay(500); + + //读取地址:0 站号:stationNumber 功能码:默认16(也可以自己传入对应的功能码) + var read_short_number = client.ReadInt16("0", stationNumber, 3).Value; + Assert.True(read_short_number == short_number); + Assert.True(client.ReadUInt16("4", stationNumber, 3).Value == ushort_number); + Assert.True(client.ReadInt32("8", stationNumber, 3).Value == int_number); + Assert.True(client.ReadUInt32("12", stationNumber, 3).Value == uint_number); + Assert.True(client.ReadInt64("16", stationNumber, 3).Value == long_number); + Assert.True(client.ReadUInt64("20", stationNumber, 3).Value == ulong_number); + Assert.True(client.ReadFloat("24", stationNumber, 3).Value == float_number); + Assert.True(client.ReadDouble("28", stationNumber, 3).Value == double_number); + + Assert.True(client.ReadCoil("32", stationNumber, 1).Value == coil); + } + + client.Close(); + } + [Fact] public void 批量读取() { @@ -61,91 +163,5 @@ namespace IoTClient.Tests.Modbus }); var result = client.BatchRead(list); } - - /// - /// Modbus值的写入有一定的延时,500毫秒后检验 - /// - /// - [Fact] - public async Task 短连接自动开关() - { - short Number = 33; - client.Write("4", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("4", stationNumber).Value == Number); - - Number = 34; - client.Write("4", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("4", stationNumber).Value == Number); - - Number = 1; - client.Write("12", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("12", stationNumber).Value == 1); - - Number = 0; - client.Write("12", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("12", stationNumber).Value == 0); - - int numberInt32 = -12; - client.Write("4", numberInt32, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt32("4", stationNumber).Value == numberInt32); - - float numberFloat = 112; - client.Write("4", numberFloat, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadFloat("4", stationNumber).Value == numberFloat); - - double numberDouble = 32; - client.Write("4", numberDouble, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadDouble("4", stationNumber).Value == numberDouble); - } - - [Fact] - public async Task 长连接主动开关() - { - client.Open(); - - short Number = 33; - client.Write("4", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("4", stationNumber).Value == Number); - - Number = 34; - client.Write("4", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("4", stationNumber).Value == Number); - - Number = 1; - client.Write("12", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("12", stationNumber).Value == 1); - - Number = 0; - client.Write("12", Number, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt16("12", stationNumber).Value == 0); - - int numberInt32 = -12; - client.Write("4", numberInt32, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadInt32("4", stationNumber).Value == numberInt32); - - float numberFloat = 112; - client.Write("4", numberFloat, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadFloat("4", stationNumber).Value == numberFloat); - - double numberDouble = 32; - client.Write("4", numberDouble, stationNumber); - await Task.Delay(500); - Assert.True(client.ReadDouble("4", stationNumber).Value == numberDouble); - - client.Close(); - } } } diff --git a/IoTClient/Clients/ModBus/ModBusTcpClient.cs b/IoTClient/Clients/ModBus/ModBusTcpClient.cs index be47c01..6dd2f4a 100644 --- a/IoTClient/Clients/ModBus/ModBusTcpClient.cs +++ b/IoTClient/Clients/ModBus/ModBusTcpClient.cs @@ -188,7 +188,7 @@ namespace IoTClient.Clients.Modbus } /// - /// 读取Int16 + /// 读取Int16类型数据 /// /// 寄存器起始地址 /// 站号 @@ -210,13 +210,19 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取Int16类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 ReadInt16(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadInt16(address.ToString(), stationNumber, functionCode); } /// - /// 读取UInt16 + /// 读取UInt16类型数据 /// /// 寄存器起始地址 /// 站号 @@ -238,13 +244,20 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取UInt16类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadUInt16(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadUInt16(address.ToString(), stationNumber, functionCode); } /// - /// 读取Int32 + /// 读取Int32类型数据 /// /// 寄存器起始地址 /// 站号 @@ -266,6 +279,13 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取Int32类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadInt32(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadInt32(address.ToString(), stationNumber, functionCode); @@ -273,7 +293,7 @@ namespace IoTClient.Clients.Modbus /// - /// 读取UInt32 + /// 读取UInt32类型数据 /// /// 寄存器起始地址 /// 站号 @@ -295,13 +315,20 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取UInt32类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadUInt32(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadUInt32(address.ToString(), stationNumber, functionCode); } /// - /// 读取Int64 + /// 读取Int64类型数据 /// /// 寄存器起始地址 /// 站号 @@ -323,13 +350,20 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取Int64类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadInt64(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadInt64(address.ToString(), stationNumber, functionCode); } /// - /// 读取UInt64 + /// 读取UInt64类型数据 /// /// 寄存器起始地址 /// 站号 @@ -351,13 +385,20 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取UInt64类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadUInt64(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadUInt64(address.ToString(), stationNumber, functionCode); } /// - /// 读取Float + /// 读取Float类型数据 /// /// 寄存器起始地址 /// 站号 @@ -379,13 +420,20 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取Float类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadFloat(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadFloat(address.ToString(), stationNumber, functionCode); } /// - /// 读取Double + /// 读取Double类型数据 /// /// 寄存器起始地址 /// 站号 @@ -407,13 +455,20 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取Double类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadDouble(int address, byte stationNumber = 1, byte functionCode = 3) { return ReadDouble(address.ToString(), stationNumber, functionCode); } /// - /// 读取线圈 + /// 读取线圈类型数据 /// /// 寄存器起始地址 /// 站号 @@ -435,17 +490,24 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取线圈类型数据 + /// + /// 寄存器起始地址 + /// 站号 + /// 功能码 + /// public Result ReadCoil(int address, byte stationNumber = 1, byte functionCode = 1) { return ReadCoil(address.ToString(), stationNumber, functionCode); } /// - /// 读取离散 + /// 读取离散类型数据 /// /// 读取地址 - /// - /// + /// 站号 + /// 功能码 /// public Result ReadDiscrete(string address, byte stationNumber = 1, byte functionCode = 2) { @@ -463,6 +525,13 @@ namespace IoTClient.Clients.Modbus return result.EndTime(); } + /// + /// 读取离散类型数据 + /// + /// 读取地址 + /// 站号 + /// 功能码 + /// public Result ReadDiscrete(int address, byte stationNumber = 1, byte functionCode = 2) { return ReadDiscrete(address.ToString(), stationNumber, functionCode); @@ -498,6 +567,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadInt16(int beginAddress, int address, byte[] values) { return ReadInt16(beginAddress.ToString(), address.ToString(), values); @@ -533,6 +609,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadUInt16(int beginAddress, int address, byte[] values) { return ReadUInt16(beginAddress.ToString(), address.ToString(), values); @@ -569,6 +652,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadInt32(int beginAddress, int address, byte[] values) { return ReadInt32(beginAddress.ToString(), address.ToString(), values); @@ -605,6 +695,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadUInt32(int beginAddress, int address, byte[] values) { return ReadUInt32(beginAddress.ToString(), address.ToString(), values); @@ -641,6 +738,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadInt64(int beginAddress, int address, byte[] values) { return ReadInt64(beginAddress.ToString(), address.ToString(), values); @@ -677,6 +781,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadUInt64(int beginAddress, int address, byte[] values) { return ReadUInt64(beginAddress.ToString(), address.ToString(), values); @@ -713,6 +824,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadFloat(int beginAddress, int address, byte[] values) { return ReadFloat(beginAddress.ToString(), address.ToString(), values); @@ -749,6 +867,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadDouble(int beginAddress, int address, byte[] values) { return ReadDouble(beginAddress.ToString(), address.ToString(), values); @@ -788,6 +913,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadCoil(int beginAddress, int address, byte[] values) { return ReadCoil(beginAddress.ToString(), address.ToString(), values); @@ -827,6 +959,13 @@ namespace IoTClient.Clients.Modbus } } + /// + /// 从批量读取的数据字节提取对应的地址数据 + /// + /// 批量读取的起始地址 + /// 读取地址 + /// 批量读取的值 + /// public Result ReadDiscrete(int beginAddress, int address, byte[] values) { return ReadDiscrete(beginAddress.ToString(), address.ToString(), values); @@ -1088,8 +1227,8 @@ namespace IoTClient.Clients.Modbus /// /// 读取地址 /// - /// - /// + /// 站号 + /// 功能码 public Result Write(string address, bool value, byte stationNumber = 1, byte functionCode = 5) { if (!socket?.Connected ?? true) Connect(); @@ -1136,8 +1275,8 @@ namespace IoTClient.Clients.Modbus /// /// 读取地址 /// 批量读取的值 - /// - /// + /// 站号 + /// 功能码 /// public Result Write(string address, byte[] values, byte stationNumber = 1, byte functionCode = 16) { diff --git a/IoTClient/Clients/PLC/OmronFinsClient.cs b/IoTClient/Clients/PLC/OmronFinsClient.cs index 91fc57d..77d0a96 100644 --- a/IoTClient/Clients/PLC/OmronFinsClient.cs +++ b/IoTClient/Clients/PLC/OmronFinsClient.cs @@ -13,6 +13,7 @@ namespace IoTClient.Clients.PLC { /// /// 欧姆龙PLC 客户端 - Beta + /// https://flat2010.github.io/2020/02/23/Omron-Fins%E5%8D%8F%E8%AE%AE/ /// public class OmronFinsClient : SocketBase, IEthernetClient { @@ -24,9 +25,11 @@ namespace IoTClient.Clients.PLC /// private byte[] BasicCommand = new byte[] { - 0x46, 0x49, 0x4E, 0x53, 0x00, 0x00, 0x00, 0x0C, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01 + 0x46, 0x49, 0x4E, 0x53,//Magic字段 0x46494E53 对应的ASCII码,即FINS + 0x00, 0x00, 0x00, 0x0C,//Length字段 表示其后所有字段的总长度 + 0x00, 0x00, 0x00, 0x00,//Command字段 + 0x00, 0x00, 0x00, 0x00,//Error Code字段 + 0x00, 0x00, 0x00, 0x01 //Client/Server Node Address字段 }; /// @@ -50,9 +53,12 @@ namespace IoTClient.Clients.PLC public LoggerDelegate WarningLog { get; set; } /// - /// 单元号地址 + /// DA2(即Destination unit address,目标单元地址) + /// 0x00:PC(CPU) + /// 0xFE: SYSMAC NET Link Unit or SYSMAC LINK Unit connected to network; + /// 0x10~0x1F:CPU总线单元 ,其值等于10 + 单元号(前端面板中配置的单元号) /// - public byte UnitNumber { get; set; } = 0x00; + public byte UnitAddress { get; set; } = 0x00; /// /// @@ -61,7 +67,7 @@ namespace IoTClient.Clients.PLC /// /// /// - public OmronFinsClient(string ip, int port, int timeout = 1500, EndianFormat endianFormat = EndianFormat.CDAB) + public OmronFinsClient(string ip, int port = 9600, int timeout = 1500, EndianFormat endianFormat = EndianFormat.CDAB) { IpAndPoint = new IPEndPoint(IPAddress.Parse(ip), port); ; this.timeout = timeout; @@ -601,19 +607,19 @@ namespace IoTClient.Clients.PLC tmp.CopyTo(command, 4); command[11] = 0x02; - command[16] = 0x80; //信息控制字段 - command[17] = 0x00; - command[18] = 0x02; - command[19] = 0x00; - command[20] = 0x13; //0x13; //01(节点地址:Ip地址的最后一位) - command[21] = UnitNumber; //单元号地址(传过来) - command[22] = 0x00; - command[23] = 0x0B; //0x0B; //01(节点地址:Ip地址的最后一位) - command[24] = 0x00; - command[25] = 0x00; + command[16] = 0x80; //ICF 信息控制字段 + command[17] = 0x00; //RSV 保留字段 + command[18] = 0x02; //GCT 网关计数 + command[19] = 0x00; //DNA 目标网络地址 00:表示本地网络 0x01~0x7F:表示远程网络 + command[20] = 0x13; //DA1 目标节点编号 0x01~0x3E:SYSMAC LINK网络中的节点号 0x01~0x7E:YSMAC NET网络中的节点号 0xFF:广播传输 + command[21] = UnitAddress; //DA2 目标单元地址 + command[22] = 0x00; //SNA 源网络地址 取值及含义同DNA字段 + command[23] = 0x0B; //SA1 源节点编号 取值及含义同DA1字段 + command[24] = 0x00; //SA2 源单元地址 取值及含义同DA2字段 + command[25] = 0x00; //SID Service ID 取值0x00~0xFF,产生会话的进程的唯一标识 command[26] = 0x01; - command[27] = 0x01; //读 + command[27] = 0x01; //Command Code 内存区域读取 command[28] = isBit ? arg.OmronFinsType.BitCode : arg.OmronFinsType.WordCode; arg.Content.CopyTo(command, 29); command[32] = (byte)(length / 256); @@ -632,19 +638,19 @@ namespace IoTClient.Clients.PLC tmp.CopyTo(command, 4); command[11] = 0x02; - command[16] = 0x80; //信息控制字段 - command[17] = 0x00; - command[18] = 0x02; - command[19] = 0x00; - command[20] = 0x13; //0x13; //01(节点地址:Ip地址的最后一位) - command[21] = UnitNumber; //单元号地址(传过来) - command[22] = 0x00; - command[23] = 0x0B; //0x0B; //01(节点地址:Ip地址的最后一位) - command[24] = 0x00; - command[25] = 0x00; + command[16] = 0x80; //ICF 信息控制字段 + command[17] = 0x00; //RSV 保留字段 + command[18] = 0x02; //GCT 网关计数 + command[19] = 0x00; //DNA 目标网络地址 00:表示本地网络 0x01~0x7F:表示远程网络 + command[20] = 0x13; //DA1 目标节点编号 0x01~0x3E:SYSMAC LINK网络中的节点号 0x01~0x7E:YSMAC NET网络中的节点号 0xFF:广播传输 + command[21] = UnitAddress; //DA2 目标单元地址 + command[22] = 0x00; //SNA 源网络地址 取值及含义同DNA字段 + command[23] = 0x0B; //SA1 源节点编号 取值及含义同DA1字段 + command[24] = 0x00; //SA2 源单元地址 取值及含义同DA2字段 + command[25] = 0x00; //SID Service ID 取值0x00~0xFF,产生会话的进程的唯一标识 command[26] = 0x01; - command[27] = 0x02; //写 + command[27] = 0x02; //Command Code 内存区域写入 command[28] = isBit ? arg.OmronFinsType.BitCode : arg.OmronFinsType.WordCode; arg.Content.CopyTo(command, 29); command[32] = isBit ? (byte)(value.Length / 256) : (byte)(value.Length / 2 / 256); diff --git a/IoTClient/IoTClient/IoTClient.xml b/IoTClient/IoTClient/IoTClient.xml index 964ab3e..beea9d8 100644 --- a/IoTClient/IoTClient/IoTClient.xml +++ b/IoTClient/IoTClient/IoTClient.xml @@ -1157,16 +1157,26 @@ - 读取Int16 + 读取Int16类型数据 寄存器起始地址 站号 功能码 + - 读取UInt16 + 读取UInt16类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取UInt16类型数据 寄存器起始地址 站号 @@ -1175,7 +1185,16 @@ - 读取Int32 + 读取Int32类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取Int32类型数据 寄存器起始地址 站号 @@ -1184,7 +1203,16 @@ - 读取UInt32 + 读取UInt32类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取UInt32类型数据 寄存器起始地址 站号 @@ -1193,7 +1221,16 @@ - 读取Int64 + 读取Int64类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取Int64类型数据 寄存器起始地址 站号 @@ -1202,7 +1239,16 @@ - 读取UInt64 + 读取UInt64类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取UInt64类型数据 寄存器起始地址 站号 @@ -1211,7 +1257,16 @@ - 读取Float + 读取Float类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取Float类型数据 寄存器起始地址 站号 @@ -1220,7 +1275,16 @@ - 读取Double + 读取Double类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取Double类型数据 寄存器起始地址 站号 @@ -1229,7 +1293,16 @@ - 读取线圈 + 读取线圈类型数据 + + 寄存器起始地址 + 站号 + 功能码 + + + + + 读取线圈类型数据 寄存器起始地址 站号 @@ -1238,11 +1311,20 @@ - 读取离散 + 读取离散类型数据 读取地址 - - + 站号 + 功能码 + + + + + 读取离散类型数据 + + 读取地址 + 站号 + 功能码 @@ -1254,6 +1336,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1263,6 +1354,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1272,6 +1372,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1281,6 +1390,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1290,6 +1408,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1299,6 +1426,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1308,6 +1444,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1317,6 +1462,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1326,6 +1480,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 从批量读取的数据字节提取对应的地址数据 @@ -1335,6 +1498,15 @@ 批量读取的值 + + + 从批量读取的数据字节提取对应的地址数据 + + 批量读取的起始地址 + 读取地址 + 批量读取的值 + + 分批读取(批量读取,内部进行批量计算读取) @@ -1348,8 +1520,8 @@ 读取地址 - - + 站号 + 功能码 @@ -1357,8 +1529,8 @@ 读取地址 批量读取的值 - - + 站号 + 功能码 @@ -1756,6 +1928,7 @@ 欧姆龙PLC 客户端 - Beta + https://flat2010.github.io/2020/02/23/Omron-Fins%E5%8D%8F%E8%AE%AE/ @@ -1783,9 +1956,12 @@ - + - 单元号地址 + DA2(即Destination unit address,目标单元地址) + 0x00:PC(CPU) + 0xFE: SYSMAC NET Link Unit or SYSMAC LINK Unit connected to network; + 0x10~0x1F:CPU总线单元 ,其值等于10 + 单元号(前端面板中配置的单元号) diff --git a/README.md b/README.md index 3f4aeca..fb8268d 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,32 @@ ModBusTcpClient client = new ModBusTcpClient("127.0.0.1", 502); //2、写操作 - 参数依次是:地址 、值 、站号 、功能码 client.Write("4", (short)33, 2, 16); -client.Write("4", (short)3344, 2, 16); + +//2.1、【注意】写入数据的时候需要明确数据类型 +client.Write("0", (short)33, 2, 16); //写入的是short类型数值 +client.Write("4", (ushort)33, 2, 16); //写入的是ushort类型数值 +client.Write("8", (int)33, 2, 16); //写入的是int类型数值 +client.Write("12", (uint)33, 2, 16); //写入的是uint类型数值 +client.Write("16", (long)33, 2, 16); //写入的是long类型数值 +client.Write("20", (ulong)33, 2, 16); //写入的是ulong类型数值 +client.Write("24", (float)33, 2, 16); //写入的是float类型数值 +client.Write("28", (double)33, 2, 16); //写入的是double类型数值 +client.Write("32", true, 2, 5); //写入的是线圈类型数值 //3、读操作 - 参数依次是:地址 、站号 、功能码 var value = client.ReadInt16("4", 2, 3).Value; -var value2 = client.ReadInt32("4", 2, 3).Value; + +//3.1、其他类型数据读取 +client.ReadInt16("0", stationNumber, 3); //short类型数据读取 +client.ReadUInt16("4", stationNumber, 3); //ushort类型数据读取 +client.ReadInt32("8", stationNumber, 3); //int类型数据读取 +client.ReadUInt32("12", stationNumber, 3); //uint类型数据读取 +client.ReadInt64("16", stationNumber, 3); //long类型数据读取 +client.ReadUInt64("20", stationNumber, 3); //ulong类型数据读取 +client.ReadFloat("24", stationNumber, 3); //float类型数据读取 +client.ReadDouble("28", stationNumber, 3); //double类型数据读取 +client.ReadCoil("32", stationNumber, 1); //线圈类型数据读取 +client.ReadDiscrete("32", stationNumber, 2);//离散类型数据读取 //4、如果没有主动Open,则会每次读写操作的时候自动打开自动和关闭连接,这样会使读写效率大大减低。所以建议手动Open和Close。 client.Open(); @@ -74,6 +95,8 @@ var result = client.BatchRead(list); ModBusTcpClient client = new ModBusTcpClient("127.0.0.1", 502, 1500, EndianFormat.ABCD); ``` +### ModBusTcp更多使用方式,请参考[单元测试](https://github.com/zhaopeiym/IoTClient/blob/master/IoTClient.Tests/Modbus_Tests/ModBusTcpClient_tests.cs) + ## ModBusRtu读写操作 ``` //实例化客户端 - [COM端口名称,波特率,数据位,停止位,奇偶校验] @@ -82,6 +105,24 @@ ModBusRtuClient client = new ModBusRtuClient("COM3", 9600, 8, StopBits.One, Pari //其他读写操作和ModBusTcpClient的读写操作一致 ``` +## ModBusAscii读写操作 +``` +//实例化客户端 - [COM端口名称,波特率,数据位,停止位,奇偶校验] +ModbusAsciiClient client = new ModbusAsciiClient("COM3", 9600, 8, StopBits.One, Parity.None); + +//其他读写操作和ModBusTcpClient的读写操作一致 +``` + +## ModbusRtuOverTcp读写操作 +``` +//串口透传 即:用Tcp的方式发送Rtu格式报文 + +//实例化客户端 - IP、端口、超时时间、大小端设置 +ModbusRtuOverTcpClient client = new ModbusRtuOverTcpClient("127.0.0.1", 502, 1500, EndianFormat.ABCD); + +//其他读写操作和ModBusTcpClient的读写操作一致 +``` + ## SiemensClient(西门子)读写操作 ``` //1、实例化客户端 - 输入正确的IP和端口