12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058 |
- /**
- *┌──────────────────────────────────────────────────────────────┐
- *│ 描 述:ModbusClient的工具类
- *│ 作 者:执笔小白
- *│ 版 本:1.3
- *│ 创建时间:2023-11-24 12:40:56
- *└──────────────────────────────────────────────────────────────┘
- *┌──────────────────────────────────────────────────────────────┐
- *│ 命名空间: Util.NetworkProtocolHelpers
- *│ 类 名:ModbusClientHelper
- *└──────────────────────────────────────────────────────────────┘
- */
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO.Ports;
- using System.Linq;
- using System.Net;
- using System.Net.NetworkInformation;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Web.Services.Description;
- using System.Windows;
- using static EasyModbus.ModbusClient;
- using ModbusClient = EasyModbus.ModbusClient;
- namespace ModBusClientSimple.Util
- {
- /// <summary>
- /// ModbusTcpClient帮助类
- /// </summary>
- public class ModbusClientHelper
- {
- #region 变量
- /// <summary>
- /// ModbusClient对象
- /// </summary>
- private ModbusClient _modbusClient;
- /// <summary>
- /// 是否是TCP
- /// true为TCP;
- /// </summary>
- private ModbusClientConnType _modbusClientConnType = ModbusClientConnType.TCP;
- #endregion 变量
- /// <summary>
- /// 创建ModbusTCP Client
- /// </summary>
- /// <param name="ipStr">IP</param>
- /// <param name="portStr">端口</param>
- /// <param name="connected_Register">检测 是否连接成功 用的寄存器地址(value=1说明连接成功);默认为-1(不推荐),-1代表使用ping IP的形式</param>
- /// <param name="isConn">是否开始连接</param>
- public ModbusClientHelper(string ipAddress = "127.0.0.1", int port = 502, int connected_Register = -1, bool isConn = false)
- {
- _modbusClientConnType = ModbusClientConnType.TCP;
- _connected_Register = connected_Register;
- _modbusClient = new ModbusClient(ipAddress, port);
- if (isConn)
- {
- Connect();
- }
- }
- /// <summary>
- /// 创建ModbusRTU Client
- /// </summary>
- /// <param name="serialPort">COM串口(COM1~COM99)</param>
- /// <param name="unitIdentifier"> Slave ID(默认值0)</param>
- /// <param name="baudrate">波特率(默认值9600)</param>
- /// <param name="stopBits">停止位(可以为Parity.Even)</param>
- /// <param name="parity">校验位(可以为StopBits.OnePointFive)</param>
- public ModbusClientHelper(string serialPort, byte unitIdentifier, int baudrate, StopBits stopBits, Parity parity)
- {
- _modbusClientConnType = ModbusClientConnType.SerialPort;
- _modbusClient = new ModbusClient();
- _modbusClient.SerialPort = serialPort; // COM串口(COM1~COM99)
- _modbusClient.UnitIdentifier = unitIdentifier; // Slave ID(默认值0)
- _modbusClient.Baudrate = baudrate; // 波特率(默认值9600)
- _modbusClient.StopBits = stopBits; // 停止位(可以为Parity.Even)
- _modbusClient.Parity = parity; // 校验位(可以为StopBits.OnePointFive)
- }
- #region 连接与断开连接
- /// <summary>
- /// 连接-可持续断线重连机制
- /// </summary>
- /// <param name="isKeep">断线重连</param>
- /// <param name="reconnSpace">断线重连间隔 1000ms</param>
- //public void Connect(bool isKeep = false, int isKeep_reconnSpace = 1000)
- public void Connect()
- {
- //if (isKeep_reconnSpace != 0)
- // _reconnSpace = isKeep_reconnSpace;
- //if (isKeep)
- //{
- // 以下方案不可用
- //_modbusClient.ConnectedChanged += new EasyModbus.ModbusClient.ConnectedChangedHandler(UpdateConnectedChanged); // 重连机制
- //Task.Run(() =>
- //{
- // UpdateConnectedChanged();
- //});
- //}
- _modbusClient.Connect();
- }
- /// <summary>
- /// 断开连接
- /// </summary>
- public void Disconnect()
- {
- if (_modbusClient != null)
- _modbusClient.Disconnect();
- }
- /// <summary>
- /// 重连
- /// </summary>
- public void ReConnect()
- {
- try
- {
- if (_modbusClient != null)
- {
- switch (_modbusClientConnType)
- {
- case ModbusClientConnType.TCP:
- string ip = IPAddress;
- int port = Port;
- _modbusClient.Disconnect();
- _modbusClient = new ModbusClient(ip, port);
- _modbusClient.Connect();
- break;
- case ModbusClientConnType.SerialPort:
- string serialPort = _modbusClient.SerialPort;
- byte unitIdentifier = _modbusClient.UnitIdentifier;
- int baudrate = _modbusClient.Baudrate;
- StopBits stopBits = _modbusClient.StopBits;
- Parity parity = _modbusClient.Parity;
- _modbusClient.Disconnect();
- _modbusClient = new ModbusClient();
- _modbusClient.SerialPort = serialPort; // COM串口(COM1~COM99)
- _modbusClient.UnitIdentifier = unitIdentifier; // Slave ID(默认值0)
- _modbusClient.Baudrate = baudrate; // 波特率(默认值9600)
- _modbusClient.StopBits = stopBits; // 停止位(可以为Parity.Even)
- _modbusClient.Parity = parity; // 校验位(可以为StopBits.OnePointFive)
- _modbusClient.Connect();
- break;
- }
- }
- }
- catch (Exception ex)
- {
- Debug.Write(ex.Message.ToString());
- }
- }
- #region 重连机制
- /// <summary>
- /// 断线重连间隔,默认为1000ms
- /// </summary>
- private int _reconnSpace = 1000;
- /// <summary>
- /// 重连写法一_上次重连时间
- /// </summary>
- public DateTime lastReconnTime;
- /// <summary>
- /// 重连等待锁
- /// </summary>
- object threadlock = new object(); // 资源锁
- /// <summary>
- /// 重连机制
- /// </summary>
- /// <returns></returns>
- /// <param name = "reconnSpace" > 断线重连间隔 1000ms</param>
- //private void UpdateConnectedChanged(object sender)
- private void UpdateConnectedChanged()
- {
- #region 重连写法一
- //while (true)
- //{
- // if (!_modbusClient.Connected)
- // {
- // if (lastReconnTime < DateTime.Now.AddMilliseconds(-reconnSpace))
- // {
- // lastReconnTime= DateTime.Now;
- // // 保护机制
- // lock (threadlock)
- // {
- // Monitor.Wait(threadlock, _reconnSpace);
- // }
- // if (!_modbusClient.Connected)
- // {
- // _modbusClient.Disconnect();
- // _modbusClient.Connect();
- // }
- // }
- // else
- // {
- // lock (threadlock)
- // {
- // Monitor.Wait(threadlock, 1000); // 等待1s
- // }
- // }
- // }
- // else
- // {
- // break;
- // }
- //}
- #endregion 重连写法一
- #region 重连写法二
- //if (!_modbusClient.Connected)
- //{
- // lock (threadlock)
- // {
- // Monitor.Wait(threadlock, _reconnSpace);
- // }
- // //_modbusClient.Disconnect();
- // _modbusClient.Connect();
- //}
- #endregion 重连写法二
- #region 重连写法三
- while (true)
- {
- if (!IsConnected)
- {
- lock (threadlock)
- {
- Monitor.Wait(threadlock, _reconnSpace);
- }
- //_modbusClient.Disconnect();
- try
- {
- _modbusClient.Connect();
- }
- catch { }
- }
- }
- #endregion 重连写法三
- }
- #endregion 重连机制
- #endregion 连接与断开连接
- #region 常用属性
- /// <summary>
- /// 检查是否连接到Modbus TCP Server
- /// </summary>
- //public bool Connected => _modbusClient.Connected;// 经测试,_modbusClient.Connected无效
- /// <summary>
- /// 检测ModbusClient连接状态
- /// </summary>
- private int _connected_Register = -1;
- /// <summary>
- /// Modbus TCP Server状态
- /// </summary>
- private bool connected = false;
- /// <summary>
- /// 检查是否连接到Modbus TCP Server
- /// </summary>
- public bool IsConnected
- {
- get
- {
- if (_modbusClientConnType == ModbusClientConnType.SerialPort)
- {
- return _modbusClient.Connected;
- }
- else // TCP
- {
- if (_connected_Register == -1) // 默认为ping IP的形式;不推荐
- {
- try
- {
- Ping p = new Ping();
- PingReply r = p.Send(_modbusClient.IPAddress, 3000);
- connected = r.Status == IPStatus.Success ? true : false;
- }
- catch { connected = false; }
- }
- else
- {
- try
- {
- var values = _modbusClient.ReadHoldingRegisters(_connected_Register, 1).FirstOrDefault();
- connected = values == 1;
- }
- catch { connected = false; }
- }
- return connected;
- }
- }
- set
- {
- connected = value;
- }
- }
- /// <summary>
- /// 获取 Modbus-TCP Server的IP-Address
- /// </summary>
- public string IPAddress => _modbusClient.IPAddress;
- /// <summary>
- /// 获取 Modbus-TCP Server的Port (默认是 502).
- /// </summary>
- public int Port => _modbusClient.Port;
- #endregion 常用属性
- #region 常用方法
- #region 读写值的方法
- #region 1、线圈(Coils)
- /// <summary>
- /// 读线圈(Coils) (FC1)
- /// </summary>
- /// <param name="startingAddress">第一个要读取的 线圈的地址</param>
- /// <param name="quantity">要读取的 线圈数量</param>
- /// <returns>线圈值的布尔数组</returns>
- public bool[] ReadCoils(int startingAddress, int quantity) => _modbusClient.ReadCoils(startingAddress, quantity);
- /// <summary>
- /// 写线圈(Coils)_单个 (FC5)
- /// </summary>
- /// <param name="startingAddress">线圈的地址</param>
- /// <param name="value">线圈值</param>
- public void WriteSingleCoil(int startingAddress, bool value) => _modbusClient.WriteSingleCoil(startingAddress, value);
- /// <summary>
- /// 写线圈(Coils)_多个 (FC15)
- /// </summary>
- /// <param name="startingAddress">第一个要写的线圈的地址</param>
- /// <param name="values">线圈值的布尔数组</param>
- public void WriteMultipleCoils(int startingAddress, bool[] values) => _modbusClient.WriteMultipleCoils(startingAddress, values);
- #endregion 1、线圈(Coils)
- #region 2、离散输入(Discrete Inputs)
- /// <summary>
- /// 读 离散输入(Discrete Inputs)(FC2)
- /// </summary>
- /// <param name="startingAddress">要读取的第一个 离散输入的地址</param>
- /// <param name="quantity">要读取的 离散输入数量</param>
- /// <returns>离散输入的布尔数组</returns>
- public bool[] ReadDiscreteInputs(int startingAddress, int quantity) => _modbusClient.ReadDiscreteInputs(startingAddress, quantity);
- #endregion 2、离散输入(Discrete Inputs)
- // 3、浮点寄存器(Modbus协议可能不支持)
- #region 4、输入寄存器(Input Registers)-只读
- /// <summary>
- /// 读 输入寄存器(Input Registers) (FC4)
- /// </summary>
- /// <param name="startingAddress">第一个要读取的 输入寄存器 的地址</param>
- /// <param name="quantity">要读取的 输入寄存器 数量</param>
- /// <returns></returns>
- public int[] ReadInputRegisters(int startingAddress, int quantity) => _modbusClient.ReadInputRegisters(startingAddress, quantity);
- /// <summary>
- /// 读 整数类型的输入寄存器(Input Registers)_单个整数/小数(FC4)- 泛型
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="startingAddress">第一个要读取的 输入寄存器 的地址</param>
- /// <param name="quantity">要读取的 输入寄存器 数量</param>
- /// <param name="registerOrder">Registers数据的读取顺序(默认为LowHigh)</param>
- /// <returns>返回的值(数字型的值类型为0;其他:时间类型的值类型为default,引用类型默认为null)</returns>
- public T ReadInputRegisters<T>(int startingAddress, int quantity, RegisterOrder registerOrder = RegisterOrder.LowHigh) where T : struct
- {
- T result = default;
- int[] registers;
- // 解析数据流
- string type = typeof(T).ToString();
- switch (type)
- {
- case "System.Int32": // Int整数
- registers = _modbusClient.ReadInputRegisters(startingAddress, 2); // 读取数据流
- int int1 = ModbusClient.ConvertRegistersToInt(registers, registerOrder);
- result = (T)Convert.ChangeType(int1, typeof(T));
- break;
- case "System.Single": // Float单精度小数
- registers = _modbusClient.ReadInputRegisters(startingAddress, 2); // 读取数据流
- float float1 = ModbusClient.ConvertRegistersToFloat(registers, registerOrder);
- result = (T)Convert.ChangeType(float1, typeof(T));
- break;
- case "System.Int64": // Long长整数
- registers = _modbusClient.ReadInputRegisters(startingAddress, 4); // 读取数据流
- long long1 = ModbusClient.ConvertRegistersToLong(registers, registerOrder);
- result = (T)Convert.ChangeType(long1, typeof(T));
- break;
- case "System.Double": // Double双精度小数
- registers = _modbusClient.ReadInputRegisters(startingAddress, 4); // 读取数据流
- double double1 = ModbusClient.ConvertRegistersToDouble(registers, registerOrder);
- result = (T)Convert.ChangeType(double1, typeof(T));
- break;
- //case "System.String": // String字符串
- // ModbusClient.ConvertRegistersToString(registers, offset, stringLength);
- // break;
- default:
- break;
- }
- return result;
- }
- /// <summary>
- /// 读 字符串类型的输入寄存器(Input Registers)_单个字符串(FC4)
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="startingAddress">第一个要读取的 输入寄存器 的地址</param>
- /// <param name="quantity">要读取的 输入寄存器 数量</param>
- /// <param name="stringLength">字符串中的字符数(必须为偶数)</param>
- /// <param name="offset">偏移量(偏移几个Register;默认为0)</param>
- /// <returns>返回的值(引用类型默认为null;其他:数字型的值类型为0,时间类型的值类型为default)</returns>
- public string ReadInputRegisters(int startingAddress, int quantity, int stringLength, int offset)
- {
- // 读取数据流
- int[] registers = _modbusClient.ReadInputRegisters(startingAddress, quantity);
- // 解析数据流
- return ModbusClient.ConvertRegistersToString(registers, offset, stringLength);
- }
- #endregion 4、输入寄存器(Input Registers)-只读
- #region 5、保持寄存器(Holding Registers)-常用
- /// <summary>
- /// 读 保持寄存器(Holding Registers) (FC3)
- /// </summary>
- /// <param name="startingAddress">第一个要读取的 保持寄存器的地址</param>
- /// <param name="quantity">要读取的 保持寄存器 数量</param>
- /// <returns></returns>
- public int[] ReadHoldingRegisters(int startingAddress, int quantity) => _modbusClient.ReadHoldingRegisters(startingAddress, quantity);
- /// <summary>
- /// 读 整数类型的保持寄存器(Holding Registers)_单个整数/小数(FC3)- 泛型
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="startingAddress">第一个要读取的 保持寄存器 的地址</param>
- /// <param name="registerOrder">Registers数据的读取顺序(默认为LowHigh)</param>
- /// <returns>返回的值(数字型的值类型为0;其他:时间类型的值类型为default,引用类型默认为null)</returns>
- public T ReadHoldingRegisters<T>(int startingAddress, RegisterOrder registerOrder = RegisterOrder.LowHigh) where T : struct
- {
- T result = default;
- int[] registers;
- // 解析数据流
- string type = typeof(T).ToString();
- switch (type)
- {
- case "System.Int16": // Int整数
- registers = _modbusClient.ReadHoldingRegisters(startingAddress, 1); // 读取数据流
- int int16 = registers.FirstOrDefault();
- result = (T)Convert.ChangeType(int16, typeof(T));
- break;
- case "System.Int32": // Int整数
- registers = _modbusClient.ReadHoldingRegisters(startingAddress, 2); // 读取数据流
- int int32 = ModbusClient.ConvertRegistersToInt(registers, registerOrder);
- result = (T)Convert.ChangeType(int32, typeof(T));
- break;
- case "System.Single": // Float单精度小数
- registers = _modbusClient.ReadHoldingRegisters(startingAddress, 2); // 读取数据流
- float float1 = ModbusClient.ConvertRegistersToFloat(registers, registerOrder);
- result = (T)Convert.ChangeType(float1, typeof(T));
- break;
- case "System.Int64": // Long长整数
- registers = _modbusClient.ReadHoldingRegisters(startingAddress, 4); // 读取数据流
- long long1 = ModbusClient.ConvertRegistersToLong(registers, registerOrder);
- result = (T)Convert.ChangeType(long1, typeof(T));
- break;
- case "System.Double": // Double双精度小数
- registers = _modbusClient.ReadHoldingRegisters(startingAddress, 4); // 读取数据流
- double double1 = ModbusClient.ConvertRegistersToDouble(registers, registerOrder);
- result = (T)Convert.ChangeType(double1, typeof(T));
- break;
- //case "System.String": // String字符串
- // ModbusClient.ConvertRegistersToString(registers, offset, stringLength);
- // break;
- default:
- break;
- }
- return result;
- }
- /// <summary>
- /// 读 字符串类型的保持寄存器(Holding Registers)_单个字符串(FC3)
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="startingAddress">第一个要读取的 保持寄存器 的地址</param>
- /// <param name="quantity">要读取的 保持寄存器 数量</param>
- /// <param name="stringLength">字符串中的字符数(必须为偶数)</param>
- /// <param name="offset">偏移量(偏移几个Register;默认为0)</param>
- /// <returns>返回的值(引用类型默认为null;其他:数字型的值类型为0,时间类型的值类型为default)</returns>
- public string ReadHoldingRegisters(int startingAddress, int quantity, int stringLength, int offset = 0)
- {
- // 读取数据流
- int[] registers = _modbusClient.ReadHoldingRegisters(startingAddress, quantity);
- // 解析数据流
- return ModbusClient.ConvertRegistersToString(registers, offset, stringLength);
- }
- /// <summary>
- /// 写 保持寄存器(Holding Registers)_单个Register (FC6)
- /// </summary>
- /// <param name="startingAddress">要写入的 保持寄存器的地址</param>
- /// <param name="value">保持寄存器的值</param>
- public void WriteSingleRegister(int startingAddress, int value) => _modbusClient.WriteSingleRegister(startingAddress, value);
- /// <summary>
- /// 写 保持寄存器(Holding Registers)_多个 (FC16)
- /// </summary>
- /// <param name="startingAddress">要写入的第一个 保持寄存器的地址</param>
- /// <param name="values">保持寄存器的值的int数组</param>
- public void WriteMultipleRegisters(int startingAddress, int[] values) => _modbusClient.WriteMultipleRegisters(startingAddress, values);
- /// <summary>
- /// 写 保持寄存器(Holding Registers)_单个整数/小数/字符串 (FC16)
- /// </summary>
- /// <param name="startingAddress">要写入的第一个 保持寄存器的地址</param>
- /// <param name="values">写入的值</param>
- /// <param name="quantity">寄存器个数限制(字符串专用)</param>
- /// <param name="registerOrder">读写顺序(默认LowHigh)</param>
- public void WriteMultipleRegisters<T>(int startingAddress, object value, int quantity = 0, RegisterOrder registerOrder = RegisterOrder.LowHigh)
- {
- // 转化为数据流
- int[] datas; // 存储数据
- string type = typeof(T).ToString();
- switch (type)
- {
- case "System.Int16": // Int16整数
- datas = new int[] { Convert.ToInt16(value) };
- break;
- case "System.Int32": // Int32整数
- datas = ModbusClient.ConvertIntToRegisters(Convert.ToInt32(value), registerOrder);
- break;
- case "System.Single": // Float单精度小数
- datas = ModbusClient.ConvertFloatToRegisters(Convert.ToSingle(value), registerOrder);
- break;
- case "System.Int64": // Long长整数
- datas = ModbusClient.ConvertLongToRegisters(Convert.ToInt64(value), registerOrder);
- break;
- case "System.Double": // Double双精度小数
- datas = ModbusClient.ConvertDoubleToRegisters(Convert.ToDouble(value), registerOrder);
- break;
- case "System.String": // String字符串
- datas = ModbusClient.ConvertStringToRegisters(Convert.ToString(value));
- // 限制占用的寄存器个数
- if (quantity != 0 && datas.Count() > quantity)
- {
- Array.Resize(ref datas, quantity);
- }
- _modbusClient.WriteMultipleRegisters(startingAddress, new int[quantity]); // 先清除旧数据
- break;
- default:
- datas = new int[] { };
- break;
- }
- if (datas == null || datas.Length == 0) // 未转化成功的不进行写入
- {
- string returnStr = "ModbusTcp协议,地址:" + startingAddress + "值:" + value + "写入失败!类型转化失败...";
- Console.WriteLine(returnStr);
- throw new Exception(returnStr);
- }
- _modbusClient.WriteMultipleRegisters(startingAddress, datas);
- }
- /// <summary>
- /// 读取+写入保持寄存器(Holding Registers)_多个(FC23)
- /// </summary>
- /// <param name="startingAddressRead">第一个要读取的 保持寄存器的地址</param>
- /// <param name="quantityRead">要读取的 保持寄存器 数量</param>
- /// <param name="startingAddressWrite">要写入的第一个 保持寄存器的地址</param>
- /// <param name="values">保持寄存器的值的int数组</param>
- /// <returns></returns>
- public int[] ReadWriteMultipleRegisters(int startingAddressRead, int quantityRead, int startingAddressWrite, int[] values)
- => _modbusClient.ReadWriteMultipleRegisters(startingAddressRead, quantityRead, startingAddressWrite, values);
- #endregion 5、保持寄存器(Holding Registers)-常用
- // 6、ASCII字符(Modbus协议可能不支持)
- #endregion 读写值的方法
- #region 检查状态-略
- /// <summary>
- /// 检查是否连接到Modbus TCP Server
- /// </summary>
- public bool Connected() => IsConnected;
- // 1、ping IP地址
- // 2、在外面检查DB块状态
- #endregion 检查状态-略
- #endregion 常用方法
- }
- /// <summary>
- /// ModbusClient的通讯类型
- /// </summary>
- public enum ModbusClientConnType
- {
- TCP,
- SerialPort
- }
- #region 示例
- /// <summary>
- /// 使用示例
- /// </summary>
- public class UseClass
- {
- /// <summary>
- /// 定义一个字典,存plc对象(通讯)
- /// </summary>
- Dictionary<int, ModbusClientHelper> Funs = new Dictionary<int, ModbusClientHelper>();
- public void main1()
- {
- Funs.Add(1, new ModbusClientHelper("", 502, 499)); // 壳体上料
- var dd = new Task(() => { ReadStation_S2(1); });
- }
- /// <summary>
- /// 电性能测试
- /// </summary>
- /// <param name="no">PLC编号</param>
- private async void ReadStation_S2(int no)
- {
- // [S1]装胶圈
- // [S2]电性能测试
- // [S3]导通性测试
- // [S4]气密测试
- // [S5]激光标记
- // [S6]CCD检测
- string stationName = "[S2]电性能测试";
- ManualResetEvent MreReadPLC = new ManualResetEvent(false);
- while (!MreReadPLC.WaitOne(300)) // 运行间隔300ms
- {
- try
- {
- if (Funs[no].IsConnected) // 检查PLC是否已连接上
- {
- #region 电性能测试-加工数据
- try
- {
- int iPLC_Flag = Funs[no].ReadHoldingRegisters(908, 1).FirstOrDefault(); // PLC_Flag
- int iMES_Flag = Funs[no].ReadHoldingRegisters(909, 1).FirstOrDefault(); // MES_Flag
- bool pLC_Flag = iPLC_Flag == 1 ? true : false; // PLC_Flag
- bool mES_Flag = iMES_Flag == 1 ? true : false; // MES_Flag
- if (pLC_Flag && !mES_Flag) // 1 0
- {
- //AddMessage(LogType.Info, Head + stationName + Body);
- await Task.Run(() => { DoProcessData_电性能测试(no); });
- //AddMessage(LogType.Info, stationName + Body + Tail);
- }
- else if (!pLC_Flag && mES_Flag) // 0 1
- {
- // 清空写给PLC的数据
- // 清空MES_RESULT
- Funs[no].WriteMultipleRegisters<int>(910, 0); // MES_RESULT
- // MES_Flag重置为0
- Funs[no].WriteSingleRegister(909, 0); // MES_Flag
- }
- }
- catch (Exception ex)
- {
- Funs[no].WriteMultipleRegisters<int>(910, 2); // MES_RESULT 为2上位机报错
- Funs[no].WriteSingleRegister(909, 1); // MES_Flag
- //AddMessage(LogType.Error, $"PLC{no}_{stationName}上传加工运行出错!错误信息:" + ex.Message.ToString());
- }
- #endregion 电性能测试-加工数据
- #region 电性能测试-点检数据
- try
- {
- int iPLC_Flag = Funs[no].ReadHoldingRegisters(1100, 1).FirstOrDefault(); // PLC_Flag
- int iMES_Flag = Funs[no].ReadHoldingRegisters(1101, 1).FirstOrDefault(); // MES_Flag
- bool pLC_Flag = iPLC_Flag == 1 ? true : false; // PLC_Flag
- bool mES_Flag = iMES_Flag == 1 ? true : false; // MES_Flag
- if (pLC_Flag && !mES_Flag) // 1 0
- {
- //AddMessage(LogType.Info, Head + stationName + Body);
- await Task.Run(() => { DoOneCheckData_电性能测试(no); });
- //AddMessage(LogType.Info, stationName + Body + Tail);
- }
- else if (!pLC_Flag && mES_Flag) // 0 1
- {
- // 清空写给PLC的数据
- // 清空MES_RESULT
- Funs[no].WriteMultipleRegisters<int>(1102, 0); // MES_RESULT
- // MES_Flag重置为0
- Funs[no].WriteSingleRegister(1101, 0); // MES_Flag
- }
- }
- catch (Exception ex)
- {
- Funs[no].WriteMultipleRegisters<int>(1102, 2); // MES_RESULT 为2上位机报错
- Funs[no].WriteSingleRegister(1101, 1); // MES_Flag
- //AddMessage(LogType.Error, $"PLC{no}_{stationName}点检运行出错!错误信息:" + ex.Message.ToString());
- }
- #endregion 电性能测试-点检数据
- //UpdatePLCMonitor(no, 1); // 更新PLC状态的UI // 更新PLC状态的UI
- }
- else
- {
- //UpdatePLCMonitor(no, 0); // 更新PLC状态的UI
- //WritePLCLog(LogType.Info, "PLC" + no.ToString() + "_" + stationName + "连接失败!");
- Funs[no].Connect();
- }
- }
- catch (Exception ex)
- {
- //UpdatePLCMonitor(no, 0); // 更新PLC状态的UI
- //AddMessage(LogType.Error, $"PLC{no}_{stationName}运行出错!错误信息:" + ex.Message.ToString());
- }
- }
- }
- // 上传加工数据_电性能测试
- private void DoProcessData_电性能测试(int no)
- {
- string equipmentCode = "LineCode" + "-S2"; // 设备编号
- string processItem = "电性能测试"; // 测试项目
- try
- {
- string workorder_code = Funs[no].ReadHoldingRegisters(944, 32, 32); // 车间订单号
- workorder_code = string.IsNullOrEmpty(workorder_code) ? "" : workorder_code.Replace("\0", "").Trim();
- string batch_num = Funs[no].ReadHoldingRegisters(976, 32, 32); // 批次号
- batch_num = string.IsNullOrEmpty(batch_num) ? "" : batch_num.Replace("\0", "").Trim();
- string mtltmrk = Funs[no].ReadHoldingRegisters(912, 32, 32); // 产品型号
- mtltmrk = string.IsNullOrEmpty(mtltmrk) ? "" : mtltmrk.Replace("\0", "").Trim();
- string plcDate_Y = Funs[no].ReadHoldingRegisters(1040, 1).FirstOrDefault().ToString("0000"); // 产品序列号的 当前日期_年
- string plcDate_M = Funs[no].ReadHoldingRegisters(1041, 1).FirstOrDefault().ToString("00"); // 产品序列号的 当前日期_月
- string plcDate_D = Funs[no].ReadHoldingRegisters(1042, 1).FirstOrDefault().ToString("00"); // 产品序列号的 当前日期_日
- string plcDate_YMD = string.Concat(plcDate_Y, plcDate_M, plcDate_D); // 产品序列号的 当前日期
- string supplierCode = Funs[no].ReadHoldingRegisters(1008, 32, 32); // 供应商代码
- supplierCode = string.IsNullOrEmpty(supplierCode) ? "" : supplierCode.Replace("\0", "").Trim();
- int sn_Number = Funs[no].ReadHoldingRegisters<int>(1048); // 产品序列号的 数字序列部分
- string sn = mtltmrk + batch_num + plcDate_YMD + supplierCode; // 产品序列号
- //List<TestItem> items = new List<TestItem>()
- //{
- // new TestItem(){
- // Parameter_name = "结果判定",
- // Parameter_value = Funs[no].ReadHoldingRegisters(1050,1).FirstOrDefault()==1?"OK":"NG",
- // Parameter_unit = ""
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试压设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1051).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试时间设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<int>(1055).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻电阻设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1057).ToString(),
- // Parameter_unit = "Ω"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试压设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1061).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试时间设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<int>(1065).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "漏电流设定上限值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1067).ToString(),
- // Parameter_unit = "mA"
- // },
- // new TestItem(){
- // Parameter_name = "漏电流设定下限值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1071).ToString(),
- // Parameter_unit = "mA"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试压实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1075).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试时间实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<int>(1079).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻电阻实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1081).ToString(),
- // Parameter_unit = "Ω"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试压实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1085).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试时间实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1089).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "漏电流实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1091).ToString(),
- // Parameter_unit = "mA"
- // },
- // new TestItem(){
- // Parameter_name = "产品结果",
- // Parameter_value = Funs[no].ReadHoldingRegisters(1095, 1).FirstOrDefault()==1?"OK":"NG",
- // Parameter_unit = ""
- // }
- //};
- int result1 = 1; // 取最后一次的结果
- for (int i = 0; i < 4; i++)
- {
- string newsn = string.Concat(sn, (sn_Number + i).ToString());
- //result1 = SwitctProcessData(items, equipmentCode, processItem
- //, workorder_code, batch_num, mtltmrk, plcDate_YMD, supplierCode, newsn); // 上传数据
- }
- int result = result1 == 1 ? 1 : ("是否上传数据" == "" ? 4 : 1);
- Funs[no].WriteMultipleRegisters<int>(910, result); // MES_RESULT 为4MES报错
- Funs[no].WriteSingleRegister(909, 1); // MES_Flag
- //WritePLCLog(LogType.Debug, $"PLC{no}_[{equipmentCode}]{processItem}-Write" + (result == 1 ? "成功!" : "失败!"));
- }
- catch (Exception ex)
- {
- Funs[no].WriteMultipleRegisters<int>(910, 2); // MES_RESULT 为2上位机报错
- Funs[no].WriteSingleRegister(909, 1); // MES_Flag
- //AddMessage(LogType.Error, $"PLC{no}_[{equipmentCode}]{processItem}上传加工报错!错误信息:" + ex.Message.ToString());
- }
- }
- // 上传点检数据_电性能测试
- private void DoOneCheckData_电性能测试(int no)
- {
- string equipmentCode = "LineCode" + "-S2"; // 设备编号
- string processItem = "电性能测试"; // 测试项目
- try
- {
- string workorder_code = Funs[no].ReadHoldingRegisters(1104, 32, 32); // 车间订单号
- workorder_code = string.IsNullOrEmpty(workorder_code) ? "" : workorder_code.Replace("\0", "").Trim();
- //string accno = Funs[no].ReadHoldingRegisters(1136, 32, 32); // 工序编号
- //accno = string.IsNullOrEmpty(accno) ? "" : accno.Replace("\0", "").Trim();
- string accno = "2"; // 工序编号
- int dxncs = Funs[no].ReadHoldingRegisters<int>(1168); // 电性能测试OK点检
- int dxncsTD1 = Funs[no].ReadHoldingRegisters<int>(1170); // 电性能测试通道1NG点检
- int dxncsTD2 = Funs[no].ReadHoldingRegisters<int>(1172); // 电性能测试通道2NG点检
- int dxncsTD3 = Funs[no].ReadHoldingRegisters<int>(1174); // 电性能测试通道3NG点检
- int dxncsTD4 = Funs[no].ReadHoldingRegisters<int>(1176); // 电性能测试通道4NG点检
- // 测试参数
- //List<TestItem> items = new List<TestItem>()
- //{
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试压设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1051).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试时间设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<int>(1055).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻电阻设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1057).ToString(),
- // Parameter_unit = "Ω"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试压设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1061).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试时间设定值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<int>(1065).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "漏电流设定上限值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1067).ToString(),
- // Parameter_unit = "mA"
- // },
- // new TestItem(){
- // Parameter_name = "漏电流设定下限值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1071).ToString(),
- // Parameter_unit = "mA"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试压实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1075).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻测试时间实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<int>(1079).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "绝缘电阻电阻实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1081).ToString(),
- // Parameter_unit = "Ω"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试压实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1085).ToString(),
- // Parameter_unit = "V"
- // },
- // new TestItem(){
- // Parameter_name = "耐电压测试时间实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1089).ToString(),
- // Parameter_unit = "s"
- // },
- // new TestItem(){
- // Parameter_name = "漏电流实际值",
- // Parameter_value = Funs[no].ReadHoldingRegisters<float>(1091).ToString(),
- // Parameter_unit = "mA"
- // }
- //};
- string itemsStr = string.Empty;
- //itemsStr =JsonConvert.SerializeObject(items);
- #region 上传数据
- //List<OneCheckItem> cheItems = new List<OneCheckItem>();
- //// 每次只上传一项点检内容;8为不上传
- //if (dxncs != 8 && dxncsTD1 == 8 && dxncsTD2 == 8 && dxncsTD3 == 8 && dxncsTD4 == 8) // 电性能测试OK点检
- //{
- // cheItems.Add(new OneCheckItem()
- // {
- // Onecheck_name = "电性能测试OK点检",
- // Onecheck_content = "OK件点检结果为OK",
- // Onecheck_result = (OneCheckRD.OneCheckResultDetails.Keys.Contains(dxncs) ? OneCheckRD.OneCheckResultDetails[dxncs] : OneCheckRD.OneCheckResultDetails[9])
- // + ";" + itemsStr
- // });
- //}
- //else if (dxncs == 8 && dxncsTD1 != 8 && dxncsTD2 == 8 && dxncsTD3 == 8 && dxncsTD4 == 8) // 电性能测试通道1NG点检
- //{
- // cheItems.Add(new OneCheckItem()
- // {
- // Onecheck_name = "电性能测试通道1NG点检",
- // Onecheck_content = "NG样件点检结果为NG",
- // Onecheck_result = (OneCheckRD.OneCheckResultDetails.Keys.Contains(dxncsTD1) ? OneCheckRD.OneCheckResultDetails[dxncsTD1] : OneCheckRD.OneCheckResultDetails[9])
- // + ";" + itemsStr
- // });
- //}
- //else if (dxncs == 8 && dxncsTD1 == 8 && dxncsTD2 != 8 && dxncsTD3 == 8 && dxncsTD4 == 8) // 电性能测试通道2NG点检
- //{
- // cheItems.Add(new OneCheckItem()
- // {
- // Onecheck_name = "电性能测试通道2NG点检",
- // Onecheck_content = "NG样件点检结果为NG",
- // Onecheck_result = (OneCheckRD.OneCheckResultDetails.Keys.Contains(dxncsTD2) ? OneCheckRD.OneCheckResultDetails[dxncsTD2] : OneCheckRD.OneCheckResultDetails[9])
- // + ";" + itemsStr
- // });
- //}
- //else if (dxncs == 8 && dxncsTD1 == 8 && dxncsTD2 == 8 && dxncsTD3 != 8 && dxncsTD4 == 8) // 电性能测试通道3NG点检
- //{
- // cheItems.Add(new OneCheckItem()
- // {
- // Onecheck_name = "电性能测试通道3NG点检",
- // Onecheck_content = "NG样件点检结果为NG",
- // Onecheck_result = (OneCheckRD.OneCheckResultDetails.Keys.Contains(dxncsTD3) ? OneCheckRD.OneCheckResultDetails[dxncsTD3] : OneCheckRD.OneCheckResultDetails[9])
- // + ";" + itemsStr
- // });
- //}
- //else if (dxncs == 8 && dxncsTD1 == 8 && dxncsTD2 == 8 && dxncsTD3 == 8 && dxncsTD4 != 8) // 电性能测试通道4NG点检
- //{
- // cheItems.Add(new OneCheckItem()
- // {
- // Onecheck_name = "电性能测试通道4NG点检",
- // Onecheck_content = "NG样件点检结果为NG",
- // Onecheck_result = (OneCheckRD.OneCheckResultDetails.Keys.Contains(dxncsTD4) ? OneCheckRD.OneCheckResultDetails[dxncsTD4] : OneCheckRD.OneCheckResultDetails[9])
- // + ";" + itemsStr
- // });
- //}
- //else // 不上传
- //{
- // Funs[no].WriteMultipleRegisters<int>(1102, 6); // MES_RESULT 为“6未找到唯一点检项”
- // Funs[no].WriteSingleRegister(1101, 1); // MES_Flag
- // AddMessage(LogType.Error, $"PLC{no}_[{equipmentCode}]{processItem}点检报错!未找到唯一的点检项目");
- //}
- int result1 = 1;
- //OneCheckData oneCheckData = new OneCheckData()
- //{
- // Line_code = GlobalContext.LineCode,
- // Line_name = GlobalContext.LineName,
- // Equipment_code = equipmentCode,
- // Equipment_name = equipmentCode,
- // Workorder_code = workorder_code,
- // Procedure_code = accno,
- // Procedure_name = processItem,
- // Oneckeck_values = cheItems,
- // Onecheck_empcode = "",
- // Onecheck_empname = "",
- // Onecheck_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
- //};
- //result1 = SwitctOneCheckData(oneCheckData, equipmentCode, processItem);
- #endregion 上传数据
- int result = result1 == 1 ? 1 : ("上传点检数据" == "" ? 4 : 1);
- Funs[no].WriteMultipleRegisters<int>(1102, result); // MES_RESULT 为4MES报错
- Funs[no].WriteSingleRegister(1101, 1); // MES_Flag
- //WritePLCLog(LogType.Debug, $"PLC{no}_[{equipmentCode}]{processItem}-Write" + (result == 1 ? "成功!" : "失败!"));
- }
- catch (Exception ex)
- {
- Funs[no].WriteMultipleRegisters<int>(1102, 2); // MES_RESULT 为2上位机报错
- Funs[no].WriteSingleRegister(1101, 1); // MES_Flag
- //AddMessage(LogType.Error, $"PLC{no}_[{equipmentCode}]{processItem}点检报错!错误信息:" + ex.Message.ToString());
- }
- }
- }
- #endregion
- }
|