PLC通讯实现

您所在的位置:网站首页 欧姆龙cp2e与电脑通讯 PLC通讯实现

PLC通讯实现

2024-05-27 00:38| 来源: 网络整理| 查看: 265

PLC通讯实现-C#实现欧姆龙以太网通讯FINS UDP(三) 背景抽象设计欧姆龙以太网通讯实现FINS UDP测试效果相关链接

背景

本人近十年的工作都与工业软件相关、其中工控系统开发过程中有一个必要环节就是跟各大厂商的PLC进行通讯,而对于从互联网行业跨入工业互联网行业的从业人员来说要实现各型号PLC通讯还是需要一个过程的,本人在此对主流型号PLC通讯实现进行总结以便大家参考。

抽象设计

首先我们要进行一下抽象设计,先设计一个抽象类(接口也可以,此处因为还有其他业务使用了抽象类)BaseEquip,对PLC的常规操作进行定义,即Open、Read、Write、Close,业务代码调用BaseEquip进行PLC的读写,然后在实现各型号的Equip类,对Open、Read、Write、Close进行实现,根据配置在业务代码中对BaseEquip进行实例化,这样后期更改PLC型号后,只需修改配置即可,不用修改业务代码。

欧姆龙以太网通讯实现FINS UDP

实现语言C#

抽象基类BaseEquip

public class BaseEquip { /// /// 打开设备 /// /// 成功返回true,失败返回false public abstract bool Open(); /// /// 读取信息 /// /// 数据块 /// 起始地址 /// 长度 /// 读取返回信息 /// 成功返回true,失败返回false public abstract bool Read(string block, int start, int len, out object[] buff); /// /// 写入信息 /// /// 数据块 /// 起始地址 /// 要写入的数据 /// 成功返回true,失败返回false public abstract bool Write(int block, int start, object[] buff); /// /// 关闭设备 /// public abstract void Close(); }

设备实现类Equip实现

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using Mesnac.Equips; namespace Mesnac.Equip.OMRON.FINS.UDP { public class Equip : BaseEquip { #region 字段定义 private string _plcIp = "192.168.1.50"; private int _plcPort = 9600; private string _pcIp = "192.168.1.131"; private Socket server = null; //Socket Server IPEndPoint plcIpEndPoint = null; IPEndPoint receiveEndPoint = null; EndPoint remote = null; private bool _isOpen = false; //是否打开连接 #endregion #region 属性定义 /// /// PLC的IP地址 /// public string PlcIp { get { return _plcIp; } } /// /// PLC的端口号 /// public int PlcPort { get { return _plcPort; } } public string PcIp { get { return _pcIp; } } #endregion #region 实现BaseEquip成员 public override bool Open() { try { if (this._isOpen == true && (server != null)) { return true; } this.State = false; this.server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); this.plcIpEndPoint = new IPEndPoint(IPAddress.Parse(this.PlcIp), 9600); this.receiveEndPoint = new IPEndPoint(IPAddress.Any, 0); this.remote = (EndPoint)this.receiveEndPoint; this.State = this.Connection(); if (!this.State) { return this.State; } else { this.State = true; this._isOpen = true; Console.WriteLine("连接成功!"); return this.State; } } catch (Exception ex) { this.State = false; this._isOpen = false; Console.WriteLine(ex.Message); return this.State; } } public override bool Read(string block, int start, int len, out object[] buff) { buff = new object[len]; try { if (len > 256) { for (int i = 0; i object[] _buff = new object[maxOneLen]; flag = this.ReadByLen(block, start + i * maxOneLen, maxOneLen, out _buff); if (flag == false) { base.State = flag; return false; } for (int k = i * maxOneLen; k object[] _buff = new object[mod]; flag = this.ReadByLen(block, start + count * maxOneLen, mod, out _buff); if (flag == false) { base.State = flag; return false; } for (int k = count * maxOneLen; k ICSharpCode.Core.LoggingService.Error(String.Format("读取PLC(OMRON)设备失败-({0})!", ex.Message)); base.State = false; return false; } } /// /// 单次读取最长100个字的方法 /// /// 块号 /// 起始字 /// 长度,最长不超过100 /// 数据缓冲区,存放读取的数据 /// 读取成功返回true,读取失败返回false private bool ReadByLen(string block, int start, int len, out object[] buff) { lock (this) { buff = new object[len]; if (!this.Open()) { return false; } int state = len; object[] _buff = new object[len]; int iblock = Convert.ToInt32(block); //iblock = iblock + start; byte[] readCmd = this.GetReadCmd(iblock + start, len); int size = this.server.SendTo(readCmd, readCmd.Length, SocketFlags.None, this.plcIpEndPoint); byte[] buffer = new byte[len * 2 + 14]; if (size int recv = server.ReceiveFrom(buffer, ref this.remote);//返回收到的字节数 if (recv != 0) { for(int i = 0; i iReadLen = state; } for (int i = 0; i value = ushort.MaxValue - value; } buff[i] = value; } return true; } } public override bool Write(int block, int start, object[] buff) { lock(this) { byte[] writeCmd = this.GetWriteCmd(block + start, buff); try { int size = this.server.SendTo(writeCmd, writeCmd.Length, SocketFlags.None, this.plcIpEndPoint); if (size return true; } else { return false; } } catch(Exception ex) { ICSharpCode.Core.LoggingService.Error(String.Format("block={0}, start={1}, len={2} 写入PLC失败,{3}", block, start, buff.Length, ex.Message), ex); return false; } } } public override void Close() { try { if (this.server != null) { this.server.Close(); this.server = null; } } catch(Exception ex) { ICSharpCode.Core.LoggingService.Error("断开PLC连接异常:" + ex.Message, ex); } } #endregion #region 辅助方法 /// /// 获取IP地址中最后一部分的值,比如:192.168.1.50,则返回50 /// /// ip地址 /// 返回IP地址中最后一部分的值 private byte GetLastIpScopeValue(string ip) { try { IPAddress ipAddress = IPAddress.Parse(ip); byte[] ipValues = ipAddress.GetAddressBytes(); return ipValues[ipValues.Length - 1]; } catch(Exception ex) { ICSharpCode.Core.LoggingService.Error(String.Format("IP地址格式不合法,IP = [{0}]", ip), ex); return 0; } } /// /// 获取读取数据的指令 /// /// 起始地址 /// 要读取的长度 /// 返回合法的读取指令 private byte[] GetReadCmd(int start, int len) { byte[] starts = BitConverter.GetBytes((short)start); byte[] lens = BitConverter.GetBytes((short)len); byte[] readCmd = new byte[18]; readCmd[0] = 0X80; readCmd[1] = 0X00; readCmd[2] = 0X02; readCmd[3] = 0X00; //下标从0开始,第4个字节表示PLC的IP地址(IP地址4部分的最后一部分的值) readCmd[4] = this.GetLastIpScopeValue(this.PlcIp); //对方IP地址,即PLC readCmd[5] = 0X00; readCmd[6] = 0X00; //下标从0开始,第7个字节表示PC的IP地址(IP地址4部分的最后一部分的值) readCmd[7] = 0X01; // this.GetLastIpScopeValue(this.PcIp); //本机IP地址,即上位机电脑,只要是大于0的值就行 readCmd[8] = 0X00; readCmd[9] = 0X00; readCmd[10] = 0X01; readCmd[11] = 0X01; //0101 读取数据 readCmd[12] = 0X82; //82 地址区域DM区 //下标从0开始,第13和14这2个字节表示起始地址 readCmd[13] = starts[1]; //读/写数据区的起始地址 readCmd[14] = starts[0]; //读/写数据区的起始地址 readCmd[15] = 0X00; //下标从0开始,第16和17这2个字节表示读取数据的长度 readCmd[16] = lens[1]; //读/写数据个数 readCmd[17] = lens[0]; //读/写数据个数 Console.WriteLine(BitConverter.ToString(readCmd).Replace("-", String.Empty)); return readCmd; } /// /// 获取写入PLC的指令 /// /// /// /// private byte[] GetWriteCmd(int start, object[] buff) { Random ra = new Random(unchecked((int)DateTime.Now.Ticks)); int SID = ra.Next(1, 100); int num = buff.Length; int amount = 18 + num * 2; byte[] writeCmd = new byte[amount]; byte[] startBytes = new byte[2]; startBytes = BitConverter.GetBytes((short)start); byte[] lenBytes = new byte[2]; lenBytes = BitConverter.GetBytes((short)num); writeCmd[0] = 0X80; //ICF writeCmd[1] = 0X00; //RSV writeCmd[2] = 0X02; //GCT writeCmd[3] = 0X00; //DNA //下标从0开始,第4个字节表示PLC的IP地址(IP地址4部分的最后一部分的值) writeCmd[4] = this.GetLastIpScopeValue(this.PlcIp); //DA1,对方IP地址,即PLC writeCmd[5] = 0X00; //DA2 writeCmd[6] = 0X00; //SNA //下标从0开始,第7个字节表示PC的IP地址(IP地址4部分的最后一部分的值) writeCmd[7] = 0X01; // this.GetLastIpScopeValue(this.PcIp); //SA1,本机IP地址,即上位机电脑,只要是大于0的值就行 writeCmd[8] = 0X00; //SA2 writeCmd[9] = Convert.ToByte(SID.ToString(), 16);//SID //0x00; writeCmd[10] = 0X01; //Command code writeCmd[11] = 0X02; //Command code,0101表示读取,0102 写入数据 writeCmd[12] = 0X82; //82 地址区域DM区 //下标从0开始,第13和14这2个字节表示起始地址 writeCmd[13] = startBytes[1]; writeCmd[14] = startBytes[0]; writeCmd[15] = 0x00; writeCmd[16] = lenBytes[1]; writeCmd[17] = lenBytes[0]; for (int i = 0; i int.TryParse(buff[i].ToString(), out value); } byte[] byteValues = BitConverter.GetBytes((short)value); writeCmd[18 + i * 2] = byteValues[1]; writeCmd[18 + i * 2 + 1] = byteValues[0]; } Console.WriteLine(BitConverter.ToString(writeCmd).Replace("-", String.Empty)); return writeCmd; } /// /// 连接测试 /// /// private bool Connection() { byte[] readCmd = this.GetReadCmd(0, 1); int size = this.server.SendTo(readCmd, readCmd.Length, SocketFlags.None, this.plcIpEndPoint); if (size return true; } return false; } #endregion } } 测试效果

在这里插入图片描述

相关链接

欧姆龙PLC之Fins UDP与Fins TCP协议解析与通讯测试.pptx 完整源代码下载



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3