using Modbus.Device;
using ModbusDemo.Model;
using ModbusDemo.Uitls;
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;
}
///
/// 读1000个寄存器
///
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)
{
MessageBox.Show($"线程 {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();
}
///
/// 自己的类
///
private void ReadOddRegister2()
{
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(async () =>
{
ushort[] registers = await ReadRegisters(slaveId, startAddress, currentChunkSize);
Array.Copy(registers, 0, allRegisters, chunkIndex * chunkSize, currentChunkSize);
});
}
// 等待所有任务完成
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();
}
public async Task ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
{
ushort[] resultValue = null;
if (!_serialPort.IsOpen)
{
MessageBox.Show("串口没有链接,请先链接");
return resultValue;
}
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();
int maxRetries = 3; // 最大重试次数
int attempt = 0;
List responseData = new List();
byte[] response = null;
_serialPort.Write(sendByte, 0, sendByte.Length);
while (attempt < maxRetries)
{
try
{
//使用时间去轮询查询数据
DateTime startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalMilliseconds < _serialPort.ReadTimeout)
{
int bytesToRead = _serialPort.BytesToRead;
if (bytesToRead > 0)
{
byte[] buffer = new byte[bytesToRead];
int bytesRead = _serialPort.Read(buffer, 0, bytesToRead);
responseData.AddRange(buffer.Take(bytesRead));
}
//延迟20毫秒,节约cpu资源
await Task.Delay(20);
}
response = responseData.ToArray();
if (response[0] == 0x00)
{
continue;
}
resultValue = ParseRegistersresponse(sendByte, response, numberOfPoints);
return resultValue;
}
catch (Exception)
{
attempt++;
}
}
return resultValue;
}
public ushort[] ParseRegistersresponse(byte[] sendByte, byte[] response, ushort numberOfPoints)
{
//判断发送回来的数据是否正确
if (CheckData.CheckResponse(response))
{
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;
}
else
{
return null;
}
}
}
}