diff --git a/ModbusDemo/App.xaml.cs b/ModbusDemo/App.xaml.cs index e71e464..a4a13d8 100644 --- a/ModbusDemo/App.xaml.cs +++ b/ModbusDemo/App.xaml.cs @@ -47,7 +47,8 @@ namespace ModbusDemo containerRegistry.RegisterSingleton(); //将读线圈注册 containerRegistry.Register(); - + //附加功能如何读取单数寄存器; + containerRegistry.RegisterForNavigation(); // 1. 加载配置文件 diff --git a/ModbusDemo/Device/ModbusRTU.cs b/ModbusDemo/Device/ModbusRTU.cs index 88f5635..afd944f 100644 --- a/ModbusDemo/Device/ModbusRTU.cs +++ b/ModbusDemo/Device/ModbusRTU.cs @@ -13,7 +13,7 @@ namespace ModbusDemo.Device { public class ModbusRTU : IModbusRTU { - + //串口 private SerialPort _serialPort; //用于操作数据库 private ModbusDbContext _modbusDbContext; @@ -106,7 +106,13 @@ namespace ModbusDemo.Device return resultValue; } - + /// + /// 用来解析返回的数据 + /// + /// + /// + /// + /// public bool[] ParseCoilresponse(byte[] sendByte, byte[] response, ushort numberOfPoints) { //将操作的指令,插入数据库 @@ -266,7 +272,13 @@ namespace ModbusDemo.Device } } - + /// + /// 读寄存器操作 + /// + /// + /// + /// + /// public ushort[] ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints) { ushort[] resultValue = null; @@ -346,6 +358,13 @@ namespace ModbusDemo.Device } + /// + /// 解析读取到的操作 + /// + /// + /// + /// + /// public ushort[] ParseRegistersresponse(byte[] sendByte, byte[] response, ushort numberOfPoints) { //将操作的指令,插入数据库 @@ -380,7 +399,12 @@ namespace ModbusDemo.Device } - + /// + /// 写寄存器 + /// + /// + /// + /// public void WriteRegisters(byte slaveAddress, ushort startAddress, ushort[] data) { if (!_serialPort.IsOpen) @@ -472,7 +496,11 @@ namespace ModbusDemo.Device } - + /// + /// 将数组转换为字符串 + /// + /// + /// static string ByteArrayToString(byte[] byteArray) { if (byteArray == null || byteArray.Length == 0) diff --git a/ModbusDemo/ModbusDemo.csproj b/ModbusDemo/ModbusDemo.csproj index d32b218..6ff48c3 100644 --- a/ModbusDemo/ModbusDemo.csproj +++ b/ModbusDemo/ModbusDemo.csproj @@ -13,6 +13,7 @@ + diff --git a/ModbusDemo/VIew/AttachUC.xaml b/ModbusDemo/VIew/AttachUC.xaml new file mode 100644 index 0000000..30c8ae1 --- /dev/null +++ b/ModbusDemo/VIew/AttachUC.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ModbusDemo/VIew/AttachUC.xaml.cs b/ModbusDemo/VIew/AttachUC.xaml.cs new file mode 100644 index 0000000..c038932 --- /dev/null +++ b/ModbusDemo/VIew/AttachUC.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace ModbusDemo.VIew +{ + /// + /// AttachUC.xaml 的交互逻辑 + /// + public partial class AttachUC : UserControl + { + public AttachUC() + { + InitializeComponent(); + } + } +} diff --git a/ModbusDemo/VIew/CoilUC.xaml b/ModbusDemo/VIew/CoilUC.xaml index 355c37f..951336f 100644 --- a/ModbusDemo/VIew/CoilUC.xaml +++ b/ModbusDemo/VIew/CoilUC.xaml @@ -88,6 +88,7 @@ Grid.Column="4" Width="80" Height="40" + IsEnabled="{Binding IsEnable}" materialDesign:ButtonAssist.CornerRadius="20" Command="{Binding ReadCoilCmm}" Content="读取" @@ -142,6 +143,7 @@ Width="80" Height="40" materialDesign:ButtonAssist.CornerRadius="20" + IsEnabled="{Binding IsEnable}" Command="{Binding WriteCoilCmm}" Content="写入" Style="{StaticResource MaterialDesignRaisedDarkButton}"> diff --git a/ModbusDemo/VIew/RegisterUC.xaml b/ModbusDemo/VIew/RegisterUC.xaml index ba45f44..e19a195 100644 --- a/ModbusDemo/VIew/RegisterUC.xaml +++ b/ModbusDemo/VIew/RegisterUC.xaml @@ -88,6 +88,7 @@ Grid.Column="4" Width="80" Height="40" + IsEnabled="{Binding IsEnable}" materialDesign:ButtonAssist.CornerRadius="20" Command="{Binding ReadRegisterCmm}" Content="读取" @@ -141,6 +142,7 @@ Grid.Column="4" Width="80" Height="40" + IsEnabled="{Binding IsEnable}" materialDesign:ButtonAssist.CornerRadius="20" Command="{Binding WriteRegisterCmm}" Content="写入" diff --git a/ModbusDemo/VIew/SettingsUC.xaml b/ModbusDemo/VIew/SettingsUC.xaml index 6b3a738..057af00 100644 --- a/ModbusDemo/VIew/SettingsUC.xaml +++ b/ModbusDemo/VIew/SettingsUC.xaml @@ -55,7 +55,7 @@ Height="30" Margin="10,0,0,5" HorizontalAlignment="Left" - materialDesign:HintAssist.Hint="COM1" + materialDesign:HintAssist.Hint="COM3" SelectedItem="{Binding PortName}"> diff --git a/ModbusDemo/VIewModel/AttachUCViewModel.cs b/ModbusDemo/VIewModel/AttachUCViewModel.cs new file mode 100644 index 0000000..248d0f4 --- /dev/null +++ b/ModbusDemo/VIewModel/AttachUCViewModel.cs @@ -0,0 +1,107 @@ +using Modbus.Device; +using Prism.Commands; +using Prism.Mvvm; +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace ModbusDemo.VIewModel +{ + public class AttachUCViewModel : BindableBase + { + + private SerialPort _serialPort; + public DelegateCommand ReadOddRegisterCmm { get; set; } + //读取的结果 + private string _readResult; + + public string ReadResult + { + get { return _readResult; } + set + { + _readResult = value; + RaisePropertyChanged(); + } + } + //显示操作的时间 + private int _time; + + public int Time + { + get { return _time; } + set + { + _time = value; + RaisePropertyChanged(); + } + } + + + public AttachUCViewModel() + { + + } + public AttachUCViewModel(SerialPort serialPort) + { + ReadOddRegisterCmm = new DelegateCommand(ReadOddRegister); + _serialPort = serialPort; + } + + private void ReadOddRegister() + { + // 创建 Modbus RTU 主站 + + IModbusSerialMaster master = ModbusSerialMaster.CreateRtu(_serialPort); + 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(() => + { + try + { + ushort[] registers = master.ReadHoldingRegisters(slaveId, startAddress, currentChunkSize); + Array.Copy(registers, 0, allRegisters, chunkIndex * chunkSize, currentChunkSize); + } + catch (Exception ex) + { + Console.WriteLine($"线程 {chunkIndex} 读取寄存器时出错: {ex.Message}"); + } + }); + } + + // 等待所有任务完成 + 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(); + + } + } + +} diff --git a/ModbusDemo/VIewModel/CoilUCViewModel.cs b/ModbusDemo/VIewModel/CoilUCViewModel.cs index df5914b..6f7012b 100644 --- a/ModbusDemo/VIewModel/CoilUCViewModel.cs +++ b/ModbusDemo/VIewModel/CoilUCViewModel.cs @@ -28,6 +28,20 @@ namespace ModbusDemo.VIewModel //获取当前使用的串口 private SerialPort _serialPort; //显示当前链接串口的信息 + + //按钮是否可以点击 + private bool _isEnable; + + public bool IsEnable + { + get { return _isEnable; } + set + { + _isEnable = value; + RaisePropertyChanged(); + } + } + public string SerialPortInfo { get @@ -163,6 +177,7 @@ namespace ModbusDemo.VIewModel _modbusDbContext = modbusDbContext; //初始化查询操作 ModbusLogList = GetOperateCoil(); + IsEnable = true; } /// @@ -170,23 +185,29 @@ namespace ModbusDemo.VIewModel /// private void ReadCoil() { + //将按钮设置为不可点击状态,并解析用户输入的信息 + IsEnable = false; if (!byte.TryParse(SlaveAddress, out byte slaveAddressValue)) { MessageBox.Show("SlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (!ushort.TryParse(StartAddress, out ushort startAddressValue)) { MessageBox.Show("StartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (!ushort.TryParse(NumberOfPoints, out ushort numberOfPointsValue)) { MessageBox.Show("NumberOfPoints 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } + //使用子线程,防止ui线程卡顿 Task.Run(() => { @@ -196,6 +217,7 @@ namespace ModbusDemo.VIewModel { MessageBox.Show("读取失败", "error", MessageBoxButton.OK, MessageBoxImage.Error); ModbusLogList = GetOperateCoil(); + IsEnable = true; return; } @@ -207,6 +229,7 @@ namespace ModbusDemo.VIewModel } ReadResult = temp; MessageBox.Show("读取成功"); + IsEnable = true; ModbusLogList = GetOperateCoil(); }); @@ -217,19 +240,24 @@ namespace ModbusDemo.VIewModel private void WriteCoil() { + //将按钮设置为不可点击状态,并解析用户输入的信息 + IsEnable = false; if (!byte.TryParse(WriteSlaveAddress, out byte writeSlaveAddressValue)) { MessageBox.Show("WriteSlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (!ushort.TryParse(WriteStartAddress, out ushort WriteStartAddressValue)) { MessageBox.Show("WriteStartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (string.IsNullOrEmpty(WriteData)) { MessageBox.Show("WriteData 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } //去除字符串中的空格 @@ -243,14 +271,15 @@ namespace ModbusDemo.VIewModel _modbusRTU.WriteCoil(writeSlaveAddressValue, WriteStartAddressValue, data); ModbusLogList = GetOperateCoil(); ModbusLog modbusLog = ModbusLogList.FirstOrDefault(); - if (modbusLog != null && modbusLog.ResponseData != string.Empty) + if (modbusLog != null && modbusLog.ResponseData != string.Empty && modbusLog.ResponseData[3] !='8') { MessageBox.Show("写入成功"); - + IsEnable = true; } else { MessageBox.Show("写入失败", "error", MessageBoxButton.OK, MessageBoxImage.Error); + IsEnable = true; } }); diff --git a/ModbusDemo/VIewModel/MainWindowViewModel.cs b/ModbusDemo/VIewModel/MainWindowViewModel.cs index 093fff5..abad9e2 100644 --- a/ModbusDemo/VIewModel/MainWindowViewModel.cs +++ b/ModbusDemo/VIewModel/MainWindowViewModel.cs @@ -66,6 +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" }); } public void DefultNaigation() diff --git a/ModbusDemo/VIewModel/RegisterUCViewModel.cs b/ModbusDemo/VIewModel/RegisterUCViewModel.cs index a952b07..95eecef 100644 --- a/ModbusDemo/VIewModel/RegisterUCViewModel.cs +++ b/ModbusDemo/VIewModel/RegisterUCViewModel.cs @@ -24,6 +24,20 @@ namespace ModbusDemo.VIewModel public DelegateCommand WriteRegisterCmm { get; set; } //获取当前使用的串口 private SerialPort _serialPort; + + //按钮是否可以点击 + private bool _isEnable; + + public bool IsEnable + { + get { return _isEnable; } + set + { + _isEnable = value; + RaisePropertyChanged(); + } + } + //显示当前链接串口的信息 public string SerialPortInfo { @@ -159,6 +173,7 @@ namespace ModbusDemo.VIewModel ModbusLogList = GetOperateRegister(); + IsEnable = true; } @@ -169,21 +184,26 @@ namespace ModbusDemo.VIewModel /// private void ReadRegister() { + //将按钮设置为不可点击状态,并解析用户输入的信息 + IsEnable = false; if (!byte.TryParse(SlaveAddress, out byte slaveAddressValue)) { MessageBox.Show("SlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (!ushort.TryParse(StartAddress, out ushort startAddressValue)) { MessageBox.Show("StartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (!ushort.TryParse(NumberOfPoints, out ushort numberOfPointsValue)) { MessageBox.Show("NumberOfPoints 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } //使用子线程进行读取,防止ui线程卡顿 @@ -194,6 +214,7 @@ namespace ModbusDemo.VIewModel { MessageBox.Show("读取失败", "error", MessageBoxButton.OK, MessageBoxImage.Error); ModbusLogList = GetOperateRegister(); + IsEnable = true; return; } string temp = ""; @@ -204,6 +225,7 @@ namespace ModbusDemo.VIewModel } ReadResult = temp; MessageBox.Show("读取成功"); + IsEnable = true; ModbusLogList = GetOperateRegister(); }); @@ -213,19 +235,24 @@ namespace ModbusDemo.VIewModel private void WriteRegister() { + //将按钮设置为不可点击状态,并解析用户输入的信息 + IsEnable = false; if (!byte.TryParse(WriteSlaveAddress, out byte writeSlaveAddressValue)) { MessageBox.Show("WriteSlaveAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (!ushort.TryParse(WriteStartAddress, out ushort WriteStartAddressValue)) { MessageBox.Show("WriteStartAddress 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } if (string.IsNullOrEmpty(WriteData)) { MessageBox.Show("WriteData 格式无效", "warning", MessageBoxButton.OK, MessageBoxImage.Warning); + IsEnable = true; return; } string[] parts = WriteData.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); @@ -244,6 +271,7 @@ namespace ModbusDemo.VIewModel { MessageBox.Show($"无法将 '{parts[i]}' 转换为 ushort 类型"); + IsEnable = true; return; } } @@ -254,14 +282,15 @@ namespace ModbusDemo.VIewModel _modbusRTU.WriteRegisters(writeSlaveAddressValue, WriteStartAddressValue, data); ModbusLogList = GetOperateRegister(); ModbusLog modbusLog = ModbusLogList.FirstOrDefault(); - if (modbusLog != null && modbusLog.ResponseData != string.Empty) + if (modbusLog != null && modbusLog.ResponseData != string.Empty && modbusLog.ResponseData[3] != '8') { MessageBox.Show("写入成功"); - + IsEnable = true; } else { MessageBox.Show("写入失败", "error", MessageBoxButton.OK, MessageBoxImage.Error); + IsEnable = true; } }); diff --git a/ModbusDemo/VIewModel/SettingsUCViewModel.cs b/ModbusDemo/VIewModel/SettingsUCViewModel.cs index 8eb872b..14bfcd7 100644 --- a/ModbusDemo/VIewModel/SettingsUCViewModel.cs +++ b/ModbusDemo/VIewModel/SettingsUCViewModel.cs @@ -25,7 +25,7 @@ namespace ModbusDemo.VIewModel //获取串口 private SerialPort _serialPort; //设置串口名字 - private string _portName = "COM1"; + private string _portName = "COM3"; public string PortName {