From 1a541a46545d879e26ba87813d8ab93de9931d53 Mon Sep 17 00:00:00 2001 From: zhangyongpan Date: Mon, 28 Jul 2025 11:08:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BA=BF=E5=9C=88bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ModbusDemo/App.xaml.cs | 2 +- ModbusDemo/Device/IModbusRTU.cs | 2 +- ModbusDemo/Device/ModbusRTU.cs | 136 +++++++++++++------- ModbusDemo/Uitls/CheckData.cs | 13 +- ModbusDemo/VIew/RegisterUC.xaml | 6 +- ModbusDemo/VIew/SettingsUC.xaml | 7 +- ModbusDemo/VIewModel/CoilUCViewModel.cs | 98 +++++++++----- ModbusDemo/VIewModel/SettingsUCViewModel.cs | 20 +-- 8 files changed, 190 insertions(+), 94 deletions(-) diff --git a/ModbusDemo/App.xaml.cs b/ModbusDemo/App.xaml.cs index a10a9cd..e71e464 100644 --- a/ModbusDemo/App.xaml.cs +++ b/ModbusDemo/App.xaml.cs @@ -61,7 +61,7 @@ namespace ModbusDemo .UseSqlServer(configuration.GetConnectionString("ConnStr")) .Options; - // 3. 注册 DbContext(作用域生命周期) + // 3. 注册 DbContext containerRegistry.Register(() => new ModbusDbContext(options)); } /// diff --git a/ModbusDemo/Device/IModbusRTU.cs b/ModbusDemo/Device/IModbusRTU.cs index 0a0a0bf..352af03 100644 --- a/ModbusDemo/Device/IModbusRTU.cs +++ b/ModbusDemo/Device/IModbusRTU.cs @@ -11,7 +11,7 @@ namespace ModbusDemo.Device public bool[] ReadCoil(byte slaveAddress, ushort startAddress, ushort numberOfPoints); - public void WriteCoil(byte slaveAddress, ushort startAddress, bool[] data); + public bool WriteCoil(byte slaveAddress, ushort startAddress, bool[] data); public ushort[] ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints); diff --git a/ModbusDemo/Device/ModbusRTU.cs b/ModbusDemo/Device/ModbusRTU.cs index 1494b6b..467da75 100644 --- a/ModbusDemo/Device/ModbusRTU.cs +++ b/ModbusDemo/Device/ModbusRTU.cs @@ -16,7 +16,7 @@ namespace ModbusDemo.Device private SerialPort _serialPort; //用于操作数据库 private ModbusDbContext _modbusDbContext; - public ModbusRTU(SerialPort serialPort,ModbusDbContext modbusDbContext) + public ModbusRTU(SerialPort serialPort, ModbusDbContext modbusDbContext) { _serialPort = serialPort; _modbusDbContext = modbusDbContext; @@ -30,10 +30,12 @@ namespace ModbusDemo.Device /// public bool[] ReadCoil(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { + bool[] resultValue = null; + if (!_serialPort.IsOpen) { MessageBox.Show("串口没有链接,请先链接"); - return null; + return resultValue; } List sendByteList = new List(); //设置从站地址 @@ -51,23 +53,44 @@ namespace ModbusDemo.Device byte[] resultCRC = CRCUitl.CalculateCRC(getCRC, getCRC.Length); sendByteList.Add(resultCRC[0]); sendByteList.Add(resultCRC[1]); - byte[] sendByte = sendByteList.ToArray(); - if (_serialPort.IsOpen) + int maxRetries = 3; // 最大重试次数 + int attempt = 0; + + while (attempt < maxRetries) { - // 清空接收缓冲区(避免残留数据干扰) - _serialPort.DiscardInBuffer(); + try + { + // 清空接收缓冲区(避免残留数据干扰) + _serialPort.DiscardInBuffer(); + _serialPort.Write(sendByte, 0, sendByte.Length); + Thread.Sleep(300); + byte[] response = new byte[_serialPort.BytesToRead]; + _serialPort.Read(response, 0, _serialPort.BytesToRead); + if (response[0] == 0x00) + { + continue; + } + resultValue = ParseCoilresponse(sendByte, response, numberOfPoints); + return resultValue; + } + catch (Exception) + { - _serialPort.Write(sendByte, 0, sendByte.Length); - Thread.Sleep(300); - byte[] response = new byte[_serialPort.BytesToRead]; - _serialPort.Read(response, 0, _serialPort.BytesToRead); + attempt++; + } - return ParseCoilresponse(sendByte, response, numberOfPoints); } - - - return null; + //将操作失败的指令,插入数据库 + string RequestStr = ByteArrayToString(sendByte); + + ModbusLog m = new ModbusLog(); + m.OperationType = "读线圈"; + m.ResponseData = ""; + m.RequestData = RequestStr; + _modbusDbContext.Add(m); + _modbusDbContext.SaveChanges(); + return resultValue; } @@ -78,20 +101,23 @@ namespace ModbusDemo.Device string responseStr = ByteArrayToString(response); ModbusLog m = new ModbusLog(); m.OperationType = "读线圈"; - m.ResponseData = responseStr; + m.ResponseData = RequestStr; m.RequestData = responseStr; _modbusDbContext.Add(m); _modbusDbContext.SaveChanges(); //判断发送回来的数据是否正确 - CheckData.CheckResponse(response); - - if (!CRCUitl.ValidateCRC(response)) + if(CheckData.CheckResponse(response)) { - MessageBox.Show("0x14:CRC校验错误"); - return null; + if (!CRCUitl.ValidateCRC(response)) + { + MessageBox.Show("0x14:CRC校验错误"); + return null; + } } + + List responseList = new List(response); //移除前两位 responseList.RemoveRange(0, 3); @@ -129,8 +155,13 @@ namespace ModbusDemo.Device /// 从站地址 /// 起始地址 /// 写入的数据 - public void WriteCoil(byte slaveAddress, ushort startAddress, bool[] data) + public bool WriteCoil(byte slaveAddress, ushort startAddress, bool[] data) { + if (!_serialPort.IsOpen) + { + MessageBox.Show("串口没有链接,请先链接"); + return false; + } List sendByteList = new List(); //设置从站地址 sendByteList.Add(slaveAddress); @@ -167,41 +198,56 @@ namespace ModbusDemo.Device byte[] resultCRC = CRCUitl.CalculateCRC(getCRC, getCRC.Length); sendByteList.Add(resultCRC[0]); sendByteList.Add(resultCRC[1]); - - byte[] sendByte = sendByteList.ToArray(); - if (_serialPort.IsOpen) + + int maxRetries = 3; // 最大重试次数 + int attempt = 0; + byte[] response = null; + while (attempt < maxRetries) { - // 清空接收缓冲区(避免残留数据干扰) - _serialPort.DiscardInBuffer(); - _serialPort.Write(sendByte, 0, sendByte.Length); - Thread.Sleep(300); - byte[] response = new byte[_serialPort.BytesToRead]; - _serialPort.Read(response, 0, _serialPort.BytesToRead); + try + { + // 清空接收缓冲区(避免残留数据干扰) + _serialPort.DiscardInBuffer(); + + _serialPort.Write(sendByte, 0, sendByte.Length); + Thread.Sleep(300); + response = new byte[_serialPort.BytesToRead]; + _serialPort.Read(response, 0, _serialPort.BytesToRead); + if (response[0] != 0x00) + { + break; + } - //将操作的指令,插入数据库 - 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(); + } + catch (Exception) + { - //判断发送回来的数据是否正确 - CheckData.CheckResponse(response); + attempt++; + } + } + //将操作的指令,插入数据库 + 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)) + { if (!CRCUitl.ValidateCRC(response)) { MessageBox.Show("0x14:CRC校验错误"); - + return false; } } - - - + return true; } public ushort[] ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints) diff --git a/ModbusDemo/Uitls/CheckData.cs b/ModbusDemo/Uitls/CheckData.cs index c64642b..f581607 100644 --- a/ModbusDemo/Uitls/CheckData.cs +++ b/ModbusDemo/Uitls/CheckData.cs @@ -10,7 +10,7 @@ namespace ModbusDemo.Uitls public static class CheckData { - public static void CheckResponse(byte[] response) + public static bool CheckResponse(byte[] response) { // 检查数组长度是否足够 if (response.Length > 1) @@ -24,10 +24,17 @@ namespace ModbusDemo.Uitls if (highNibble == 8) { MessageBox.Show($"数据错误:错误码为:0x{response[2]:X2}"); - return; + } - + return false; } + if(response.Length == 0) + { + MessageBox.Show("返回数据为空","error",MessageBoxButton.OK,MessageBoxImage.Error); + return false; + } + + return true; } } diff --git a/ModbusDemo/VIew/RegisterUC.xaml b/ModbusDemo/VIew/RegisterUC.xaml index 6c167c9..041e2e5 100644 --- a/ModbusDemo/VIew/RegisterUC.xaml +++ b/ModbusDemo/VIew/RegisterUC.xaml @@ -151,16 +151,16 @@ - + - + - + diff --git a/ModbusDemo/VIew/SettingsUC.xaml b/ModbusDemo/VIew/SettingsUC.xaml index d771eb6..6e02848 100644 --- a/ModbusDemo/VIew/SettingsUC.xaml +++ b/ModbusDemo/VIew/SettingsUC.xaml @@ -55,6 +55,7 @@ Height="30" Margin="10,0,0,5" HorizontalAlignment="Left" + materialDesign:HintAssist.Hint="COM1" SelectedItem="{Binding PortName}"> @@ -71,6 +72,7 @@ Height="30" Margin="10,0,0,5" HorizontalAlignment="Left" + materialDesign:HintAssist.Hint="19200" SelectedItem="{Binding BaudRate}"> @@ -118,6 +120,7 @@ Height="30" Margin="10,0,0,5" HorizontalAlignment="Left" + materialDesign:HintAssist.Hint="8" SelectedItem="{Binding DataBits}"> @@ -140,7 +143,7 @@ Height="30" materialDesign:ButtonAssist.CornerRadius="15" Style="{StaticResource MaterialDesignRaisedDarkButton}" - Content="链接" + Content="连接" Command="{Binding ConnectionCmm}"> diff --git a/ModbusDemo/VIewModel/CoilUCViewModel.cs b/ModbusDemo/VIewModel/CoilUCViewModel.cs index fba086f..3973686 100644 --- a/ModbusDemo/VIewModel/CoilUCViewModel.cs +++ b/ModbusDemo/VIewModel/CoilUCViewModel.cs @@ -170,47 +170,83 @@ namespace ModbusDemo.VIewModel /// private void ReadCoil() { - try + if (!byte.TryParse(SlaveAddress, out byte slaveAddressValue)) { - bool[] result = _modbusRTU.ReadCoil(byte.Parse(SlaveAddress), - ushort.Parse(StartAddress), - ushort.Parse(NumberOfPoints)); - if (result != null) - { - string temp = ""; - foreach (var item in result) - { - temp += item; - temp += " "; - } - ReadResult = temp; - } + MessageBox.Show("SlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + return; } - catch (Exception) + + if (!ushort.TryParse(StartAddress, out ushort startAddressValue)) { + MessageBox.Show("StartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } - MessageBox.Show("参数配置错误"); + if (!ushort.TryParse(NumberOfPoints, out ushort numberOfPointsValue)) + { + MessageBox.Show("NumberOfPoints 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + return; } + //使用子线程,防止ui线程卡顿 + Task.Run(() => + { + bool[] result = _modbusRTU.ReadCoil(slaveAddressValue, startAddressValue, numberOfPointsValue); + + if (result == null) + { + MessageBox.Show("读取失败", "error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + string temp = ""; + foreach (var item in result) + { + temp += item; + temp += " "; + } + ReadResult = temp; + MessageBox.Show("读取成功"); + ModbusLogList = GetOperateCoil(); + }); + } + + + private void WriteCoil() { + if (!byte.TryParse(WriteSlaveAddress, out byte writeSlaveAddressValue)) + { + MessageBox.Show("WriteSlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + if (!ushort.TryParse(WriteStartAddress, out ushort WriteStartAddressValue)) + { + MessageBox.Show("WriteStartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } + if (string.IsNullOrEmpty(WriteData)) + { + MessageBox.Show("WriteData 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + return; + } //去除字符串中的空格 WriteData = WriteData.Replace(" ", ""); //转换为布尔数组 bool[] data = WriteData.Select(m => m == '1').ToArray(); - try - { - _modbusRTU.WriteCoil(byte.Parse(WriteSlaveAddress), - ushort.Parse(WriteStartAddress), - data); - } - catch (Exception) + //使用子线程执行,避免ui线程卡顿 + Task.Run(() => { - - MessageBox.Show("信息配置错误"); - } + bool boo= _modbusRTU.WriteCoil(writeSlaveAddressValue, WriteStartAddressValue, data); + if (boo) + { + MessageBox.Show("写入成功"); + } + + ModbusLogList = GetOperateCoil(); + }); } @@ -220,11 +256,11 @@ namespace ModbusDemo.VIewModel /// private List GetOperateCoil() { - return _modbusDbContext.ModbusLog - .Where(log => log.OperationType == "读线圈" || log.OperationType == "写线圈") - .OrderByDescending(log => log.Time) // 按时间倒序,最新的在前 - .Take(20) // 只取前20条记录 - .ToList(); // 执行查询 + return _modbusDbContext.ModbusLog + .Where(log => log.OperationType == "读线圈" || log.OperationType == "写线圈") + .OrderByDescending(log => log.Time) // 按时间倒序,最新的在前 + .Take(20) // 只取前20条记录 + .ToList(); // 执行查询 } } } diff --git a/ModbusDemo/VIewModel/SettingsUCViewModel.cs b/ModbusDemo/VIewModel/SettingsUCViewModel.cs index 1d3cca7..0726297 100644 --- a/ModbusDemo/VIewModel/SettingsUCViewModel.cs +++ b/ModbusDemo/VIewModel/SettingsUCViewModel.cs @@ -110,6 +110,7 @@ namespace ModbusDemo.VIewModel if (_serialPort.IsOpen) { _serialPort.Close(); + MessageBox.Show("连接已经断开"); } } @@ -118,18 +119,21 @@ namespace ModbusDemo.VIewModel /// private void Connection() { - //todo,做数据的判空处理 + //TODO,做数据的判空处理 if (!_serialPort.IsOpen) { - + _serialPort.PortName = GetComboBoxItemValue(this.PortName); + _serialPort.BaudRate = int.Parse(GetComboBoxItemValue(this.BaudRate)); + _serialPort.Parity = this.Parity; + _serialPort.StopBits = this.StopBits; + _serialPort.DataBits = int.Parse(GetComboBoxItemValue(this.DataBits)); + //读取超时时间 + _serialPort.ReadTimeout = 500; + //写入超时时间 + _serialPort.WriteTimeout = 500; try { - _serialPort.PortName = GetComboBoxItemValue(this.PortName); - _serialPort.BaudRate = int.Parse(GetComboBoxItemValue(this.BaudRate)); - _serialPort.Parity = this.Parity; - _serialPort.StopBits = this.StopBits; - _serialPort.DataBits = int.Parse(GetComboBoxItemValue(this.DataBits)); _serialPort.Open(); MessageBox.Show("串口链接成功"); _regionManager.Regions["ModbusRegion"].RequestNavigate("CoilUC"); @@ -138,7 +142,7 @@ namespace ModbusDemo.VIewModel catch (Exception) { - MessageBox.Show("串口已经链接,请先断开链接在尝试"); + MessageBox.Show("串口已经链接,请先断开链接在尝试","warning",MessageBoxButton.OK,MessageBoxImage.Warning); } }