From 6f9e9a76e9a10de8c00c9e2f2f624c2bc813df70 Mon Sep 17 00:00:00 2001 From: zhangyongpan Date: Sat, 26 Jul 2025 19:14:07 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=BB=E5=8F=96=E5=AF=84=E5=AD=98=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ModbusDemo/Device/IModbusRTU.cs | 2 + ModbusDemo/Device/ModbusRTU.cs | 72 ++++++- .../Extension/EnumBindingSourceExtension.cs | 3 + ModbusDemo/MainWindow.xaml | 19 +- ModbusDemo/VIew/CoilUC.xaml | 28 ++- ModbusDemo/VIew/RegisterUC.xaml | 138 ++++++++++++- ModbusDemo/VIewModel/RegisterUCViewModel.cs | 187 +++++++++++++++++- ModbusDemo/VIewModel/SettingsUCViewModel.cs | 9 +- 8 files changed, 440 insertions(+), 18 deletions(-) diff --git a/ModbusDemo/Device/IModbusRTU.cs b/ModbusDemo/Device/IModbusRTU.cs index 847e908..250c8d5 100644 --- a/ModbusDemo/Device/IModbusRTU.cs +++ b/ModbusDemo/Device/IModbusRTU.cs @@ -13,5 +13,7 @@ namespace ModbusDemo.Device public void 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 0c3fae7..aee8904 100644 --- a/ModbusDemo/Device/ModbusRTU.cs +++ b/ModbusDemo/Device/ModbusRTU.cs @@ -58,7 +58,7 @@ namespace ModbusDemo.Device Thread.Sleep(300); byte[] response = new byte[_serialPort.BytesToRead]; _serialPort.Read(response, 0, _serialPort.BytesToRead); - return Parseresponse(response,numberOfPoints); + return ParseCoilresponse(response,numberOfPoints); } @@ -66,7 +66,7 @@ namespace ModbusDemo.Device } - public bool[] Parseresponse(byte[] response, ushort numberOfPoints) + public bool[] ParseCoilresponse(byte[] response, ushort numberOfPoints) { //判断发送回来的数据是否正确 CheckData.CheckResponse(response); @@ -107,7 +107,12 @@ namespace ModbusDemo.Device } return ultimately; } - + /// + /// 写入多个线圈操作 + /// + /// 从站地址 + /// 起始地址 + /// 写入的数据 public void WriteCoil(byte slaveAddress, ushort startAddress, bool[] data) { List sendByteList = new List(); @@ -172,5 +177,66 @@ namespace ModbusDemo.Device } + + public ushort[] ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints) + { + if (!_serialPort.IsOpen) + { + MessageBox.Show("串口没有链接,请先链接"); + return null; + } + 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(); + if (_serialPort.IsOpen) + { + // 清空接收缓冲区(避免残留数据干扰) + _serialPort.DiscardInBuffer(); + + _serialPort.Write(sendByte, 0, sendByte.Length); + Thread.Sleep(300); + byte[] response = new byte[_serialPort.BytesToRead]; + _serialPort.Read(response, 0, _serialPort.BytesToRead); + return ParseRegistersresponse(response, numberOfPoints); + } + + return null; + } + public ushort[] ParseRegistersresponse(byte[] response, ushort numberOfPoints) + { + //判断发送回来的数据是否正确 + CheckData.CheckResponse(response); + + if (!CRCUitl.ValidateCRC(response)) + { + MessageBox.Show("0x14:CRC校验错误"); + return null; + } + + 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; + } } } diff --git a/ModbusDemo/Extension/EnumBindingSourceExtension.cs b/ModbusDemo/Extension/EnumBindingSourceExtension.cs index 027db05..29320aa 100644 --- a/ModbusDemo/Extension/EnumBindingSourceExtension.cs +++ b/ModbusDemo/Extension/EnumBindingSourceExtension.cs @@ -7,6 +7,9 @@ using System.Windows.Markup; namespace ModbusDemo.Extension { + /// + /// 此处代码是复制粘贴,用来让枚举类型绑定到下拉框上 + /// class EnumBindingSourceExtension : MarkupExtension { private Type _enumType; diff --git a/ModbusDemo/MainWindow.xaml b/ModbusDemo/MainWindow.xaml index e3fd029..f38d325 100644 --- a/ModbusDemo/MainWindow.xaml +++ b/ModbusDemo/MainWindow.xaml @@ -7,16 +7,18 @@ xmlns:local="clr-namespace:ModbusDemo" xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" - xmlns:prism="http://prismlibrary.com/" - xmlns:viewmodel="clr-namespace:ModbusDemo.VIewModel" - d:DataContext="{d:DesignInstance Type=viewmodel:MainWindowViewModel,IsDesignTimeCreatable=True}" + xmlns:prism="http://prismlibrary.com/" + xmlns:viewmodel="clr-namespace:ModbusDemo.VIewModel" Title="MainWindow" Width="900" Height="600" + d:DataContext="{d:DesignInstance Type=viewmodel:MainWindowViewModel, + IsDesignTimeCreatable=True}" WindowStartupLocation="CenterScreen" mc:Ignorable="d"> - + + @@ -37,8 +39,13 @@ - - + + diff --git a/ModbusDemo/VIew/CoilUC.xaml b/ModbusDemo/VIew/CoilUC.xaml index 3ac4a84..db83084 100644 --- a/ModbusDemo/VIew/CoilUC.xaml +++ b/ModbusDemo/VIew/CoilUC.xaml @@ -13,6 +13,12 @@ d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d"> + + + @@ -45,6 +51,10 @@ + + + + @@ -66,11 +76,11 @@ - - - - - + + + + + + @@ -115,7 +126,12 @@ - + diff --git a/ModbusDemo/VIew/RegisterUC.xaml b/ModbusDemo/VIew/RegisterUC.xaml index b0f47d4..adaf8cb 100644 --- a/ModbusDemo/VIew/RegisterUC.xaml +++ b/ModbusDemo/VIew/RegisterUC.xaml @@ -5,11 +5,147 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:ModbusDemo.VIew" + xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:viewmodel="clr-namespace:ModbusDemo.VIewModel" + d:DataContext="{d:DesignInstance Type=viewmodel:RegisterUCViewModel, + IsDesignTimeCreatable=True}" d:DesignHeight="450" + d:Background="White" d:DesignWidth="800" mc:Ignorable="d"> + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ModbusDemo/VIewModel/RegisterUCViewModel.cs b/ModbusDemo/VIewModel/RegisterUCViewModel.cs index 2a5747f..dbf94e9 100644 --- a/ModbusDemo/VIewModel/RegisterUCViewModel.cs +++ b/ModbusDemo/VIewModel/RegisterUCViewModel.cs @@ -1,13 +1,198 @@ -using Prism.Mvvm; +using ModbusDemo.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 { class RegisterUCViewModel:BindableBase { + + //获取读线圈的类 + private IModbusRTU _modbusRTU; + //定义读线圈的命令 + public DelegateCommand ReadRegisterCmm { get; set; } + //定义写线圈操作 + public DelegateCommand WriteRegisterCmm { get; set; } + //获取当前使用的串口 + private SerialPort _serialPort; + //显示当前链接串口的信息 + public string SerialPortInfo + { + get + { + return "当前链接的状态:" + "串口号:" + _serialPort.PortName + ",波特率:" + _serialPort.BaudRate + + ",数据位:" + _serialPort.DataBits + ",校验位:" + _serialPort.Parity + ",停止位:" + _serialPort.StopBits; + } + + } + #region 读取定义 + + //读取的从站id + private string _slaveAddress; + + public string SlaveAddress + { + get { return _slaveAddress; } + set + { + _slaveAddress = value; + RaisePropertyChanged(); + } + } + //读取的起始地址 + private string _startAddress; + + + public string StartAddress + { + get { return _startAddress; } + set + { + _startAddress = value; + RaisePropertyChanged(); + } + } + //读取的位数 + private string _numberOfPoints; + + + public string NumberOfPoints + { + get { return _numberOfPoints; } + set + { + _numberOfPoints = value; + RaisePropertyChanged(); + } + } + + private string _readResult; + + //读取的结果 + public string ReadResult + { + get { return _readResult; } + set + { + _readResult = value; + RaisePropertyChanged(); + } + } + #endregion + + #region 写入定义 + + //写入的从站id + private string _writeslaveAddress; + + public string WriteSlaveAddress + { + get { return _writeslaveAddress; } + set + { + _writeslaveAddress = value; + RaisePropertyChanged(); + } + } + //写入的起始地址 + private string _writestartAddress; + + + public string WriteStartAddress + { + get { return _writestartAddress; } + set + { + _writestartAddress = value; + RaisePropertyChanged(); + } + } + //写入的数据 + private string _writeData; + + + public string WriteData + { + get { return _writeData; } + set + { + _writeData = value; + RaisePropertyChanged(); + } + } + + + #endregion + + public RegisterUCViewModel() + { + + } + public RegisterUCViewModel(SerialPort serialPort, ModbusRTU modbusRTU) + { + _serialPort = serialPort; + ReadRegisterCmm = new DelegateCommand(ReadRegister); + _modbusRTU = modbusRTU; + WriteRegisterCmm = new DelegateCommand(WriteRegister); + } + + + + + /// + /// 线圈读取操作 + /// + private void ReadRegister() + { + try + { + ushort[] result = _modbusRTU.ReadRegisters(byte.Parse(SlaveAddress), + ushort.Parse(StartAddress), + ushort.Parse(NumberOfPoints)); + if (result != null) + { + string temp = ""; + foreach (var item in result) + { + temp += item; + temp += " "; + } + ReadResult = temp; + } + } + catch (Exception) + { + + MessageBox.Show("参数配置错误"); + } + + } + private void WriteRegister() + { + //去除字符串中的空格 + WriteData = WriteData.Replace(" ", ""); + //转换为布尔数组 + bool[] data = WriteData.Select(m => m == '1').ToArray(); + + try + { + _modbusRTU.WriteCoil(byte.Parse(WriteSlaveAddress), + ushort.Parse(WriteStartAddress), + data); + } + catch (Exception) + { + + MessageBox.Show("信息配置错误"); + } + + } } } diff --git a/ModbusDemo/VIewModel/SettingsUCViewModel.cs b/ModbusDemo/VIewModel/SettingsUCViewModel.cs index 79beda4..1d3cca7 100644 --- a/ModbusDemo/VIewModel/SettingsUCViewModel.cs +++ b/ModbusDemo/VIewModel/SettingsUCViewModel.cs @@ -1,6 +1,7 @@ using ModbusDemo.Uitls; using Prism.Commands; using Prism.Mvvm; +using Prism.Regions; using System; using System.Collections.Generic; using System.IO.Ports; @@ -14,6 +15,9 @@ namespace ModbusDemo.VIewModel class SettingsUCViewModel : BindableBase { + //控制页面跳转 + private readonly IRegionManager _regionManager; + //断开连接的命令 public DelegateCommand DisConnectionCmm { get; set; } //链接窗口的命令 public DelegateCommand ConnectionCmm { get; set; } @@ -93,11 +97,12 @@ namespace ModbusDemo.VIewModel /// 从容器中获取创建的窗口 /// /// - public SettingsUCViewModel(SerialPort serialPort) + public SettingsUCViewModel(SerialPort serialPort, IRegionManager regionManager) { _serialPort = serialPort; ConnectionCmm = new DelegateCommand(Connection); DisConnectionCmm = new DelegateCommand(DisConnection); + _regionManager = regionManager; } private void DisConnection() @@ -127,6 +132,8 @@ namespace ModbusDemo.VIewModel _serialPort.DataBits = int.Parse(GetComboBoxItemValue(this.DataBits)); _serialPort.Open(); MessageBox.Show("串口链接成功"); + _regionManager.Regions["ModbusRegion"].RequestNavigate("CoilUC"); + } catch (Exception) {