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 CarLocalMeter
  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 = AppConfigCache.rfidConnTime;
  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. master.Dispose();
  106. }
  107. catch { }
  108. }
  109. #region 数据采集
  110. private List<int> lWeight = new List<int>();
  111. /// <summary>
  112. /// 数据采集线程
  113. /// </summary>
  114. private void DataCollect()
  115. {
  116. if (!blThreadFlag) return;
  117. while (blThreadFlag)
  118. {
  119. try
  120. {
  121. //不停的给plc写值,我这写1234,他那会改为4321
  122. DataCollectWrite(0, 1234);
  123. //将重量信息写入到plc重量位置
  124. DataCollectWrite2(4, (ushort)CacleCls.weight);
  125. foreach (KeyValuePair<string, int> kvp in locationInfo)
  126. {
  127. startAddress = (ushort)kvp.Value;
  128. registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
  129. string db = "";
  130. for (int i = 0; i < registerBuffer.Length; i++)
  131. {
  132. db += registerBuffer[i];
  133. }
  134. switch (kvp.Key)
  135. {
  136. case "plcState":
  137. {
  138. if (db != "4321")
  139. CacleCls.plcState = 1;
  140. else
  141. CacleCls.plcState = 0;
  142. };
  143. break;
  144. case "leftGs": //左光栅
  145. CacleCls.leftGs = db;
  146. break;
  147. case "rightGs": //右光栅
  148. CacleCls.rightGs = db;
  149. break;
  150. case "topHw": //前红外
  151. CacleCls.topJg = db;
  152. break;
  153. case "bottomHw": //后红外
  154. CacleCls.bottomJg = db;
  155. break;
  156. case "rgLight": //红绿灯
  157. CacleCls.rgLight = db;
  158. break;
  159. }
  160. }
  161. Thread.Sleep(AppConfigCache.sleepTime);
  162. //读取到db之后,则需要将这个db值写入到缓存中
  163. }
  164. catch (Exception ex)
  165. {
  166. try { master.Dispose(); } catch { }
  167. CacleCls.plcState = 1;
  168. blThreadFlag = false;
  169. lg.WriteLog(LogType.PlcLog, $"获取PLC数据异常:{ex.Message}");
  170. ReConn();
  171. }
  172. }
  173. }
  174. #region 读取2个寄存器的情况,例如数据是int32
  175. public void getDb()
  176. {
  177. registerBuffer = master.ReadHoldingRegisters(slaveAddress, 4, 2);
  178. int[] i = new int[1];
  179. Buffer.BlockCopy(registerBuffer, 0, i, 0, 4);
  180. Console.WriteLine(i[0]);
  181. /*
  182. //将short转换为int,由于我们在插入到Modbus寄存器中一个int32会拆分为2个int16进行插入,
  183. //因此我们在获取寄存器数据类型为int32的数据时,返回的是2个short,此时需要转换为1个int
  184. //也就是用Buffer.BlockCopy即可。当然类似flat的搞法也是一样的,见下面的例子
  185. short[] s = { 1, 2 };
  186. int[] i = new int[1];
  187. float[] f = new float[1];
  188. Buffer.BlockCopy(s, 0, i, 0, 4);
  189. Buffer.BlockCopy(s, 0, f, 0, 4);
  190. Console.WriteLine("{0} {1}", i[0], f[0]);
  191. */
  192. }
  193. #endregion
  194. /// <summary>
  195. /// 传入需要写入的地址
  196. /// </summary>
  197. /// <param name="startAddr"></param>
  198. /// <param name="uValue"></param>
  199. public async void DataCollectWrite(ushort startAddr, ushort uValue)
  200. {
  201. try
  202. {
  203. await master.WriteSingleRegisterAsync(slaveAddress, startAddr, uValue);
  204. }
  205. catch(Exception ex)
  206. {
  207. //这里写个日志,记录下未成功
  208. lg.WriteLog(LogType.PlcLog, $"写入位置:[{startAddr}]的值:[{uValue}]异常。错误信息:{ex.Message}");
  209. }
  210. }
  211. /// <summary>
  212. /// 写入占位2个的情况,因为一个寄存器只能写入到int16,所以数据类型为int32需要写入2个寄存器
  213. /// </summary>
  214. /// <param name="startAddr"></param>
  215. /// <param name="uValue"></param>
  216. public async void DataCollectWrite2(ushort startAddr, uint uValue)
  217. {
  218. try
  219. {
  220. ushort[] uSValue = new ushort[2];
  221. uSValue[0] = BitConverter.ToUInt16(BitConverter.GetBytes(uValue), 0);
  222. uSValue[1] = BitConverter.ToUInt16(BitConverter.GetBytes(uValue), 2);
  223. await master.WriteMultipleRegistersAsync(slaveAddress, startAddr, uSValue);
  224. }
  225. catch (Exception ex)
  226. {
  227. //这里写个日志,记录下未成功
  228. lg.WriteLog(LogType.PlcLog, $"写入位置:[{startAddr}]的值:[{uValue}]异常。错误信息:{ex.Message}");
  229. }
  230. }
  231. #endregion
  232. }
  233. }