RS485Client.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using Modbus.Device;
  2. using System.IO.Ports;
  3. ///**********************************************************
  4. ///System.Ports 可以使用
  5. ///RJCP.IO.Ports 可以使用
  6. ///**********************************************************
  7. namespace SHJX.Service.PortClient.OptionClient.RS485
  8. {
  9. public static class Rs485Client
  10. {
  11. private static readonly ILogger logger = LogFactory.BuildLogger(typeof(Rs485Client));
  12. /// <summary>
  13. /// RS485通信对象
  14. /// </summary>
  15. /// 选用RJCP.IO.Ports 而不是微软自带的,整体框架基于core,怕会出现跨平台的可能
  16. public static SerialPort Sport { get; set; }
  17. public static IModbusMaster Master { get; set; }
  18. /// <summary>
  19. /// 发送命令时锁定
  20. /// </summary>
  21. private static readonly object SnedLocker = new();
  22. /// <summary>
  23. /// 延时等待的单位间隔,默认20ms
  24. /// </summary>
  25. private static int DelayUnit { get; set; }
  26. /// <summary>
  27. /// 超时时长,默认1000ms
  28. /// </summary>
  29. private static int Timeout { get; set; }
  30. /// <summary>
  31. /// 端口状态:
  32. /// True=打开,False=关闭
  33. /// </summary>
  34. public static bool IsValid => Sport is not null && Sport.IsOpen;
  35. /// <summary>
  36. /// 初始化
  37. /// </summary>
  38. public static void InitPort()
  39. {
  40. // 创建COM通信对象
  41. Sport ??= new SerialPort
  42. {
  43. BaudRate = 9600,
  44. DataBits = 8,
  45. StopBits = StopBits.One,
  46. Parity = Parity.None
  47. };
  48. Master = ModbusSerialMaster.CreateRtu(Sport);
  49. DelayUnit = 10;
  50. Timeout = 1000;
  51. }
  52. /// <summary>
  53. /// 打开COM通信端口,使用指定参数
  54. /// </summary>
  55. /// <param name="portName">端口号</param>
  56. /// <returns>是否正常打开</returns>
  57. public static bool Open(string portName)
  58. {
  59. try
  60. {
  61. lock (SnedLocker)
  62. {
  63. if (Sport.IsOpen) Sport.Close();
  64. Sport.PortName = portName;
  65. try
  66. {
  67. Sport.Open();
  68. }
  69. catch (Exception ex)
  70. {
  71. logger.LogError(ex.Message);
  72. }
  73. }
  74. return Sport.IsOpen;
  75. }
  76. catch (UnauthorizedAccessException exIo)
  77. {
  78. logger.LogError(exIo.ToString());
  79. return false;
  80. }
  81. catch (Exception ex)
  82. {
  83. logger.LogError(ex.ToString());
  84. return false;
  85. }
  86. }
  87. /// <summary>
  88. /// 关闭COM通信端口
  89. /// </summary>
  90. /// <returns>true=已关闭,false=未关闭</returns>
  91. public static void Close()
  92. {
  93. if (!Sport.IsOpen)
  94. {
  95. return;
  96. }
  97. Sport.Close();
  98. Sport.Dispose();
  99. }
  100. #region
  101. /// <summary>
  102. /// 向端口发送指令,并等待回复。
  103. /// 以lastChar字符作为回复的结尾识别字符,收到该字符后返回。
  104. /// 失败时,返回string.Empty
  105. /// </summary>
  106. /// <param name="cmdStr">指令</param>
  107. /// <param name="lastChar">结尾识别字符</param>
  108. /// <returns>完整的应答数据,含结尾识别字符</returns>
  109. public static string SendData(string cmdStr, char lastChar)
  110. {
  111. if (Sport.IsOpen.Equals(false)) return string.Empty;
  112. lock (SnedLocker)
  113. {
  114. for (; ; )
  115. {
  116. try
  117. {
  118. var strRes = string.Empty;
  119. Sport.DiscardInBuffer();
  120. Sport.DiscardOutBuffer();
  121. Sport.Write(cmdStr);// 发送指令
  122. // 等待回复
  123. for (var i = 0; i < Timeout / DelayUnit; i++)
  124. {
  125. // 判断数据是否接收完整
  126. if (Sport.BytesToRead > 0)
  127. strRes += Sport.ReadExisting();
  128. if (strRes.IndexOf(lastChar) != -1)
  129. break;
  130. Thread.Sleep(DelayUnit);
  131. }
  132. if (strRes.Length.Equals(0))
  133. {
  134. strRes = string.Empty;
  135. }
  136. return strRes;
  137. }
  138. catch (UnauthorizedAccessException exIo)
  139. {
  140. logger.LogError(exIo.ToString());
  141. }
  142. catch (Exception ex)
  143. {
  144. logger.LogError(ex.ToString());
  145. }
  146. }
  147. }
  148. }
  149. #endregion
  150. /// <summary>
  151. /// 向端口发送指令,并等待回复。
  152. /// 以lastStr字符串作为回复的结尾识别字符,收到该字符串后返回。
  153. /// 失败时,返回string.Empty
  154. /// </summary>
  155. /// <param name="cmdStr">指令</param>
  156. /// <param name="lastStr"></param>
  157. /// <returns>收到的回复数据,含结尾识别字符串</returns>
  158. public static string SendData(string cmdStr, string lastStr)
  159. {
  160. using TaskMutexUtil mutex = new("comm"); //lock (SnedLocker)
  161. if (Sport.IsOpen == false)
  162. {
  163. return string.Empty;
  164. }
  165. for (; ; )
  166. {
  167. try
  168. {
  169. var strRes = string.Empty;
  170. Sport.DiscardInBuffer();
  171. Sport.DiscardOutBuffer();
  172. Sport.Write(cmdStr);// 发送指令
  173. // 等待回复
  174. for (var i = 0; i < Timeout / DelayUnit; i++)
  175. {
  176. // 判断数据是否接收完整
  177. if (Sport.BytesToRead > 0)
  178. {
  179. strRes += Sport.ReadExisting();
  180. }
  181. if (strRes.IndexOf(lastStr, StringComparison.Ordinal) > 0)
  182. {
  183. break;
  184. }
  185. Thread.Sleep(DelayUnit);
  186. }
  187. if (strRes.Length == 0)
  188. {
  189. strRes = string.Empty;
  190. }
  191. return strRes;
  192. }
  193. catch (UnauthorizedAccessException exIo)
  194. {
  195. logger.LogError(exIo.ToString());
  196. }
  197. catch (Exception ex)
  198. {
  199. logger.LogError(ex.ToString());
  200. }
  201. }
  202. }
  203. /// <summary>
  204. /// 向端口发送指令,并等待回复。
  205. /// 以lastStr字符串作为回复的结尾识别字符,收到该字符串后返回。
  206. /// 失败时,返回string.Empty
  207. /// </summary>
  208. /// <param name="cmdStr">指令</param>
  209. /// <param name="lastStr"></param>
  210. /// <returns>收到的回复数据,含结尾识别字符串</returns>
  211. //public static string SendDataByte(byte[] cmdStr)
  212. //{
  213. // using TaskMutexUtil mutex = new("comm"); //lock (SnedLocker)
  214. // if (Sport.IsOpen == false)
  215. // {
  216. // return string.Empty;
  217. // }
  218. // for (; ; )
  219. // {
  220. // try
  221. // {
  222. // var strRes = string.Empty;
  223. // Sport.DiscardInBuffer();
  224. // Sport.DiscardOutBuffer();
  225. // Sport.Write(cmdStr,0,8);// 发送指令
  226. // // 等待回复
  227. // for (var i = 0; i < Timeout / DelayUnit; i++)
  228. // {
  229. // // 判断数据是否接收完整
  230. // if (Sport.BytesToRead > 0)
  231. // {
  232. // strRes += Sport.ReadExisting();
  233. // }
  234. // if (strRes.IndexOf(lastStr, StringComparison.Ordinal) > 0)
  235. // {
  236. // break;
  237. // }
  238. // Thread.Sleep(DelayUnit);
  239. // }
  240. // if (strRes.Length == 0)
  241. // {
  242. // strRes = string.Empty;
  243. // }
  244. // return strRes;
  245. // }
  246. // catch (UnauthorizedAccessException exIo)
  247. // {
  248. // logger.LogError(exIo.ToString());
  249. // }
  250. // catch (Exception ex)
  251. // {
  252. // logger.LogError(ex.ToString());
  253. // }
  254. // }
  255. //}
  256. private static ushort temp = 100;
  257. private static ushort hli = 200;
  258. public static object HumitureRead()
  259. {
  260. using TaskMutexUtil mutex = new("comm"); //lock (SnedLocker)
  261. if (!Sport.IsOpen)
  262. {
  263. return null;
  264. }
  265. try
  266. {
  267. byte slaveAddress = byte.Parse("8");//站号
  268. ushort temperatureStartAddress = ushort.Parse("1");
  269. ushort numberOfPoints = ushort.Parse("2");
  270. ushort[] registerBuffer = Master.ReadInputRegisters(slaveAddress, temperatureStartAddress, numberOfPoints);
  271. return registerBuffer;
  272. }
  273. catch
  274. {
  275. return new ushort[] { temp++, hli++ };
  276. }
  277. }
  278. }
  279. }