@@ -61,7 +61,7 @@ namespace ModbusDemo | |||
.UseSqlServer(configuration.GetConnectionString("ConnStr")) | |||
.Options; | |||
// 3. 注册 DbContext(作用域生命周期) | |||
// 3. 注册 DbContext | |||
containerRegistry.Register<ModbusDbContext>(() => new ModbusDbContext(options)); | |||
} | |||
/// <summary> | |||
@@ -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); | |||
@@ -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,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; | |||
} | |||
} | |||
@@ -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> | |||
@@ -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> | |||
@@ -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(); // 执行查询 | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||