From 569cbca30020e506d0fddf0b734872ff6b49eb16 Mon Sep 17 00:00:00 2001 From: zhangyongpan Date: Wed, 30 Jul 2025 10:20:41 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=96=B9=E6=A1=88=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ModbusDemo/Device/IStreamResource.cs | 45 ++++++ ModbusDemo/Device/ModbusRTU.cs | 162 +++++++++++++------- ModbusDemo/Device/SerialPortAdapter.cs | 71 +++++++++ ModbusDemo/ModbusDemo.csproj | 11 ++ ModbusDemo/ModbusRTU_64x64.ico | Bin 0 -> 2065 bytes ModbusDemo/Model/ModbusDbContext.cs | 3 + ModbusDemo/Model/ModbusLog.cs | 4 + ModbusDemo/Uitls/CheckData.cs | 6 +- ModbusDemo/VIew/CoilUC.xaml | 8 +- ModbusDemo/VIew/RegisterUC.xaml | 4 +- ModbusDemo/VIewModel/AttachUCViewModel.cs | 153 +++++++++++++++++- ModbusDemo/VIewModel/CoilUCViewModel.cs | 2 + ModbusDemo/VIewModel/MainWindowViewModel.cs | 2 +- ModbusTest/ModbusRTUTest.cs | 77 ++++++++-- 14 files changed, 475 insertions(+), 73 deletions(-) create mode 100644 ModbusDemo/Device/IStreamResource.cs create mode 100644 ModbusDemo/Device/SerialPortAdapter.cs create mode 100644 ModbusDemo/ModbusRTU_64x64.ico diff --git a/ModbusDemo/Device/IStreamResource.cs b/ModbusDemo/Device/IStreamResource.cs new file mode 100644 index 0000000..1678ced --- /dev/null +++ b/ModbusDemo/Device/IStreamResource.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModbusDemo.Device +{ + public interface IStreamResource : IDisposable + { + int InfiniteTimeout { get; } + + /// + /// Gets or sets the number of milliseconds before a timeout occurs when a read operation does not finish. + /// + int ReadTimeout { get; set; } + + /// + /// Gets or sets the number of milliseconds before a timeout occurs when a write operation does not finish. + /// + int WriteTimeout { get; set; } + + /// + /// Purges the receive buffer. + /// + void DiscardInBuffer(); + + /// + /// Reads a number of bytes from the input buffer and writes those bytes into a byte array at the specified offset. + /// + /// The byte array to write the input to. + /// The offset in the buffer array to begin writing. + /// The number of bytes to read. + /// The number of bytes read. + int Read(byte[] buffer, int offset, int count); + + /// + /// Writes a specified number of bytes to the port from an output buffer, starting at the specified offset. + /// + /// The byte array that contains the data to write to the port. + /// The offset in the buffer array to begin writing. + /// The number of bytes to write. + void Write(byte[] buffer, int offset, int count); + } +} diff --git a/ModbusDemo/Device/ModbusRTU.cs b/ModbusDemo/Device/ModbusRTU.cs index afd944f..93803dc 100644 --- a/ModbusDemo/Device/ModbusRTU.cs +++ b/ModbusDemo/Device/ModbusRTU.cs @@ -17,11 +17,14 @@ namespace ModbusDemo.Device private SerialPort _serialPort; //用于操作数据库 private ModbusDbContext _modbusDbContext; + //TODO,修改 + private SerialPortAdapter _portAdapter; public ModbusRTU(SerialPort serialPort, ModbusDbContext modbusDbContext) { _serialPort = serialPort; _modbusDbContext = modbusDbContext; + _portAdapter = new SerialPortAdapter(serialPort); } /// /// 用来发送读写线圈的指令 @@ -94,15 +97,24 @@ namespace ModbusDemo.Device } } - //将操作失败的指令,插入数据库 - string RequestStr = ByteArrayToString(sendByte); + try + { + //将操作失败的指令,插入数据库 + string RequestStr = ByteArrayToString(sendByte); + + ModbusLog m = new ModbusLog(); + m.OperationType = "读线圈"; + m.ResponseData = ""; + m.RequestData = RequestStr; + _modbusDbContext.Add(m); + _modbusDbContext.SaveChanges(); + } + catch (Exception) + { - ModbusLog m = new ModbusLog(); - m.OperationType = "读线圈"; - m.ResponseData = ""; - m.RequestData = RequestStr; - _modbusDbContext.Add(m); - _modbusDbContext.SaveChanges(); + MessageBox.Show("0x15:数据库插入错误"); + } + return resultValue; } @@ -115,15 +127,24 @@ namespace ModbusDemo.Device /// public bool[] ParseCoilresponse(byte[] sendByte, byte[] response, ushort numberOfPoints) { - //将操作的指令,插入数据库 - string RequestStr = ByteArrayToString(sendByte); - string responseStr = ByteArrayToString(response); - ModbusLog m = new ModbusLog(); - m.OperationType = "读线圈"; - m.ResponseData = responseStr; - m.RequestData = RequestStr; - _modbusDbContext.Add(m); - _modbusDbContext.SaveChanges(); + try + { + //将操作的指令,插入数据库 + string RequestStr = ByteArrayToString(sendByte); + string responseStr = ByteArrayToString(response); + ModbusLog m = new ModbusLog(); + m.OperationType = "读线圈"; + m.ResponseData = responseStr; + m.RequestData = RequestStr; + _modbusDbContext.Add(m); + _modbusDbContext.SaveChanges(); + } + catch (Exception) + { + + MessageBox.Show("0x15:数据库插入错误"); + } + //判断发送回来的数据是否正确 @@ -255,21 +276,29 @@ namespace ModbusDemo.Device } } - //将操作的指令,插入数据库 - string RequestStr = ByteArrayToString(sendByte); - string responseStr = ByteArrayToString(response); - ModbusLog m = new ModbusLog(); - m.OperationType = "写线圈"; - m.ResponseData = responseStr; - m.RequestData = RequestStr; - _modbusDbContext.Add(m); - _modbusDbContext.SaveChanges(); - //判断发送回来的数据是否正确 - if (CheckData.CheckResponse(response)) + try { + //将操作的指令,插入数据库 + string RequestStr = ByteArrayToString(sendByte); + string responseStr = ByteArrayToString(response); + ModbusLog m = new ModbusLog(); + m.OperationType = "写线圈"; + m.ResponseData = responseStr; + m.RequestData = RequestStr; + _modbusDbContext.Add(m); + _modbusDbContext.SaveChanges(); + } + catch (Exception) + { + MessageBox.Show("0x15:数据库插入错误"); } + + + //判断发送回来的数据是否正确 + CheckData.CheckResponse(response); + } /// @@ -347,12 +376,21 @@ namespace ModbusDemo.Device //将操作失败的指令,插入数据库 string RequestStr = ByteArrayToString(sendByte); - ModbusLog m = new ModbusLog(); - m.OperationType = "读寄存器"; - m.ResponseData = ""; - m.RequestData = RequestStr; - _modbusDbContext.Add(m); - _modbusDbContext.SaveChanges(); + try + { + ModbusLog m = new ModbusLog(); + m.OperationType = "读寄存器"; + m.ResponseData = ""; + m.RequestData = RequestStr; + _modbusDbContext.Add(m); + _modbusDbContext.SaveChanges(); + } + catch (Exception) + { + + MessageBox.Show("0x15:数据库插入错误"); + } + return resultValue; @@ -367,15 +405,24 @@ namespace ModbusDemo.Device /// public ushort[] ParseRegistersresponse(byte[] sendByte, byte[] response, ushort numberOfPoints) { - //将操作的指令,插入数据库 - string RequestStr = ByteArrayToString(sendByte); - string responseStr = ByteArrayToString(response); - ModbusLog m = new ModbusLog(); - m.OperationType = "读寄存器"; - m.ResponseData = responseStr; - m.RequestData = responseStr; - _modbusDbContext.Add(m); - _modbusDbContext.SaveChanges(); + try + { + //将操作的指令,插入数据库 + string RequestStr = ByteArrayToString(sendByte); + string responseStr = ByteArrayToString(response); + ModbusLog m = new ModbusLog(); + m.OperationType = "读寄存器"; + m.ResponseData = responseStr; + m.RequestData = RequestStr; + _modbusDbContext.Add(m); + _modbusDbContext.SaveChanges(); + } + catch (Exception) + { + MessageBox.Show("0x15:数据库插入错误"); + + } + //判断发送回来的数据是否正确 if (CheckData.CheckResponse(response)) @@ -479,16 +526,25 @@ namespace ModbusDemo.Device attempt++; } } + try + { + //将操作的指令,插入数据库 + string RequestStr = ByteArrayToString(sendByte); + string responseStr = ByteArrayToString(response); + ModbusLog m = new ModbusLog(); + m.OperationType = "写寄存器"; + m.ResponseData = responseStr; + m.RequestData = RequestStr; + _modbusDbContext.Add(m); + _modbusDbContext.SaveChanges(); + } + catch (Exception) + { - //将操作的指令,插入数据库 - string RequestStr = ByteArrayToString(sendByte); - string responseStr = ByteArrayToString(response); - ModbusLog m = new ModbusLog(); - m.OperationType = "写寄存器"; - m.ResponseData = responseStr; - m.RequestData = RequestStr; - _modbusDbContext.Add(m); - _modbusDbContext.SaveChanges(); + MessageBox.Show("0x15:数据库插入错误"); + } + + //判断发送回来的数据是否正确 CheckData.CheckResponse(response); @@ -506,7 +562,7 @@ namespace ModbusDemo.Device if (byteArray == null || byteArray.Length == 0) return string.Empty; - System.Text.StringBuilder sb = new System.Text.StringBuilder(); + StringBuilder sb = new StringBuilder(); // 处理第一个元素(无前导空格) sb.Append(byteArray[0].ToString("X2")); diff --git a/ModbusDemo/Device/SerialPortAdapter.cs b/ModbusDemo/Device/SerialPortAdapter.cs new file mode 100644 index 0000000..5a1da48 --- /dev/null +++ b/ModbusDemo/Device/SerialPortAdapter.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModbusDemo.Device +{ + public class SerialPortAdapter:IStreamResource + { + private string NewLine = Environment.NewLine; + private SerialPort _serialPort; + + public SerialPortAdapter(SerialPort serialPort) + { + Debug.Assert(serialPort != null, "Argument serialPort cannot be null."); + + _serialPort = serialPort; + _serialPort.NewLine = NewLine; + } + + public int InfiniteTimeout + { + get { return SerialPort.InfiniteTimeout; } + } + + public int ReadTimeout + { + get { return _serialPort.ReadTimeout; } + set { _serialPort.ReadTimeout = value; } + } + + public int WriteTimeout + { + get { return _serialPort.WriteTimeout; } + set { _serialPort.WriteTimeout = value; } + } + + public void DiscardInBuffer() + { + _serialPort.DiscardInBuffer(); + } + + public int Read(byte[] buffer, int offset, int count) + { + return _serialPort.Read(buffer, offset, count); + } + + public void Write(byte[] buffer, int offset, int count) + { + _serialPort.Write(buffer, offset, count); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _serialPort?.Dispose(); + _serialPort = null; + } + } + } +} diff --git a/ModbusDemo/ModbusDemo.csproj b/ModbusDemo/ModbusDemo.csproj index 6ff48c3..02d9860 100644 --- a/ModbusDemo/ModbusDemo.csproj +++ b/ModbusDemo/ModbusDemo.csproj @@ -6,8 +6,15 @@ disable enable true + ModbusRTU_64x64.ico + + + Always + + + @@ -24,4 +31,8 @@ + + + + diff --git a/ModbusDemo/ModbusRTU_64x64.ico b/ModbusDemo/ModbusRTU_64x64.ico new file mode 100644 index 0000000000000000000000000000000000000000..97c1b9ed478cd755f89f2da77c7e1de55592c2d2 GIT binary patch literal 2065 zcmV+s2=4a)0096206;(h0000W0Q(0302TlM0EtjeM-2)Z3IG5A4M|8uQUCw|KmY&$ zKnMl^0063Kaozv`00d`2O+f$vv5yP z0Dy!50Qvv`0D$NK0Cg|`0P0`>06Lfe02gqax=}m;00((VL_t(|ob6j}Y+F|uexBp& zI8K|zw$g@dkpf%oj5b<7R!u_cDn*E@45T4Vw3}ccO@fv0E~*@=eG)t4MpKd3CV%0i1A zj|T%Uq|+Gzyy58k1Rkjlt;#|KZ<|5?ZU9ig+&_P}I1d0M9`}SI#{hu%^6wnJj_t{% zDrv|$3L~K0EMWA~4atC2A|l3ZcGl(C-w9 z6ta6dw*Qd6aMaR!5g9Rqfu{1&s~o(c$S}!`RyI|r(*KL|KyhCz1<*;ot$cKb!aIp?5)M<`-`$a#8@x=g^XH zFz}3JUy}MmyzA4y@q{BMAh_SEUZFNMw$iX!(ew#pU&82?t_ zPw5;_IAU70lU=4#D7XyXEhxJH6x=9xA9n(q1dwKLDEimj;jcyh7z+kg^(M;}0Z4jD z>`tdeWKaW7#)E;++tGeGVT%AFxGq|MQv?YBAh}5aZ~DSf!HIX>cJxs$*fj@Cn_X>h z2;?uh25;?#4{hqBEUlvTab*i9~90HLIfP@SjfqJ9 z=n?tG`ra$M1Zc@K0pq3iVXFW_70%5gux_R8O(&;Xb44K8T%#OsE8@OIeFHOQr@x`p zK1$vTh~RR5roILM@y<=Z@P?u<2@0gw>)%VWed;{j%;^;|6Dn(%E7oLJH~(u%PD);KLYmzs5XIW zW7%`SSYzVSx?9OL@wsfW(TFd%?DAKEeeH=!U}Qy%Rx$4SN8p|S)h1AF-1P$3@@Z_P z$m~Q#-U9hVIzQIwXTeG~l2CO zW0T#R2i$!(AE=e-UI@QH!YP7R&5@z+<7mgUCv@czLj9d&U5fIZLa|w%@ZcE**{=nc zs&W2%vS+~MmYE@dnGj48hkZ>ghhqR09hoQ%hwzm`T`I_a z08qqcue2z$$RhMn|Y^?cA`nQHYA|jb%u!iu}2eZo-d(Icx1kR$QdipbeqKJMkCGuQ`k9Zy~ zS{Ee>phQhWxUkPQrWYMpYK58%8FCopL^_>BYLQs>VZ(wCq!ZwON~yi}C&8l&2Ok6< zb%<=!(64Lg*BOuBT&j9imqELbf6&e1+iDtV}=p@%MI)Eme2zj{pE;!?Qn+ z4bQl=$XftFz+J=I%jmgLyHwq^FTlx&%h%+Z@in<-C^WQ4CbX`;IrZ74s;_+kazVaR zN^yJV0OET3rMf?9~m_l6<|3pL~EjXs%`T=cr+pxO_}1DTB4agEgc z7ct5wDcqZWCotmib4yXq9|6J@FIVFS1J`6eJe^AINngScVDxs^r#=+mgLGMveFaG= z{CD~(Jz{0f+HXc;jN1%?2??DTK;^j>PE z!_|^7IOw{aa*8C>jDdt}cJ3X*Y*;taFfr3C4m6I}H(bWonkNAOCvMhx>k>PXNsj6i z#%eI-O7|HL26nkmeQ>{1RLh(TGCKDB!xqtL(w=ioD*xLcP}$vBC1K^OT>usVqF9NWlnrdcx5kD z+t%s@ilr`133!U=={I~$Ek*atK>8vD2iC&1IiUn{FGg4))_=hu0C+-?7ZrK5{Onc_ zQleiT3%0$uaCJ5m{TqqLt4XR-5a3^Cr++JuH3^zQ|86bPQ$1RhffhNQb{@!C1>(WL vOEJe-jRuZYo?3Y!g73zLhn(3r#{uAfh|afybG22n00000NkvXXu0mjfl+VWR literal 0 HcmV?d00001 diff --git a/ModbusDemo/Model/ModbusDbContext.cs b/ModbusDemo/Model/ModbusDbContext.cs index e37d7dd..068adb4 100644 --- a/ModbusDemo/Model/ModbusDbContext.cs +++ b/ModbusDemo/Model/ModbusDbContext.cs @@ -7,6 +7,9 @@ using System.Threading.Tasks; namespace ModbusDemo.Model { + /// + /// 操作数据库的上下文 + /// public class ModbusDbContext:DbContext { protected ModbusDbContext() diff --git a/ModbusDemo/Model/ModbusLog.cs b/ModbusDemo/Model/ModbusLog.cs index fc0e255..59dbc20 100644 --- a/ModbusDemo/Model/ModbusLog.cs +++ b/ModbusDemo/Model/ModbusLog.cs @@ -7,6 +7,9 @@ using System.Threading.Tasks; namespace ModbusDemo.Model { + /// + /// 表的映射 + /// public class ModbusLog { //数据库主键 @@ -17,6 +20,7 @@ namespace ModbusDemo.Model //请求的字节信息 public string RequestData { get; set; } //返回的字节信息 + public string ResponseData { get; set; } //操作的时间 diff --git a/ModbusDemo/Uitls/CheckData.cs b/ModbusDemo/Uitls/CheckData.cs index 31854d5..ec4b836 100644 --- a/ModbusDemo/Uitls/CheckData.cs +++ b/ModbusDemo/Uitls/CheckData.cs @@ -9,7 +9,11 @@ namespace ModbusDemo.Uitls { public static class CheckData { - + /// + /// 检测返回的数据格式是否正确 + /// + /// + /// public static bool CheckResponse(byte[] response) { if (response.Length == 0) diff --git a/ModbusDemo/VIew/CoilUC.xaml b/ModbusDemo/VIew/CoilUC.xaml index 951336f..a0a0489 100644 --- a/ModbusDemo/VIew/CoilUC.xaml +++ b/ModbusDemo/VIew/CoilUC.xaml @@ -88,8 +88,8 @@ Grid.Column="4" Width="80" Height="40" - IsEnabled="{Binding IsEnable}" materialDesign:ButtonAssist.CornerRadius="20" + IsEnabled="{Binding IsEnable}" Command="{Binding ReadCoilCmm}" Content="读取" Style="{StaticResource MaterialDesignRaisedDarkButton}"> @@ -154,16 +154,16 @@ - + - + - + diff --git a/ModbusDemo/VIew/RegisterUC.xaml b/ModbusDemo/VIew/RegisterUC.xaml index e19a195..57330b4 100644 --- a/ModbusDemo/VIew/RegisterUC.xaml +++ b/ModbusDemo/VIew/RegisterUC.xaml @@ -88,8 +88,8 @@ Grid.Column="4" Width="80" Height="40" - IsEnabled="{Binding IsEnable}" materialDesign:ButtonAssist.CornerRadius="20" + IsEnabled="{Binding IsEnable}" Command="{Binding ReadRegisterCmm}" Content="读取" Style="{StaticResource MaterialDesignRaisedDarkButton}"> @@ -142,8 +142,8 @@ Grid.Column="4" Width="80" Height="40" - IsEnabled="{Binding IsEnable}" materialDesign:ButtonAssist.CornerRadius="20" + IsEnabled="{Binding IsEnable}" Command="{Binding WriteRegisterCmm}" Content="写入" Style="{StaticResource MaterialDesignRaisedDarkButton}"> diff --git a/ModbusDemo/VIewModel/AttachUCViewModel.cs b/ModbusDemo/VIewModel/AttachUCViewModel.cs index 248d0f4..c5c851c 100644 --- a/ModbusDemo/VIewModel/AttachUCViewModel.cs +++ b/ModbusDemo/VIewModel/AttachUCViewModel.cs @@ -1,4 +1,6 @@ using Modbus.Device; +using ModbusDemo.Model; +using ModbusDemo.Uitls; using Prism.Commands; using Prism.Mvvm; using System; @@ -51,11 +53,12 @@ namespace ModbusDemo.VIewModel ReadOddRegisterCmm = new DelegateCommand(ReadOddRegister); _serialPort = serialPort; } - + /// + /// 读1000个寄存器 + /// private void ReadOddRegister() { // 创建 Modbus RTU 主站 - IModbusSerialMaster master = ModbusSerialMaster.CreateRtu(_serialPort); byte slaveId = 1; ushort totalRegisters = 1000; @@ -80,7 +83,7 @@ namespace ModbusDemo.VIewModel } catch (Exception ex) { - Console.WriteLine($"线程 {chunkIndex} 读取寄存器时出错: {ex.Message}"); + MessageBox.Show($"线程 {chunkIndex} 读取寄存器时出错: {ex.Message}"); } }); } @@ -102,6 +105,150 @@ namespace ModbusDemo.VIewModel ReadResult = result.ToString(); } + + private void ReadOddRegister2() + { + byte slaveId = 1; + ushort totalRegisters = 1000; + ushort chunkSize = 100; + int numChunks = (int)Math.Ceiling((double)totalRegisters / chunkSize); + + ushort[] allRegisters = new ushort[totalRegisters]; + Task[] tasks = new Task[numChunks]; + DateTime startTime = DateTime.Now; + for (int i = 0; i < numChunks; i++) + { + ushort startAddress = (ushort)(10300 + i * chunkSize); + ushort currentChunkSize = 100; + + int chunkIndex = i; + tasks[i] = Task.Run(() => + { + + ushort[] registers = ReadRegisters(slaveId, startAddress, currentChunkSize); + Array.Copy(registers, 0, allRegisters, chunkIndex * chunkSize, currentChunkSize); + + + }); + } + + // 等待所有任务完成 + Task.WaitAll(tasks); + Time = (int)(DateTime.Now - startTime).TotalMilliseconds; + StringBuilder result = new StringBuilder(); + int count = 0; + for (int i = 1; i < totalRegisters; i += 2) + { + result.Append(allRegisters[i].ToString() + " "); + count++; + if (count % 50 == 0) + { + result.AppendLine(); + } + } + ReadResult = result.ToString(); + } + + + public ushort[] ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints) + { + object _lock = new object(); + ushort[] resultValue = null; + if (!_serialPort.IsOpen) + { + MessageBox.Show("串口没有链接,请先链接"); + return resultValue; + } + List sendByteList = new List(); + //设置从站地址 + sendByteList.Add(slaveAddress); + //设置功能码 + sendByteList.Add(0x03); + //设置起始地址的高位和低位 + sendByteList.Add(BitConverter.GetBytes(startAddress)[1]); + sendByteList.Add(BitConverter.GetBytes(startAddress)[0]); + //设置读取几个线圈的高位和低位 + sendByteList.Add(BitConverter.GetBytes(numberOfPoints)[1]); + sendByteList.Add(BitConverter.GetBytes(numberOfPoints)[0]); + //获取CRC校验码 + byte[] getCRC = sendByteList.ToArray(); + byte[] resultCRC = CRCUitl.CalculateCRC(getCRC, getCRC.Length); + sendByteList.Add(resultCRC[0]); + sendByteList.Add(resultCRC[1]); + + byte[] sendByte = sendByteList.ToArray(); + int maxRetries = 3; // 最大重试次数 + int attempt = 0; + List responseData = new List(); + byte[] response = null; + _serialPort.Write(sendByte, 0, sendByte.Length); + while (attempt < maxRetries) + { + try + { + lock (_lock) + { + + + //使用时间去轮询查询数据 + DateTime startTime = DateTime.Now; + while ((DateTime.Now - startTime).TotalMilliseconds < _serialPort.ReadTimeout) + { + int bytesToRead = _serialPort.BytesToRead; + if (bytesToRead > 0) + { + byte[] buffer = new byte[bytesToRead]; + int bytesRead = _serialPort.Read(buffer, 0, bytesToRead); + responseData.AddRange(buffer.Take(bytesRead)); + } + //延迟20毫秒,节约cpu资源 + Task.Delay(20); + } + response = responseData.ToArray(); + if (response[0] == 0x00) + { + continue; + } + resultValue = ParseRegistersresponse(sendByte, response, numberOfPoints); + return resultValue; + } + } + catch (Exception) + { + + attempt++; + } + + } + + return resultValue; + + + + } + + public ushort[] ParseRegistersresponse(byte[] sendByte, byte[] response, ushort numberOfPoints) + { + + + //判断发送回来的数据是否正确 + if (CheckData.CheckResponse(response)) + { + ushort[] registers = new ushort[numberOfPoints]; + for (int i = 0; i < numberOfPoints; i++) + { + int pos = 3 + i * 2; + // 大端序转换 (高位在前) + registers[i] = (ushort)((response[pos] << 8) | response[pos + 1]); + } + + return registers; + } + else + { + return null; + } + } } } diff --git a/ModbusDemo/VIewModel/CoilUCViewModel.cs b/ModbusDemo/VIewModel/CoilUCViewModel.cs index 6f7012b..c2eee20 100644 --- a/ModbusDemo/VIewModel/CoilUCViewModel.cs +++ b/ModbusDemo/VIewModel/CoilUCViewModel.cs @@ -50,6 +50,8 @@ namespace ModbusDemo.VIewModel + ",数据位:" + _serialPort.DataBits + ",校验位:" + _serialPort.Parity + ",停止位:" + _serialPort.StopBits; } + + } #region 读取定义 diff --git a/ModbusDemo/VIewModel/MainWindowViewModel.cs b/ModbusDemo/VIewModel/MainWindowViewModel.cs index abad9e2..fc5f8b6 100644 --- a/ModbusDemo/VIewModel/MainWindowViewModel.cs +++ b/ModbusDemo/VIewModel/MainWindowViewModel.cs @@ -66,7 +66,7 @@ namespace ModbusDemo.VIewModel LeftMenusList.Add(new MenusInfo() { Icon = "AllInclusive", MenuName = "线圈操作", ViewName = "CoilUC" }); LeftMenusList.Add(new MenusInfo() { Icon = "BlurCircular", MenuName = "寄存器操作", ViewName = "RegisterUC" }); LeftMenusList.Add(new MenusInfo() { Icon = "Settings", MenuName = "串口设置", ViewName = "SettingsUC" }); - LeftMenusList.Add(new MenusInfo() { Icon = "Settings", MenuName = "附加功能", ViewName = "AttachUC" }); + LeftMenusList.Add(new MenusInfo() { Icon = "AddCircle", MenuName = "附加功能", ViewName = "AttachUC" }); } public void DefultNaigation() diff --git a/ModbusTest/ModbusRTUTest.cs b/ModbusTest/ModbusRTUTest.cs index 79fee9e..1d6c982 100644 --- a/ModbusTest/ModbusRTUTest.cs +++ b/ModbusTest/ModbusRTUTest.cs @@ -29,7 +29,7 @@ namespace ModbusTest _serialport.StopBits = StopBits.One; _serialport.ReadTimeout = 500; _serialport.WriteTimeout = 500; - _serialport.Open(); + _serialport.Open(); _mockDbContext = new Mock(); _modbusRtu = new ModbusRTU(_serialport, _mockDbContext.Object); } @@ -47,7 +47,6 @@ namespace ModbusTest { var result = _modbusRtu.ReadCoil(1, 300, 5); - // 创建包含5个true的预期数组 var expected = new bool[5]; Array.Fill(expected, false); CollectionAssert.AreEqual(expected, result); @@ -57,21 +56,23 @@ namespace ModbusTest public void ReadCoil2() { var result = _modbusRtu.ReadCoil(1, 305, 5); - // 创建包含5个flase的预期数组 + var expected = new bool[5]; Array.Fill(expected, true); CollectionAssert.AreEqual(expected, result); } - + /// + /// 测试写入线圈 + /// [Test] public void WriteCoil1() { var data = new bool[5]; Array.Fill(data, true); _modbusRtu.WriteCoil(1, 310, data); - // 创建包含5个true的预期数组 + var expected = _modbusRtu.ReadCoil(1, 310, 5); CollectionAssert.AreEqual(data, expected); @@ -85,13 +86,15 @@ namespace ModbusTest var data = new bool[5]; Array.Fill(data, false); _modbusRtu.WriteCoil(1, 315, data); - // 创建包含5个flase的预期数组 + var expected = _modbusRtu.ReadCoil(1, 315, 5); CollectionAssert.AreEqual(data, expected); } - + /// + /// 测试读取寄存器 + /// [Test] public void ReadRegister1() { @@ -108,13 +111,15 @@ namespace ModbusTest { ushort[] data = new ushort[5]; Array.Fill(data, (ushort)1); - + var expected = _modbusRtu.ReadRegisters(1, 305, 5); CollectionAssert.AreEqual(data, expected); } - + /// + /// 测试写入寄存器 + /// [Test] public void WriteRegister1() { @@ -137,5 +142,59 @@ namespace ModbusTest var expected = _modbusRtu.ReadRegisters(1, 315, 5); CollectionAssert.AreEqual(data, expected); } + + /// + /// 解析线圈的返回值 + /// + [Test] + public void ParseCoilresponse1() + { + var data = new bool[5]; + Array.Fill(data, true); + byte[] response = new byte[] { 0x01, 0x01, 0x01, 0x7f, 0x10, 0x68 }; + bool[] bools = _modbusRtu.ParseCoilresponse(new byte[] { }, response, 5); + + CollectionAssert.AreEqual(data, bools); + } + + [Test] + public void ParseCoilresponse2() + { + var data = new bool[5]; + Array.Fill(data, false); + byte[] response = new byte[] { 0x01, 0x01, 0x01, 0x00, 0x51, 0x88 }; + bool[] result = _modbusRtu.ParseCoilresponse(new byte[] { }, response, 5); + + CollectionAssert.AreEqual(data, result); + } + + /// + /// 解析寄存器的返回值 + /// + [Test] + public void ParseRegistersresponse1() + { + ushort[] data = new ushort[5]; + Array.Fill(data, (ushort)1); + byte[] response = new byte[] {0x01, 0x03, 0x0a, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x01, 0x94, 0x26 }; + + ushort[] result = _modbusRtu.ParseRegistersresponse(new byte[] {},response, 5); + + CollectionAssert.AreEqual(data, result); + } + + [Test] + public void ParseRegistersresponse2() + { + ushort[] data = new ushort[2]; + Array.Fill(data, (ushort)10); + byte[] response = new byte[] {0x01, 0x03, 0x04, 0x00,0x0a, 0x00, 0x0a, 0x5a, 0x36 }; + + ushort[] result = _modbusRtu.ParseRegistersresponse(new byte[] { }, response, 2); + + CollectionAssert.AreEqual(data, result); + } + } }