PlcCls.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using NModbus;
  7. using System.Net.Sockets;
  8. using System.Threading;
  9. using System.Configuration;
  10. using System.Net.NetworkInformation;
  11. namespace RailLocalMeter
  12. {
  13. public class PlcCls
  14. {
  15. private Log lg = Log.GetInstance(); //写日志
  16. Dictionary<string, int> locationInfo = new Dictionary<string, int>();
  17. private static ModbusFactory modbusFactory;
  18. private static IModbusMaster master;
  19. ushort[] registerBuffer;
  20. //参数(分别为站号,起始地址,长度)
  21. byte slaveAddress = 0;
  22. ushort startAddress;
  23. ushort numberOfPoints = 1;
  24. bool blThreadFlag;//数据采集线程开关
  25. Thread DataCollectThread = null;//采集进程
  26. #region 重连接
  27. int tryReconnNetTimeSpan = 1;
  28. private void ReConn()
  29. {
  30. bool isSuc = false;
  31. using (Ping ping = new Ping())
  32. {
  33. PingReply reply = null;
  34. for (int i = 0; i < tryReconnNetTimeSpan * 60; i++)
  35. {
  36. try
  37. {
  38. reply = ping.Send(AppConfigCache.plcIp, 1000);
  39. if (reply.Status == IPStatus.Success)
  40. {
  41. isSuc = true;
  42. break;
  43. }
  44. else
  45. {
  46. lg.WriteLog(LogType.RfidLoc, "Ping不通");
  47. continue;
  48. }
  49. }
  50. catch (Exception ex)
  51. {
  52. lg.WriteLog(LogType.RfidLoc, $"尝试自动恢复连接失败:{ex.Message}");
  53. return;
  54. }
  55. }
  56. }
  57. //建立连接
  58. if (isSuc)
  59. {
  60. Start();
  61. }
  62. }
  63. #endregion
  64. /// <summary>
  65. /// 这里需尝试不停的连接,若没有成功,则继续连,一直到成功或者连续几次不成功,给出提示
  66. /// </summary>
  67. private void ConnectionPlc()
  68. {
  69. //初始化modbusmaster
  70. modbusFactory = new ModbusFactory();
  71. //在本地测试 所以使用回环地址,modbus协议规定端口号 502
  72. master = modbusFactory.CreateMaster(new TcpClient(AppConfigCache.plcIp, AppConfigCache.plcPort));
  73. //设置读取超时时间
  74. master.Transport.ReadTimeout = 2000;
  75. master.Transport.Retries = 2000;
  76. blThreadFlag = true;
  77. DataCollectThread = new Thread(new ThreadStart(DataCollect));
  78. string[] strLocation = AppConfigCache.plcLocation.Split(',');
  79. string[] strLocationName = AppConfigCache.plcLocationName.Split(',');
  80. for (int i = 0; i < strLocation.Length; i++)
  81. {
  82. locationInfo.Add(strLocationName[i], Convert.ToInt32(strLocation[i]));
  83. }
  84. }
  85. public void Start()
  86. {
  87. try
  88. {
  89. blThreadFlag = true;
  90. ConnectionPlc();
  91. CacleCls.plcState = 0;
  92. DataCollectThread.Start();
  93. }
  94. catch
  95. {
  96. CacleCls.plcMsgInfo = "PLC连接失败,请检查配置信息及PLC网络";
  97. CacleCls.plcState = 1;
  98. }
  99. }
  100. public void Stop()
  101. {
  102. try
  103. {
  104. blThreadFlag = false;
  105. if (master != null)
  106. master.Dispose();
  107. }
  108. catch { }
  109. }
  110. bool bFlag = false;
  111. #region 数据采集
  112. private List<int> lWeight = new List<int>();
  113. /// <summary>
  114. /// 数据采集线程
  115. /// </summary>
  116. private void DataCollect()
  117. {
  118. if (!blThreadFlag) return;
  119. while (blThreadFlag)
  120. {
  121. try
  122. {
  123. /*
  124. //不停的给plc写值,我这写1234,他那会改为4321
  125. DataCollectWrite(0, 1234);
  126. //将重量信息写入到plc重量位置
  127. DataCollectWrite2(4, (ushort)CacleCls.weight);
  128. //*/
  129. foreach (KeyValuePair<string, int> kvp in locationInfo)
  130. {
  131. startAddress = (ushort)kvp.Value;
  132. registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
  133. string db = "";
  134. for (int i = 0; i < registerBuffer.Length; i++)
  135. {
  136. db += registerBuffer[i];
  137. }
  138. switch (kvp.Key)
  139. {
  140. case "plcState":
  141. {
  142. if (db != "4321")
  143. CacleCls.plcState = 1;
  144. else
  145. CacleCls.plcState = 0;
  146. };
  147. break;
  148. case "btnState": //左光栅
  149. CacleCls.btnState = db;
  150. break;
  151. case "topHw": //前红外
  152. CacleCls.topJg = db;
  153. break;
  154. case "bottomHw": //后红外
  155. CacleCls.bottomJg = db;
  156. break;
  157. }
  158. }
  159. if (CacleCls.btnState == "1")
  160. {
  161. lg.WriteLog(LogType.PlcLog, $"写入PLC的按钮值为1{DateTime.Now.ToString("yyyy-MM-dd HH24:mi:ss")}");
  162. }
  163. Thread.Sleep(AppConfigCache.sleepTime);
  164. //读取到db之后,则需要将这个db值写入到缓存中
  165. }
  166. catch (Exception ex)
  167. {
  168. try { master.Dispose(); } catch { }
  169. CacleCls.plcState = 1;
  170. blThreadFlag = false;
  171. lg.WriteLog(LogType.PlcLog, $"获取PLC数据异常:{ex.Message}");
  172. ReConn();
  173. }
  174. }
  175. }
  176. #region 读取2个寄存器的情况,例如数据是int32
  177. public void getDb()
  178. {
  179. registerBuffer = master.ReadHoldingRegisters(slaveAddress, 4, 2);
  180. int[] i = new int[1];
  181. Buffer.BlockCopy(registerBuffer, 0, i, 0, 4);
  182. Console.WriteLine(i[0]);
  183. /*
  184. //将short转换为int,由于我们在插入到Modbus寄存器中一个int32会拆分为2个int16进行插入,
  185. //因此我们在获取寄存器数据类型为int32的数据时,返回的是2个short,此时需要转换为1个int
  186. //也就是用Buffer.BlockCopy即可。当然类似flat的搞法也是一样的,见下面的例子
  187. short[] s = { 1, 2 };
  188. int[] i = new int[1];
  189. float[] f = new float[1];
  190. Buffer.BlockCopy(s, 0, i, 0, 4);
  191. Buffer.BlockCopy(s, 0, f, 0, 4);
  192. Console.WriteLine("{0} {1}", i[0], f[0]);
  193. */
  194. }
  195. #endregion
  196. /// <summary>
  197. /// 传入需要写入的地址
  198. /// </summary>
  199. /// <param name="startAddr"></param>
  200. /// <param name="uValue"></param>
  201. public async void DataCollectWrite(ushort startAddr, ushort uValue)
  202. {
  203. try
  204. {
  205. await master.WriteSingleRegisterAsync(slaveAddress, startAddr, uValue);
  206. }
  207. catch(Exception ex)
  208. {
  209. //这里写个日志,记录下未成功
  210. lg.WriteLog(LogType.PlcLog, $"写入位置:[{startAddr}]的值:[{uValue}]异常。错误信息:{ex.Message}");
  211. }
  212. }
  213. /// <summary>
  214. /// 写入占位2个的情况,因为一个寄存器只能写入到int16,所以数据类型为int32需要写入2个寄存器
  215. /// </summary>
  216. /// <param name="startAddr"></param>
  217. /// <param name="uValue"></param>
  218. public async void DataCollectWrite2(ushort startAddr, uint uValue)
  219. {
  220. try
  221. {
  222. ushort[] uSValue = new ushort[2];
  223. uSValue[0] = BitConverter.ToUInt16(BitConverter.GetBytes(uValue), 0);
  224. uSValue[1] = BitConverter.ToUInt16(BitConverter.GetBytes(uValue), 2);
  225. await master.WriteMultipleRegistersAsync(slaveAddress, startAddr, uSValue);
  226. }
  227. catch (Exception ex)
  228. {
  229. //这里写个日志,记录下未成功
  230. lg.WriteLog(LogType.PlcLog, $"写入位置:[{startAddr}]的值:[{uValue}]异常。错误信息:{ex.Message}");
  231. }
  232. }
  233. #endregion
  234. }
  235. }