C实现Omron欧姆龙PLC的Fins Tcp协议

C实现Omron欧姆龙PLC的Fins Tcp协议nbsp nbsp 最近项目需要用上位机通讯 OmronPLC 使用无线网络的 Fins 协议 经测试通过后代码如下 使用方法 1 引用此命名空间 2 实例化类 FinsTcp 3 调用连接函数 conn 4 读取写入操作 读位数据 写位数据 读字数据 写字数据 nbsp 四个函数都有说明 注意 读字数据和写字数据时 一个字 两个字节 注意字节数组长度应该是字的两倍 还有高低位变化 usingSystem

    最近项目需要用上位机通讯Omron PLC,使用无线网络的Fins协议,经测试通过后代码如下:

使用方法:

1、引用此命名空间;

2、实例化类FinsTcp;

3、调用连接函数conn();

4、读取写入操作(读位数据,写位数据,读字数据,写字数据  四个函数都有说明);

注意:读字数据 和 写字数据时,一个字 = 两个字节,注意字节数组长度应该是字的两倍,还有高低位变化。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; namespace Omron { class FinsTcp { public bool connected; string ip; int port; byte[] Client = new byte[4]; byte[] Server = new byte[4];//PLC和本机数据 byte[] dataLeng = { 0x00, 0x01 }; TcpClient msender; Socket msock; #region 构造函数 ///  /// Fins协议Tcp连接的构造函数(PLC的IP地址、PLC端口号、本机节点) ///  /// IP地址 /// 端口号,默认9600 /// 本机节点 /// 
     
       实例化一个Fins协议Tcp连接 
      public FinsTcp(string ip, int port, byte fra) { //frame = Convert.ToByte(ip.Substring(ip.LastIndexOf('.'))); this.ip = ip; this.port = port; Client[3] = fra; connected = false; } #endregion #region 断开连接 ///  /// 断开连接 ///  public void disconn() { if (connected) { msender.Close(); connected = false; } } #endregion #region 连接PLC ///  /// 连接PLC ///  public void conn() { if (!connected) { msender = new TcpClient(ip, port); msock = msender.Client; byte[] Handshake = new byte[20]; Handshake[0] = 0x46;//F Handshake[1] = 0x49;//I Handshake[2] = 0x4e;//N Handshake[3] = 0x53;//S Handshake[4] = 0; Handshake[5] = 0; Handshake[6] = 0; Handshake[7] = 0x0c;//Length长度 Handshake[8] = 0; Handshake[9] = 0; Handshake[10] = 0; Handshake[11] = 0;//Command Handshake[12] = 0; Handshake[13] = 0; Handshake[14] = 0; Handshake[15] = 0;//Error Code Handshake[16] = 0; Handshake[17] = 0; Handshake[18] = 0; Handshake[19] = Client[3];//FINS Frame (本机节点) msock.Send(Handshake); byte[] buffer = new byte[24]; msock.Receive(buffer, SocketFlags.None); byte[] buf = buffer; buf[0] = 0x46;//F buf[1] = 0x49;//I buf[2] = 0x4e;//N buf[3] = 0x53;//S buf[4] = 0; buf[5] = 0; buf[6] = 0; buf[7] = 20; buf[8] = 0; buf[9] = 0; buf[10] = 0; buf[11] = 1; buf[12] = 0; buf[13] = 0; buf[14] = 0; buf[15] = 0; if (buf == buffer) { Client[0] = buffer[16]; Client[1] = buffer[17]; Client[2] = buffer[18]; Client[3] = buffer[19]; Server[0] = buffer[20]; Server[1] = buffer[21]; Server[2] = buffer[22]; Server[3] = buffer[23]; connected = true; } } } #endregion #region 读位数据 ///  /// 读取PLC上的位数据(内存地址、读取结果) ///  /// PLC的内存地址(区域.地址.位 如:CIO.1.2) /// 读取结果 public int readBit(string memory, ref bool result) { byte[] re = new byte[1] { 0x00 }; int rev = SendByte(memory, true, true, ref re); if (rev == 0) result = Convert.ToBoolean(re[0]); return rev; } #endregion #region 写位数据 ///  /// 写入PLC上的位数据(内存地址、写入数据) ///  /// PLC的内存地址(区域.地址.位 如:WR.3.0) /// 写入数据 public int writeBit(string memory, bool sendBit) { Byte[] Se = new Byte[1]; Se[0] = Convert.ToByte(sendBit); return SendByte(memory, true, false, ref Se, Se); } #endregion #region 读字数据 ///  /// 读取PLC上的位数据(内存地址、读取结果) ///  /// PLC的内存地址(区域.地址.字长度 如:DR.1.2) /// 读取结果 public int readWord(string memory, ref byte[] result) { return SendByte(memory, false, true, ref result); } #endregion #region 写字数据 ///  /// 写入PLC上的位数据(内存地址、写入数据) ///  /// PLC的内存地址(区域.地址.字长度 如:WR.10.4) /// 写入数据 public int writeWord(string memory, byte[] sendWord) { return SendByte(memory, false, false, ref sendWord, sendWord); } #endregion #region PLC内存格式转换 ///  /// 地址格式转化 ///  private byte[] addsToByte(string memory, bool isBit) { string[] AddrParts = memory.Split('.'); byte[] CH = BitConverter.GetBytes(Convert.ToInt32(AddrParts[1])); byte[] Count = BitConverter.GetBytes(Convert.ToInt32(AddrParts[2])); byte[] Addrs = new byte[6]; Addrs[1] = CH[1]; Addrs[2] = CH[0]; if (!isBit) //字处理 { switch (AddrParts[0]) { case "CIO": Addrs[0] = 0xB0; break; case "WR": Addrs[0] = 0xB1; break; case "DM": Addrs[0] = 0x82; break; case "HR": Addrs[0] = 0xB2; break; case "TIM": Addrs[0] = 0x89; break; case "AR": Addrs[0] = 0xB3; break; case "CNT": Addrs[0] = 0x89; break; default: Addrs[0] = 0x00; break; } Addrs[3] = 0x00; Addrs[4] = Count[1]; Addrs[5] = Count[0];//读写字的长度 } else //位处理 { switch (AddrParts[0]) { case "CIO": Addrs[0] = 0x30; break; case "WR": Addrs[0] = 0x31; break; case "DM": Addrs[0] = 0x02; break; case "HR": Addrs[0] = 0x32; break; case "TIM": Addrs[0] = 0x09; break; case "AR": Addrs[0] = 0x33; break; case "CNT": Addrs[0] = 0x09; break; default: Addrs[0] = 0x00; break; } Addrs[3] = Count[0]; Addrs[4] = 0x00; Addrs[5] = 0x01;//每次读写一位 } return Addrs; } #endregion #region 报文处理 ///  /// 报文处理 ///  /// 要读写的内存地址 /// 位还是字 /// 读还是写 /// 返回的数据 /// 写入的数据 private int SendByte(string memory, bool isBit, bool isRead, ref byte[] rev, byte[] datas = null) { int dataLength; if (datas == null) dataLength = 26; else dataLength = datas.Length + 26; byte[] SendByte = new byte[dataLength + 8]; SendByte[0] = 0x46;//F SendByte[1] = 0x49;//I SendByte[2] = 0x4e;//N SendByte[3] = 0x53;//S SendByte[4] = 0;//cmd length SendByte[5] = 0; SendByte[6] = 0; SendByte[7] = Convert.ToByte(dataLength); SendByte[8] = 0;//frame command SendByte[9] = 0; SendByte[10] = 0; SendByte[11] = 0x02; SendByte[12] = 0;//err SendByte[13] = 0; SendByte[14] = 0; SendByte[15] = 0; //command frame header SendByte[16] = 0x80;//ICF SendByte[17] = 0x00;//RSV SendByte[18] = 0x02;//GCT, less than 8 network layers SendByte[19] = 0x00;//DNA, local network SendByte[20] = Server[3];//DA1 SendByte[21] = 0x00;//DA2, CPU unit SendByte[22] = 0x00;//SNA, local network SendByte[23] = Client[3];//SA1 SendByte[24] = 0x00;//SA2, CPU unit SendByte[25] = Convert.ToByte(21);//SID SendByte[26] = 0x01; if (isRead) SendByte[27] = 0x01; else SendByte[27] = 0x02; byte[] head = addsToByte(memory, isBit); SendByte[28] = head[0]; SendByte[29] = head[1]; SendByte[30] = head[2]; SendByte[31] = head[3]; SendByte[32] = head[4]; SendByte[33] = head[5]; if (datas != null) { Array.Copy(datas, 0, SendByte, 34, datas.Length); } msock.Send(SendByte, SocketFlags.None); byte[] buffer = new byte[256]; msock.Receive(buffer); int err = 0; if (buffer[0] != SendByte[0] || buffer[1] != SendByte[1] || buffer[2] != SendByte[2] || buffer[3] != SendByte[3]) { err = 1;//the head is err } if (err == 0 && buffer[11] == 3) { switch (buffer[15]) { case 0x01: err = 2; break;//the head is not 'FINS' case 0x02: err = 3; break;//the data length is too long case 0x03: err = 4; break;//the command is not supported } } if (err == 0 && buffer[28] != 0 && buffer[29] != 0) { err = 5; //end code err switch (buffer[28]) { case 0x00: if (buffer[29] == 0x01) err = 6;//service canceled break; case 0x01: switch (buffer[29]) { case 0x01: err = 7; break; //local node not in network case 0x02: err = 8; break; //token timeout case 0x03: err = 9; break; //retries failed case 0x04: err = 10; break; //too many send frames case 0x05: err = 11; break; //node address range error case 0x06: err = 12; break; //node address duplication } break; case 0x02: switch (buffer[29]) { case 0x01: err = 13; break; //destination node not in network case 0x02: err = 14; break; //unit missing case 0x03: err = 15; break; //third node missing case 0x04: err = 16; break; //destination node busy case 0x05: err = 17; break; //response timeout } break; case 0x03: switch (buffer[29]) { case 0x01: err = 18; break; //communications controller error case 0x02: err = 19; break; //CPU unit error case 0x03: err = 20; break; //controller error case 0x04: err = 21; break; //unit number error } break; case 0x04: switch (buffer[29]) { case 0x01: err = 22; break; //undefined command case 0x02: err = 23; break; //not supported by model/version } break; case 0x05: switch (buffer[29]) { case 0x01: err = 24; break; //destination address setting error case 0x02: err = 25; break; //no routing tables case 0x03: err = 26; break; //routing table error case 0x04: err = 27; break; //too many relays } break; case 0x10: switch (buffer[29]) { case 0x01: err = 28; break; //command too long case 0x02: err = 29; break; //command too short case 0x03: err = 30; break; //elements/data don't match case 0x04: err = 31; break; //command format error case 0x05: err = 32; break; //header error } break; case 0x11: switch (buffer[29]) { case 0x01: err = 33; break; //area classification missing case 0x02: err = 34; break; //access size error case 0x03: err = 35; break; //address range error case 0x04: err = 36; break; //address range exceeded case 0x06: err = 37; break; //program missing case 0x09: err = 38; break; //relational error case 0x0a: err = 39; break; //duplicate data access case 0x0b: err = 40; break; //response too long case 0x0c: err = 41; break; //parameter error } break; case 0x20: switch (buffer[29]) { case 0x02: err = 42; break; //protected case 0x03: err = 43; break; //table missing case 0x04: err = 44; break; //data missing case 0x05: err = 45; break; //program missing case 0x06: err = 46; break; //file missing case 0x07: err = 47; break; //data mismatch } break; case 0x21: switch (buffer[29]) { case 0x01: err = 48; break; //read-only case 0x02: err = 49; break; //protected , cannot write data link table case 0x03: err = 50; break; //cannot register case 0x05: err = 51; break; //program missing case 0x06: err = 52; break; //file missing case 0x07: err = 53; break; //file name already exists case 0x08: err = 54; break; //cannot change } break; case 0x22: switch (buffer[29]) { case 0x01: err = 55; break; //not possible during execution case 0x02: err = 56; break; //not possible while running case 0x03: err = 57; break; //wrong PLC mode case 0x04: err = 58; break; //wrong PLC mode case 0x05: err = 59; break; //wrong PLC mode case 0x06: err = 60; break; //wrong PLC mode case 0x07: err = 61; break; //specified node not polling node case 0x08: err = 62; break; //step cannot be executed } break; case 0x23: switch (buffer[29]) { case 0x01: err = 63; break; //file device missing case 0x02: err = 64; break; //memory missing case 0x03: err = 65; break; //clock missing } break; case 0x24: if (buffer[29] == 0x01) err = 66; //table missing break; case 0x25: switch (buffer[29]) { case 0x02: err = 67; break; //memory error case 0x03: err = 68; break; //I/O setting error case 0x04: err = 69; break; //too many I/O points case 0x05: err = 70; break; //CPU bus error case 0x06: err = 71; break; //I/O duplication case 0x07: err = 72; break; //CPU bus error case 0x09: err = 73; break; //SYSMAC BUS/2 error case 0x0a: err = 74; break; //CPU bus unit error case 0x0d: err = 75; break; //SYSMAC BUS No. duplication case 0x0f: err = 76; break; //memory error case 0x10: err = 77; break; //SYSMAC BUS terminator missing } break; case 0x26: switch (buffer[29]) { case 0x01: err = 78; break; //no protection case 0x02: err = 79; break; //incorrect password case 0x04: err = 80; break; //protected case 0x05: err = 81; break; //service already executing case 0x06: err = 82; break; //service stopped case 0x07: err = 83; break; //no execution right case 0x08: err = 84; break; //settings required before execution case 0x09: err = 85; break; //necessary items not set case 0x0a: err = 86; break; //number already defined case 0x0b: err = 87; break; //error will not clear } break; case 0x30: if (buffer[29] == 0x01) err = 88; //no access right break; case 0x40: if (buffer[29] == 0x01) err = 89;//service aborted break; } } if (err == 0 && isRead) Array.Copy(buffer, 30, rev, 0, rev.Length); return err; } #endregion } }
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/211807.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午9:33
下一篇 2026年3月18日 下午9:33


相关推荐

  • 无锁环形缓冲区的详细解释

    无锁环形缓冲区的详细解释由以下博客的分析可以知道,内核的kfifo使用了很多技巧以实现其高效性。比如,通过限定写入的数据不能溢出和内存屏障实现在单进程写单进程读的情况下不使用锁。因为锁是使用在共享资源可能存在冲突的情况下。还用设置buffer缓冲区的大小为2的幂次方,以简化求模运算。通过使用unsignedint为kfifo的下标,可以不用考虑每次下标超过size时对下表进行取模运算赋值,这里使用到了无符号整数的溢出回

    2022年5月21日
    90
  • 数据挖掘模型中的IV和WOE详解

    数据挖掘模型中的IV和WOE详解1 IV 的用途 IV 的全称是 Information nbsp Value 中文意思是信息价值 或者信息量 我们在用逻辑回归 决策树等模型方法构建分类模型时 经常需要对自变量进行筛选 比如我们有 200 个候选自变量 通常情况下 不会直接把 200 个变量直接放到模型中去进行拟合训练 而是会用一些方法 从这 200 个自变量中挑选一些出来 放进模型 形成入模变量列表 那么我们怎么去挑选入模变量呢 挑选入模变

    2026年3月26日
    1
  • 如何使用banana进行产品替换

    如何使用banana进行产品替换

    2026年3月15日
    2
  • Midjourney平替本地部署全指南

    Midjourney平替本地部署全指南

    2026年3月15日
    2
  • vscode 和 pycharm

    vscode 和 pycharm代码编写工具介绍 vscodepychar 是微软一款开源的编写代码工具 它支持很多的编程语言 例如 PHP C C 等等 当然我们的 python 也不例外 那么我们先来看看它怎么安装吧传送门 vscode 官网 vscode 编写 python 的 3 个先决条件 1 安装下载 vscode2 安装插件 3 安装 python3 这个我们前面说过了 然后选择你的 python 解释器 就可以开始编写我们的 python 代码了 pycharmpycha 是专为开发 python 而存在的一款

    2026年3月27日
    2
  • PotPlayer使用技巧和常用快捷键

    PotPlayer使用技巧和常用快捷键常用快捷键Alt+K屏幕旋转

    2022年5月21日
    84

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号