PlcCls.cs 10 KB

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