25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

269 satır
8.4 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(ReadOddRegister2);
  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. /// <summary>
  98. /// 自己的类
  99. /// </summary>
  100. private void ReadOddRegister2()
  101. {
  102. byte slaveId = 1;
  103. ushort totalRegisters = 1000;
  104. ushort chunkSize = 100;
  105. int numChunks = (int)Math.Ceiling((double)totalRegisters / chunkSize);
  106. ushort[] allRegisters = new ushort[totalRegisters];
  107. Task[] tasks = new Task[numChunks];
  108. DateTime startTime = DateTime.Now;
  109. for (int i = 0; i < numChunks; i++)
  110. {
  111. ushort startAddress = (ushort)(10300 + i * chunkSize);
  112. ushort currentChunkSize = 100;
  113. int chunkIndex = i;
  114. ushort[] registers = ReadRegisters(slaveId, startAddress, currentChunkSize);
  115. Array.Copy(registers, 0, allRegisters, chunkIndex * chunkSize, currentChunkSize);
  116. }
  117. // 等待所有任务完成
  118. Time = (int)(DateTime.Now - startTime).TotalMilliseconds;
  119. StringBuilder result = new StringBuilder();
  120. int count = 0;
  121. for (int i = 1; i < totalRegisters; i += 2)
  122. {
  123. result.Append(allRegisters[i].ToString() + " ");
  124. count++;
  125. if (count % 50 == 0)
  126. {
  127. result.AppendLine();
  128. }
  129. }
  130. ReadResult = result.ToString();
  131. }
  132. public ushort[] ReadRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints)
  133. {
  134. ushort[] resultValue = null;
  135. if (!_serialPort.IsOpen)
  136. {
  137. MessageBox.Show("串口没有链接,请先链接");
  138. return resultValue;
  139. }
  140. var sendByteList = new List<byte>(8)
  141. {
  142. slaveAddress, // 从站地址
  143. 0x03, // 功能码:读保持寄存器
  144. };
  145. // 添加起始地址(高字节在前)
  146. sendByteList.AddRange(BitConverter.GetBytes(startAddress).Reverse());
  147. // 添加读取点数(高字节在前)
  148. sendByteList.AddRange(BitConverter.GetBytes(numberOfPoints).Reverse());
  149. //获取CRC校验码
  150. byte[] getCRC = sendByteList.ToArray();
  151. byte[] resultCRC = CRCUitl.CalculateCRC(getCRC, getCRC.Length);
  152. sendByteList.Add(resultCRC[0]);
  153. sendByteList.Add(resultCRC[1]);
  154. byte[] sendByte = sendByteList.ToArray();
  155. int maxRetries = 3; // 最大重试次数
  156. int attempt = 0;
  157. List<byte> responseData = new List<byte>();
  158. byte[] response = null;
  159. while (attempt < maxRetries)
  160. {
  161. // 每次重试前清空缓冲区
  162. responseData.Clear();
  163. // 清除输入缓冲区残留数据
  164. _serialPort.DiscardInBuffer();
  165. try
  166. {
  167. _serialPort.Write(sendByte, 0, sendByte.Length);
  168. //使用时间去轮询查询数据
  169. DateTime startTime = DateTime.Now;
  170. while ((DateTime.Now - startTime).TotalMilliseconds < _serialPort.ReadTimeout)
  171. {
  172. int bytesToRead = _serialPort.BytesToRead;
  173. if (bytesToRead > 0)
  174. {
  175. byte[] buffer = new byte[bytesToRead];
  176. int bytesRead = _serialPort.Read(buffer, 0, bytesToRead);
  177. responseData.AddRange(buffer.Take(bytesRead));
  178. }
  179. //延迟20毫秒,节约cpu资源
  180. Thread.Sleep(20);
  181. }
  182. response = responseData.ToArray();
  183. if (response.Length == 0)
  184. {
  185. continue;
  186. }
  187. resultValue = ParseRegistersresponse(sendByte, response, numberOfPoints);
  188. return resultValue;
  189. }
  190. catch (Exception)
  191. {
  192. }
  193. finally
  194. {
  195. attempt++;
  196. }
  197. }
  198. return resultValue;
  199. }
  200. /// <summary>
  201. /// 解析读取到的操作
  202. /// </summary>
  203. /// <param name="sendByte"></param>
  204. /// <param name="response"></param>
  205. /// <param name="numberOfPoints"></param>
  206. /// <returns></returns>
  207. public ushort[] ParseRegistersresponse(byte[] sendByte, byte[] response, ushort numberOfPoints)
  208. {
  209. //判断发送回来的数据是否正确
  210. if (CheckData.CheckResponse(response))
  211. {
  212. ushort[] registers = new ushort[numberOfPoints];
  213. for (int i = 0; i < numberOfPoints; i++)
  214. {
  215. int pos = 3 + i * 2;
  216. // 大端序转换 (高位在前)
  217. registers[i] = (ushort)((response[pos] << 8) | response[pos + 1]);
  218. }
  219. return registers;
  220. }
  221. else
  222. {
  223. return null;
  224. }
  225. }
  226. }
  227. }