@@ -1,40 +1,47 @@ | |||
<prism:PrismApplication x:Class="ModbusDemo.App" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:local="clr-namespace:ModbusDemo" | |||
xmlns:prism="http://prismlibrary.com/" | |||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" | |||
> | |||
<prism:PrismApplication | |||
x:Class="ModbusDemo.App" | |||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |||
xmlns:local="clr-namespace:ModbusDemo" | |||
xmlns:prism="http://prismlibrary.com/" | |||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"> | |||
<Application.Resources> | |||
<ResourceDictionary> | |||
<ResourceDictionary.MergedDictionaries> | |||
<!-- 使用捆绑的主题,设置基础主题为浅色,主色为深紫色,次色为酸橙色 --> | |||
<!-- 使用捆绑的主题,设置基础主题为浅色,主色为深紫色,次色为酸橙色 --> | |||
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="LightBlue" SecondaryColor="Lime" /> | |||
<!-- 引用 Material Design 2 的默认样式 --> | |||
<!-- 引用 Material Design 2 的默认样式 --> | |||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesign2.Defaults.xaml" /> | |||
</ResourceDictionary.MergedDictionaries> | |||
<Style x:Key="LeftMenuStyle" TargetType="ListBoxItem"> | |||
<Setter Property="MinHeight" Value="40"></Setter> | |||
<Setter Property="MinHeight" Value="40"> | |||
</Setter> | |||
<Setter Property="Template"> | |||
<Setter.Value> | |||
<ControlTemplate TargetType="ListBoxItem"> | |||
<Grid> | |||
<Border x:Name="border"></Border> | |||
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"></ContentPresenter> | |||
<Border x:Name="border"> | |||
</Border> | |||
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"> | |||
</ContentPresenter> | |||
</Grid> | |||
<!--触发器--> | |||
<!-- 触发器 --> | |||
<ControlTemplate.Triggers> | |||
<Trigger Property="IsSelected" Value="True"> | |||
<Setter TargetName="border" Property="Background" Value="{DynamicResource PrimaryHueLightBrush}"></Setter> | |||
<Setter TargetName="border" Property="Opacity" Value="0.2"></Setter> | |||
<Setter TargetName="border" Property="Background" Value="{DynamicResource PrimaryHueLightBrush}"> | |||
</Setter> | |||
<Setter TargetName="border" Property="Opacity" Value="0.2"> | |||
</Setter> | |||
</Trigger> | |||
<Trigger Property="IsMouseOver" Value="True"> | |||
<Setter TargetName="border" Property="Background" Value="{DynamicResource PrimaryHueLightBrush}"></Setter> | |||
<Setter TargetName="border" Property="Opacity" Value="0.2"></Setter> | |||
<Setter TargetName="border" Property="Background" Value="{DynamicResource PrimaryHueLightBrush}"> | |||
</Setter> | |||
<Setter TargetName="border" Property="Opacity" Value="0.2"> | |||
</Setter> | |||
</Trigger> | |||
</ControlTemplate.Triggers> | |||
</ControlTemplate> | |||
@@ -9,5 +9,9 @@ namespace ModbusDemo.Device | |||
interface IModbusRTU | |||
{ | |||
public bool[] ReadCoil(byte slaveAddress, ushort startAddress, ushort numberOfPoints); | |||
public void WriteCoil(byte slaveAddress, ushort startAddress, bool[] data); | |||
} | |||
} |
@@ -26,7 +26,11 @@ namespace ModbusDemo.Device | |||
/// <returns></returns> | |||
public bool[] ReadCoil(byte slaveAddress, ushort startAddress, ushort numberOfPoints) | |||
{ | |||
if (!_serialPort.IsOpen) | |||
{ | |||
MessageBox.Show("串口没有链接,请先链接"); | |||
return null; | |||
} | |||
List<byte> sendByteList = new List<byte>(); | |||
//设置从站地址 | |||
sendByteList.Add(slaveAddress); | |||
@@ -89,20 +93,84 @@ namespace ModbusDemo.Device | |||
} | |||
//先将字符串转为数组,再反转,再转为字节数组 | |||
char[] chars = result.ToArray().Reverse<char>().ToArray(); | |||
bool[] f = new bool[numberOfPoints]; | |||
bool[] ultimately = new bool[numberOfPoints]; | |||
for (int i = 0; i < numberOfPoints; i++) | |||
{ | |||
if (chars[i] == '1') | |||
{ | |||
f[i] = true; | |||
ultimately[i] = true; | |||
} | |||
else | |||
{ | |||
f[i] = false; | |||
ultimately[i] = false; | |||
} | |||
} | |||
return f; | |||
return ultimately; | |||
} | |||
public void WriteCoil(byte slaveAddress, ushort startAddress, bool[] data) | |||
{ | |||
List<byte> sendByteList = new List<byte>(); | |||
//设置从站地址 | |||
sendByteList.Add(slaveAddress); | |||
//设置功能码 | |||
sendByteList.Add(0x0F); | |||
//设置起始地址的高位和低位 | |||
sendByteList.Add(BitConverter.GetBytes(startAddress)[1]); | |||
sendByteList.Add(BitConverter.GetBytes(startAddress)[0]); | |||
//设置写入几个线圈 | |||
sendByteList.Add(BitConverter.GetBytes(data.Length)[1]); | |||
sendByteList.Add(BitConverter.GetBytes(data.Length)[0]); | |||
// 计算字节数 | |||
int byteCount = (data.Length + 7) / 8; | |||
sendByteList.Add((byte)byteCount); | |||
// 初始化字节数组 | |||
byte[] coilBytes = new byte[byteCount]; | |||
// 把bool数组转换为字节 | |||
for (int i = 0; i < data.Length; i++) | |||
{ | |||
int byteIndex = i / 8; | |||
int bitIndex = i % 8; | |||
if (data[i]) | |||
{ | |||
coilBytes[byteIndex] |= (byte)(1 << bitIndex); | |||
} | |||
} | |||
sendByteList.AddRange(coilBytes); | |||
//获取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); | |||
//判断发送回来的数据是否正确 | |||
CheckData.CheckResponse(response); | |||
if (!CRCUitl.ValidateCRC(response)) | |||
{ | |||
MessageBox.Show("0x14:CRC校验错误"); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -31,6 +31,7 @@ | |||
FontWeight="Black" | |||
FontSize="16"> | |||
</TextBlock> | |||
<!-- 定义读取的数据 --> | |||
<Grid Grid.Row="1"> | |||
<Grid.ColumnDefinitions> | |||
<ColumnDefinition> | |||
@@ -44,34 +45,89 @@ | |||
<ColumnDefinition> | |||
</ColumnDefinition> | |||
</Grid.ColumnDefinitions> | |||
<StackPanel Orientation="Vertical" HorizontalAlignment="Center"> | |||
<TextBlock Text="从站地址" Margin="20"></TextBlock> | |||
<TextBox Text="{Binding SlaveAddress}" Margin="0,-10,0,0"></TextBox> | |||
<StackPanel HorizontalAlignment="Center" Orientation="Vertical"> | |||
<TextBlock Margin="20" Text="从站地址"> | |||
</TextBlock> | |||
<TextBox Margin="0,-10,0,0" Text="{Binding SlaveAddress}"> | |||
</TextBox> | |||
</StackPanel> | |||
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="1"> | |||
<TextBlock Text="起始地址" Margin="20"></TextBlock> | |||
<TextBox Text="{Binding StartAddress}" Margin="0,-10,0,0"></TextBox> | |||
<StackPanel Grid.Column="1" HorizontalAlignment="Center" Orientation="Vertical"> | |||
<TextBlock Margin="20" Text="起始地址"> | |||
</TextBlock> | |||
<TextBox Margin="0,-10,0,0" Text="{Binding StartAddress}"> | |||
</TextBox> | |||
</StackPanel> | |||
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="2"> | |||
<TextBlock Text="读取位数" Margin="20"></TextBlock> | |||
<TextBox Text="{Binding NumberOfPoints}" Margin="0,-10,0,0"></TextBox> | |||
<StackPanel Grid.Column="2" HorizontalAlignment="Center" Orientation="Vertical"> | |||
<TextBlock Margin="20" Text="读取位数"> | |||
</TextBlock> | |||
<TextBox Margin="0,-10,0,0" Text="{Binding NumberOfPoints}"> | |||
</TextBox> | |||
</StackPanel> | |||
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="3"> | |||
<TextBlock Text="读取结果" Margin="20"></TextBlock> | |||
<TextBox Text="{Binding ReadResult}" Margin="0,-10,0,0"></TextBox> | |||
<StackPanel Grid.Column="3" HorizontalAlignment="Center" Orientation="Vertical"> | |||
<TextBlock Margin="20" Text="读取结果"> | |||
</TextBlock> | |||
<TextBox Margin="0,-10,0,0" Text="{Binding ReadResult}"> | |||
</TextBox> | |||
</StackPanel> | |||
<Button | |||
Grid.Column="4" | |||
Width="80" | |||
Height="30" | |||
Command="{Binding ReadCoilCmm}" | |||
materialDesign:ButtonAssist.CornerRadius="15" | |||
Command="{Binding ReadCoilCmm}" | |||
Content="读取" | |||
Style="{StaticResource MaterialDesignRaisedDarkButton}"> | |||
</Button> | |||
</Grid> | |||
<Grid Grid.Row="2"> | |||
<Grid.ColumnDefinitions> | |||
<ColumnDefinition> | |||
</ColumnDefinition> | |||
<ColumnDefinition> | |||
</ColumnDefinition> | |||
<ColumnDefinition> | |||
</ColumnDefinition> | |||
<ColumnDefinition> | |||
</ColumnDefinition> | |||
<ColumnDefinition> | |||
</ColumnDefinition> | |||
</Grid.ColumnDefinitions> | |||
<StackPanel HorizontalAlignment="Center" Orientation="Vertical"> | |||
<TextBlock Margin="20" Text="从站地址"> | |||
</TextBlock> | |||
<TextBox Margin="0,-10,0,0" Text="{Binding WriteSlaveAddress}"> | |||
</TextBox> | |||
</StackPanel> | |||
<StackPanel Grid.Column="1" HorizontalAlignment="Center" Orientation="Vertical"> | |||
<TextBlock Margin="20" Text="起始地址"> | |||
</TextBlock> | |||
<TextBox Margin="0,-10,0,0" Text="{Binding WriteStartAddress}"> | |||
</TextBox> | |||
</StackPanel> | |||
<StackPanel Grid.Column="2" HorizontalAlignment="Center" Orientation="Vertical"> | |||
<TextBlock Margin="20" Text="写入数据"> | |||
</TextBlock> | |||
<TextBox Margin="0,-10,0,0" Text="{Binding WriteData}"> | |||
</TextBox> | |||
</StackPanel> | |||
<TextBlock Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Center" Text="1代表Ture,0代表flase"> | |||
</TextBlock> | |||
<Button | |||
Grid.Column="4" | |||
Width="80" | |||
Height="30" | |||
materialDesign:ButtonAssist.CornerRadius="15" | |||
Command="{Binding WriteCoilCmm}" | |||
Content="写入" | |||
Style="{StaticResource MaterialDesignRaisedDarkButton}"> | |||
</Button> | |||
</Grid> | |||
</Grid> | |||
</UserControl> |
@@ -20,6 +20,8 @@ namespace ModbusDemo.VIewModel | |||
private IModbusRTU _modbusRTU; | |||
//定义读线圈的命令 | |||
public DelegateCommand ReadCoilCmm { get; set; } | |||
//定义写线圈操作 | |||
public DelegateCommand WriteCoilCmm { get; set; } | |||
//获取当前使用的串口 | |||
private SerialPort _serialPort; | |||
//显示当前链接串口的信息 | |||
@@ -32,7 +34,7 @@ namespace ModbusDemo.VIewModel | |||
} | |||
} | |||
#region 读取定义 | |||
//读取的从站id | |||
private string _slaveAddress; | |||
@@ -46,10 +48,10 @@ namespace ModbusDemo.VIewModel | |||
RaisePropertyChanged(); | |||
} | |||
} | |||
//读取的起始地址 | |||
private string _startAddress; | |||
//读取的起始地址 | |||
public string StartAddress | |||
{ | |||
get { return _startAddress; } | |||
@@ -59,10 +61,10 @@ namespace ModbusDemo.VIewModel | |||
RaisePropertyChanged(); | |||
} | |||
} | |||
//读取的位数 | |||
private string _numberOfPoints; | |||
//读取的位数 | |||
public string NumberOfPoints | |||
{ | |||
get { return _numberOfPoints; } | |||
@@ -85,9 +87,51 @@ namespace ModbusDemo.VIewModel | |||
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 CoilUCViewModel() | |||
{ | |||
@@ -98,30 +142,31 @@ namespace ModbusDemo.VIewModel | |||
_serialPort = serialPort; | |||
ReadCoilCmm = new DelegateCommand(ReadCoil); | |||
_modbusRTU = modbusRTU; | |||
WriteCoilCmm = new DelegateCommand(WriteCoil); | |||
} | |||
private void ReadCoil() | |||
{ | |||
/// <summary> | |||
/// 线圈读取操作 | |||
/// </summary> | |||
private void ReadCoil() | |||
{ | |||
try | |||
{ | |||
bool[] result = _modbusRTU.ReadCoil(byte.Parse(SlaveAddress), | |||
ushort.Parse(StartAddress), | |||
ushort.Parse(NumberOfPoints)); | |||
if(result != null) | |||
if (result != null) | |||
{ | |||
string temp = ""; | |||
foreach(var item in result) | |||
foreach (var item in result) | |||
{ | |||
temp += item; | |||
temp += " "; | |||
} | |||
ReadResult = temp; | |||
} | |||
} | |||
catch (Exception) | |||
{ | |||
@@ -129,9 +174,26 @@ namespace ModbusDemo.VIewModel | |||
MessageBox.Show("参数配置错误"); | |||
} | |||
} | |||
private void WriteCoil() | |||
{ | |||
//去除字符串中的空格 | |||
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("信息配置错误"); | |||
} | |||
} | |||
} | |||
} |