Ver código fonte

修改线圈bug

dev1
永攀 张 2 semanas atrás
pai
commit
1a541a4654
8 arquivos alterados com 190 adições e 94 exclusões
  1. +1
    -1
      ModbusDemo/App.xaml.cs
  2. +1
    -1
      ModbusDemo/Device/IModbusRTU.cs
  3. +91
    -45
      ModbusDemo/Device/ModbusRTU.cs
  4. +10
    -3
      ModbusDemo/Uitls/CheckData.cs
  5. +3
    -3
      ModbusDemo/VIew/RegisterUC.xaml
  6. +5
    -2
      ModbusDemo/VIew/SettingsUC.xaml
  7. +67
    -31
      ModbusDemo/VIewModel/CoilUCViewModel.cs
  8. +12
    -8
      ModbusDemo/VIewModel/SettingsUCViewModel.cs

+ 1
- 1
ModbusDemo/App.xaml.cs Ver arquivo

@@ -61,7 +61,7 @@ namespace ModbusDemo
.UseSqlServer(configuration.GetConnectionString("ConnStr"))
.Options;

// 3. 注册 DbContext(作用域生命周期)
// 3. 注册 DbContext
containerRegistry.Register<ModbusDbContext>(() => new ModbusDbContext(options));
}
/// <summary>


+ 1
- 1
ModbusDemo/Device/IModbusRTU.cs Ver arquivo

@@ -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);



+ 91
- 45
ModbusDemo/Device/ModbusRTU.cs Ver arquivo

@@ -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
/// <returns></returns>
public bool[] ReadCoil(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
bool[] resultValue = null;

if (!_serialPort.IsOpen)
{
MessageBox.Show("串口没有链接,请先链接");
return null;
return resultValue;
}
List<byte> sendByteList = new List<byte>();
//设置从站地址
@@ -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<byte> responseList = new List<byte>(response);
//移除前两位
responseList.RemoveRange(0, 3);
@@ -129,8 +155,13 @@ namespace ModbusDemo.Device
/// <param name="slaveAddress">从站地址</param>
/// <param name="startAddress">起始地址</param>
/// <param name="data">写入的数据</param>
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<byte> sendByteList = new List<byte>();
//设置从站地址
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)


+ 10
- 3
ModbusDemo/Uitls/CheckData.cs Ver arquivo

@@ -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;
}
}


+ 3
- 3
ModbusDemo/VIew/RegisterUC.xaml Ver arquivo

@@ -151,16 +151,16 @@
<DataGrid ItemsSource="{Binding ModbusLogList}" AutoGenerateColumns="False" IsReadOnly="True" ColumnWidth="*">
<DataGrid.Columns>
<!-- 操作类型列 -->
<DataGridTextColumn Header="操作类型" Binding="{Binding OperationType}" Width="100" />
<DataGridTextColumn Width="100" Header="操作类型" Binding="{Binding OperationType}" />

<!-- 请求数据列 -->
<DataGridTextColumn Header="请求数据" Binding="{Binding RequestData}" />
<DataGridTextColumn Header="请求数据" Binding="{Binding RequestData}" />

<!-- 响应数据列 -->
<DataGridTextColumn Header="响应数据" Binding="{Binding ResponseData}" />

<!-- 操作时间列 -->
<DataGridTextColumn Header="操作时间" Binding="{Binding Time, StringFormat='yyyy-MM-dd HH:mm:ss'}" Width="200"/>
<DataGridTextColumn Width="200" Header="操作时间" Binding="{Binding Time, StringFormat='yyyy-MM-dd HH:mm:ss'}" />
</DataGrid.Columns>
</DataGrid>
</Grid>


+ 5
- 2
ModbusDemo/VIew/SettingsUC.xaml Ver arquivo

@@ -55,6 +55,7 @@
Height="30"
Margin="10,0,0,5"
HorizontalAlignment="Left"
materialDesign:HintAssist.Hint="COM1"
SelectedItem="{Binding PortName}">
<ComboBoxItem Content="COM1" />
<ComboBoxItem Content="COM2" />
@@ -71,6 +72,7 @@
Height="30"
Margin="10,0,0,5"
HorizontalAlignment="Left"
materialDesign:HintAssist.Hint="19200"
SelectedItem="{Binding BaudRate}">
<ComboBoxItem Content="4800" />
<ComboBoxItem Content="9600" />
@@ -118,6 +120,7 @@
Height="30"
Margin="10,0,0,5"
HorizontalAlignment="Left"
materialDesign:HintAssist.Hint="8"
SelectedItem="{Binding DataBits}">
<ComboBoxItem Content="7">
</ComboBoxItem>
@@ -140,7 +143,7 @@
Height="30"
materialDesign:ButtonAssist.CornerRadius="15"
Style="{StaticResource MaterialDesignRaisedDarkButton}"
Content="接"
Content="接"
Command="{Binding ConnectionCmm}">
</Button>
<Button
@@ -150,7 +153,7 @@
materialDesign:ButtonAssist.CornerRadius="15"
Style="{StaticResource MaterialDesignRaisedDarkButton}"
Content="断开"
Command="{Binding ConnectionCmm}">
Command="{Binding DisConnectionCmm}">
</Button>
</Grid>
</Grid>


+ 67
- 31
ModbusDemo/VIewModel/CoilUCViewModel.cs Ver arquivo

@@ -170,47 +170,83 @@ namespace ModbusDemo.VIewModel
/// </summary>
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
/// <returns></returns>
private List<ModbusLog> 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(); // 执行查询
}
}
}

+ 12
- 8
ModbusDemo/VIewModel/SettingsUCViewModel.cs Ver arquivo

@@ -110,6 +110,7 @@ namespace ModbusDemo.VIewModel
if (_serialPort.IsOpen)
{
_serialPort.Close();
MessageBox.Show("连接已经断开");
}
}

@@ -118,18 +119,21 @@ namespace ModbusDemo.VIewModel
/// </summary>
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);
}
}


Carregando…
Cancelar
Salvar