最近项目需要用上位机通讯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
}
}