You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

255 lines
8.3 KiB

  1. using Modbus.Device;
  2. using ModbusDemo.Model;
  3. using ModbusDemo.Uitls;
  4. using Prism.Commands;
  5. using Prism.Mvvm;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.IO.Ports;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Windows;
  13. namespace ModbusDemo.VIewModel
  14. {
  15. public class AttachUCViewModel : BindableBase
  16. {
  17. private SerialPort _serialPort;
  18. public DelegateCommand ReadOddRegisterCmm { get; set; }
  19. //读取的结果
  20. private string _readResult;
  21. public string ReadResult
  22. {
  23. get { return _readResult; }
  24. set
  25. {
  26. _readResult = value;
  27. RaisePropertyChanged();
  28. }
  29. }
  30. //显示操作的时间
  31. private int _time;
  32. public int Time
  33. {
  34. get { return _time; }
  35. set
  36. {
  37. _time = value;
  38. RaisePropertyChanged();
  39. }
  40. }
  41. public AttachUCViewModel()
  42. {
  43. }
  44. public AttachUCViewModel(SerialPort serialPort)
  45. {
  46. ReadOddRegisterCmm = new DelegateCommand(ReadOddRegister);
  47. _serialPort = serialPort;
  48. }
  49. /// <summary>
  50. /// 读1000个寄存器
  51. /// </summary>
  52. private void ReadOddRegister()
  53. {
  54. // 创建 Modbus RTU 主站
  55. IModbusSerialMaster master = ModbusSerialMaster.CreateRtu(_serialPort);
  56. byte slaveId = 1;
  57. ushort totalRegisters = 1000;
  58. ushort chunkSize = 100;
  59. int numChunks = (int)Math.Ceiling((double)totalRegisters / chunkSize);
  60. ushort[] allRegisters = new ushort[totalRegisters];
  61. Task[] tasks = new Task[numChunks];
  62. DateTime startTime = DateTime.Now;
  63. for (int i = 0; i < numChunks; i++)
  64. {
  65. ushort startAddress = (ushort)(10300 + i * chunkSize);
  66. ushort currentChunkSize = 100;
  67. int chunkIndex = i;
  68. tasks[i] = Task.Run(() =>
  69. {
  70. try
  71. {
  72. ushort[] registers = master.ReadHoldingRegisters(slaveId, startAddress, currentChunkSize);
  73. Array.Copy(registers, 0, allRegisters, chunkIndex * chunkSize, currentChunkSize);
  74. }
  75. catch (Exception ex)
  76. {
  77. MessageBox.Show($"线程 {chunkIndex} 读取寄存器时出错: {ex.Message}");
  78. }
  79. });
  80. }
  81. // 等待所有任务完成
  82. Task.WaitAll(tasks);
  83. Time = (int)(DateTime.Now - startTime).TotalMilliseconds;
  84. StringBuilder result = new StringBuilder();
  85. int count = 0;
  86. for (int i = 1; i < totalRegisters; i += 2)
  87. {
  88. result.Append(allRegisters[i].ToString()+" ");
  89. count++;
  90. if (count % 50 == 0)
  91. {
  92. result.AppendLine();
  93. }
  94. }
  95. ReadResult = result.ToString();
  96. }
  97. private void ReadOddRegister2()
  98. {
  99. byte slaveId = 1;
  100. ushort totalRegisters = 1000;
  101. ushort chunkSize = 100;
  102. int numChunks = (int)Math.Ceiling((double)totalRegisters / chunkSize);
  103. ushort[] allRegisters = new ushort[totalRegisters];
  104. Task[] tasks = new Task[numChunks];
  105. DateTime startTime = DateTime.Now;
  106. for (int i = 0; i < numChunks; i++)
  107. {
  108. ushort startAddress = (ushort)(10300 + i * chunkSize);
  109. ushort currentChunkSize = 100;
  110. int chunkIndex = i;
  111. tasks[i] = Task.Run(() =>
  112. {
  113. ushort[] registers = ReadRegisters(slaveId, startAddress, currentChunkSize);
  114. Array.Copy(registers, 0, allRegisters, chunkIndex * chunkSize, currentChunkSize);
  115. });
  116. }
  117. // 等待所有任务完成
  118. Task.WaitAll(tasks);
  119. Time = (int)(DateTime.Now - startTime).TotalMilliseconds;
  120. StringBuilder result = new StringBuilder();
  121. int count = 0;
  122. for (int i = 1; i < totalRegisters; i += 2)
  123. {
  124. result.Append(allRegisters[i].ToString() + " ");
  125. count++;
  126. if (count % 50 == 0)
  127. {
  128. result.AppendLine();
  129. }
  130. }
  131. ReadResult = result.ToString();
  132. }
  133. public ushort[] ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
  134. {
  135. object _lock = new object();
  136. ushort[] resultValue = null;
  137. if (!_serialPort.IsOpen)
  138. {
  139. MessageBox.Show("串口没有链接,请先链接");
  140. return resultValue;
  141. }
  142. List<byte> sendByteList = new List<byte>();
  143. //设置从站地址
  144. sendByteList.Add(slaveAddress);
  145. //设置功能码
  146. sendByteList.Add(0x03);
  147. //设置起始地址的高位和低位
  148. sendByteList.Add(BitConverter.GetBytes(startAddress)[1]);
  149. sendByteList.Add(BitConverter.GetBytes(startAddress)[0]);
  150. //设置读取几个线圈的高位和低位
  151. sendByteList.Add(BitConverter.GetBytes(numberOfPoints)[1]);
  152. sendByteList.Add(BitConverter.GetBytes(numberOfPoints)[0]);
  153. //获取CRC校验码
  154. byte[] getCRC = sendByteList.ToArray();
  155. byte[] resultCRC = CRCUitl.CalculateCRC(getCRC, getCRC.Length);
  156. sendByteList.Add(resultCRC[0]);
  157. sendByteList.Add(resultCRC[1]);
  158. byte[] sendByte = sendByteList.ToArray();
  159. int maxRetries = 3; // 最大重试次数
  160. int attempt = 0;
  161. List<byte> responseData = new List<byte>();
  162. byte[] response = null;
  163. _serialPort.Write(sendByte, 0, sendByte.Length);
  164. while (attempt < maxRetries)
  165. {
  166. try
  167. {
  168. lock (_lock)
  169. {
  170. //使用时间去轮询查询数据
  171. DateTime startTime = DateTime.Now;
  172. while ((DateTime.Now - startTime).TotalMilliseconds < _serialPort.ReadTimeout)
  173. {
  174. int bytesToRead = _serialPort.BytesToRead;
  175. if (bytesToRead > 0)
  176. {
  177. byte[] buffer = new byte[bytesToRead];
  178. int bytesRead = _serialPort.Read(buffer, 0, bytesToRead);
  179. responseData.AddRange(buffer.Take(bytesRead));
  180. }
  181. //延迟20毫秒,节约cpu资源
  182. Task.Delay(20);
  183. }
  184. response = responseData.ToArray();
  185. if (response[0] == 0x00)
  186. {
  187. continue;
  188. }
  189. resultValue = ParseRegistersresponse(sendByte, response, numberOfPoints);
  190. return resultValue;
  191. }
  192. }
  193. catch (Exception)
  194. {
  195. attempt++;
  196. }
  197. }
  198. return resultValue;
  199. }
  200. public ushort[] ParseRegistersresponse(byte[] sendByte, byte[] response, ushort numberOfPoints)
  201. {
  202. //判断发送回来的数据是否正确
  203. if (CheckData.CheckResponse(response))
  204. {
  205. ushort[] registers = new ushort[numberOfPoints];
  206. for (int i = 0; i < numberOfPoints; i++)
  207. {
  208. int pos = 3 + i * 2;
  209. // 大端序转换 (高位在前)
  210. registers[i] = (ushort)((response[pos] << 8) | response[pos + 1]);
  211. }
  212. return registers;
  213. }
  214. else
  215. {
  216. return null;
  217. }
  218. }
  219. }
  220. }