| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using NModbus;
- using System.Net.Sockets;
- using System.Threading;
- using System.Configuration;
- using System.Net.NetworkInformation;
- namespace CarLocalMeter
- {
- public class PlcCls
- {
- private Log lg = Log.GetInstance(); //写日志
- Dictionary<string, int> locationInfo = new Dictionary<string, int>();
- private static ModbusFactory modbusFactory;
- private static IModbusMaster master;
- ushort[] registerBuffer;
- //参数(分别为站号,起始地址,长度)
- byte slaveAddress = 0;
- ushort startAddress;
- ushort numberOfPoints = 1;
- bool blThreadFlag;//数据采集线程开关
- Thread DataCollectThread = null;//采集进程
- #region 重连接
- int tryReconnNetTimeSpan = AppConfigCache.rfidConnTime;
- private void ReConn()
- {
- bool isSuc = false;
- using (Ping ping = new Ping())
- {
- PingReply reply = null;
- for (int i = 0; i < tryReconnNetTimeSpan * 60; i++)
- {
- try
- {
- reply = ping.Send(AppConfigCache.plcIp, 1000);
- if (reply.Status == IPStatus.Success)
- {
- isSuc = true;
- break;
- }
- else
- {
- lg.WriteLog(LogType.RfidLoc, "Ping不通");
- continue;
- }
- }
- catch (Exception ex)
- {
- lg.WriteLog(LogType.RfidLoc, $"尝试自动恢复连接失败:{ex.Message}");
- return;
- }
- }
- }
- //建立连接
- if (isSuc)
- {
- Start();
- }
- }
- #endregion
- /// <summary>
- /// 这里需尝试不停的连接,若没有成功,则继续连,一直到成功或者连续几次不成功,给出提示
- /// </summary>
- private void ConnectionPlc()
- {
- //初始化modbusmaster
- modbusFactory = new ModbusFactory();
- //在本地测试 所以使用回环地址,modbus协议规定端口号 502
- master = modbusFactory.CreateMaster(new TcpClient(AppConfigCache.plcIp, AppConfigCache.plcPort));
- //设置读取超时时间
- master.Transport.ReadTimeout = 2000;
- master.Transport.Retries = 2000;
- blThreadFlag = true;
- DataCollectThread = new Thread(new ThreadStart(DataCollect));
- string[] strLocation = AppConfigCache.plcLocation.Split(',');
- string[] strLocationName = AppConfigCache.plcLocationName.Split(',');
- for (int i = 0; i < strLocation.Length; i++)
- {
- locationInfo.Add(strLocationName[i], Convert.ToInt32(strLocation[i]));
- }
-
- }
- public void Start()
- {
- try
- {
- blThreadFlag = true;
- ConnectionPlc();
- CacleCls.plcState = 0;
- DataCollectThread.Start();
- }
- catch
- {
- CacleCls.plcMsgInfo = "PLC连接失败,请检查配置信息及PLC网络";
- CacleCls.plcState = 1;
- }
- }
- public void Stop()
- {
- try
- {
- blThreadFlag = false;
- if (master != null)
- master.Dispose();
- }
- catch { }
- }
- bool bFlag = false;
- #region 数据采集
- private List<int> lWeight = new List<int>();
- /// <summary>
- /// 数据采集线程
- /// </summary>
- private void DataCollect()
- {
- if (!blThreadFlag) return;
-
- while (blThreadFlag)
- {
- try
- {
- //不停的给plc写值,我这写1234,他那会改为4321
- DataCollectWrite(0, 1234);
- //将重量信息写入到plc重量位置
- DataCollectWrite2(4, (ushort)CacleCls.weight);
- foreach (KeyValuePair<string, int> kvp in locationInfo)
- {
- startAddress = (ushort)kvp.Value;
- registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
- string db = "";
- for (int i = 0; i < registerBuffer.Length; i++)
- {
- db += registerBuffer[i];
- }
- switch (kvp.Key)
- {
- case "plcState":
- {
- if (db != "4321")
- CacleCls.plcState = 1;
- else
- CacleCls.plcState = 0;
- };
- break;
- case "leftGs": //左光栅
- CacleCls.leftGs = db;
- break;
- case "rightGs": //右光栅
- CacleCls.rightGs = db;
- break;
- case "topHw": //前红外
- CacleCls.topJg = db;
- break;
- case "bottomHw": //后红外
- CacleCls.bottomJg = db;
- break;
- case "rgLight": //红绿灯
- CacleCls.rgLight = db;
- break;
- }
- }
- #region
- /*
- try
- {
- if (CacleCls.weight < 500)
- {
- if (!bFlag)
- {
- //实际上红绿灯是自动控制的,所以没影响
- //DataCollectWrite();
- }
- bFlag = true;
- }
- else
- {
- if (bFlag)
- {
-
- }
- bFlag = false;
- }
- } catch(Exception ex)
- {
-
- }
- //*/
- #endregion
- Thread.Sleep(AppConfigCache.sleepTime);
- //读取到db之后,则需要将这个db值写入到缓存中
- }
- catch (Exception ex)
- {
- try { master.Dispose(); } catch { }
- CacleCls.plcState = 1;
- blThreadFlag = false;
- lg.WriteLog(LogType.PlcLog, $"获取PLC数据异常:{ex.Message}");
- ReConn();
- }
- }
- }
- #region 读取2个寄存器的情况,例如数据是int32
- public void getDb()
- {
- registerBuffer = master.ReadHoldingRegisters(slaveAddress, 4, 2);
- int[] i = new int[1];
- Buffer.BlockCopy(registerBuffer, 0, i, 0, 4);
- Console.WriteLine(i[0]);
- /*
- //将short转换为int,由于我们在插入到Modbus寄存器中一个int32会拆分为2个int16进行插入,
- //因此我们在获取寄存器数据类型为int32的数据时,返回的是2个short,此时需要转换为1个int
- //也就是用Buffer.BlockCopy即可。当然类似flat的搞法也是一样的,见下面的例子
- short[] s = { 1, 2 };
- int[] i = new int[1];
- float[] f = new float[1];
- Buffer.BlockCopy(s, 0, i, 0, 4);
- Buffer.BlockCopy(s, 0, f, 0, 4);
- Console.WriteLine("{0} {1}", i[0], f[0]);
- */
- }
- #endregion
- /// <summary>
- /// 传入需要写入的地址
- /// </summary>
- /// <param name="startAddr"></param>
- /// <param name="uValue"></param>
- public async void DataCollectWrite(ushort startAddr, ushort uValue)
- {
- try
- {
- await master.WriteSingleRegisterAsync(slaveAddress, startAddr, uValue);
- }
- catch(Exception ex)
- {
- //这里写个日志,记录下未成功
- lg.WriteLog(LogType.PlcLog, $"写入位置:[{startAddr}]的值:[{uValue}]异常。错误信息:{ex.Message}");
- }
- }
- /// <summary>
- /// 写入占位2个的情况,因为一个寄存器只能写入到int16,所以数据类型为int32需要写入2个寄存器
- /// </summary>
- /// <param name="startAddr"></param>
- /// <param name="uValue"></param>
- public async void DataCollectWrite2(ushort startAddr, uint uValue)
- {
- try
- {
- ushort[] uSValue = new ushort[2];
- uSValue[0] = BitConverter.ToUInt16(BitConverter.GetBytes(uValue), 0);
- uSValue[1] = BitConverter.ToUInt16(BitConverter.GetBytes(uValue), 2);
- await master.WriteMultipleRegistersAsync(slaveAddress, startAddr, uSValue);
- }
- catch (Exception ex)
- {
- //这里写个日志,记录下未成功
- lg.WriteLog(LogType.PlcLog, $"写入位置:[{startAddr}]的值:[{uValue}]异常。错误信息:{ex.Message}");
- }
- }
- #endregion
- }
- }
|