NJ1P2 Tcp连接不成功,咨询客服说不支持Fins Tcp,所以改成Udp方式。
Udp连接:
locateIp = IPAddress.Parse(txtLocateIP.Text);
locatePoint = new IPEndPoint(locateIp, Convert.ToInt32(txtLocatePort.Text));
udpClient = new UdpClient(locatePoint);
Fins通讯主要是报文格式
上位机发送 FINS UDP 命令读写 PLC 数据.pdf
使用 0101 代码读 D100 的数据,命令如下: 0101(读代码)82(DM 地址代码)006400(D100)0001(1 个数据)
DM区 代码:82 W区bit : 31 字:B1
006400 =》 D100 实际地址(需要在PLC上 全局变量里分配到
指定 实际地址 W区的0.01就是0地址的第1位,0.00是0地址的第0位
用 0102 代码写 W0.05 为 ON,命令如下: 0102(写代码)31(W 位地址代码)000005(W0.05)0001(1 个数据)01(ON)
读 D100 数据,完整命令如下: 800002(固定) 000300(PLC节点)00C000(计算机节点)00(结束)0101(读数据)82(DM区)006400(实际地址 D100)0001(长度)
反馈:
C00002 00C000(计算机节点) 000300(PLC 节点) 00 0101(读数据) 0000(正常反馈) 0123(数据)
写 W0.05 完整命令如下: 800002 000300 00C000 00 0102 31 000005 0001 01
比较大的整数和浮点数,长度是2位,4个字节。需要CDAB格式转换一下
byte[] newdataa = new byte[4];
newdataa[0] = Num[2];
newdataa[1] = Num[3];
newdataa[2] = Num[0];
newdataa[3] = Num[1];
if (BitConverter.IsLittleEndian) Array.Reverse(newdataa);
int intFinish = BitConverter.ToInt32(newdataa, 0);
欧姆龙PLC的FINS协议解释
UDP访问方式:
读取示例:读取DM区20个字, 从DM100H开始
命令:80 00 02 00 41 00 00 0B 00 00 01 01 82 00 64 00 00 14
说明:
80 00 02 固定帧头
00 41 00 设备的网络号,节点号,单元号
00 0B 00 PC的网络号,节点号,单元号
00 01 01 SID+MRC+SRC
82 表示DM区
00 64 首地址
00 固定
00 14 读取数量
响应: D100=0x1388, D101=0x1770, D102=0x1b58
c0 00 02 00 0b 00 00 41 00 00 01 01 00 00 13 88 17 70 1b 58 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
说明:
C0 00 02 固定帧头
00 0B 00 PC网络号,节点号,单元号
00 41 00 设备网络号,节点号,单元号
00 01 01 SID+MRC+SRC
00 00
数据区:
13 88 17 70 1b 58 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
————————————————
demo:UCMM
//1.注册会话ID
byte[] registerSessionCommand = new byte[]
{
//--------------------------------------------------------Header 24byte-------------------------------------
0x6F,0x00,//命令 2byte
0x04,0x00,//Header后面数据的长度 2byte
0x00,0x00,0x00,0x00,//会话句柄 4byte
0x00,0x00,0x00,0x00,//状态默认0 4byte
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//发送方描述默认0 8byte
0x00,0x00,0x00,0x00,//选项默认0 4byte
//-------------------------------------------------------CommandSpecificData 指令指定数据 4byte
0x01,0x00,//协议版本 2byte
0x00,0x00,//选项标记 2byte
};
//2.提取会话ID-注册请求的应答报文
byte[] RefRegisterCmd = new byte[28]
{
//--------------------------------------------------------Header 24byte-------------------------------------
0x6F, 0x00,//命令 2byte
0x04, 0x00,//CommandSpecificData的长度 2byte
0x6B, 0x01, 0x01, 0x00,//会话句柄 4byte 由PLC生成
0x00, 0x00, 0x00, 0x00,//状态默认0 4byte
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//发送方描述默认0 8byte
0x00, 0x00, 0x00, 0x00,//选项默认0 4byte
//-------------------------------------------------------CommandSpecificData 指令指定数据 4byte
0x01, 0x00,//协议版本 2byte
0x00, 0x00,//选项标记 2byte
};
byte[] SessionHandle = new byte[4] { 0x6B, 0x01, 0x01, 0x00 };//从应答报文提取的会话ID:索引4开始,查找4个字节
//------------------3.读数据服务请求报文-------------------------
//报文由三部分组成 Header 24个字节 、CommandSpecificData 16个字节、以及CIP消息(由读取的标签生成)实例,
//读取单个标签名为 TAG1的报文总长度为64个字节
byte[] Header = new byte[24]
{
0x6F,0x00,//命令 2byte
0x28,0x00,//长度 2byte(总长度-Header的长度)=40
0x6B,0x01,0x01,0x00,//会话句柄 4byte
0x00,0x00,0x00,0x00,//状态默认0 4byte
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//发送方描述默认0 8byte
0x00,0x00,0x00,0x00,//选项默认0 4byte
};
byte[] CommandSpecificData = new byte[16]
{
0x00,0x00,0x00,0x00,//接口句柄 CIP默认为0x00000000 4byte
0x01,0x00,//超时默认0x0001 4byte
0x02,0x00,//项数默认0x0002 4byte
0x00,0x00,//空地址项默认0x0000 2byte
0x00,0x00,//长度默认0x0000 2byte
0xb2,0x00,//未连接数据项默认为 0x00b2
0x18,0x00,//后面数据包的长度 24个字节(总长度-Header的长度-CommandSpecificData的长度)
};
byte[] CipMessage = new byte[24]
{
0x52,0x02, //服务默认0x52 请求路径大小 默认2
0x22,0x06,0x24,0x01,//请求路径 默认0x01240622 4byte
0x0A,0xF0,//超时默认0xF00A 4byte
0x0A,0x00,//Cip指令长度 服务标识到服务命令指定数据的长度
0x4C,//服务标识固定为0x4C 1byte
0x03,// 节点长度 2byte 规律为 (标签名的长度+1/2)+1
0x91,//扩展符号 默认为 0x91
0x04,//标签名的长度
0x54,0x41,0x47,0x31,//标签名 :TAG1转换成ASCII字节 当标签名的长度为奇数时,需要在末尾补0 比如TAG转换成ASCII为0x54,0x41,0x47,需要在末尾补0 变成 0x54,0x41,0x47,0
0x01,0x00,//服务命令指定数据 默认为0x0001
0x01,0x00,0x01,0x00//最后一位是PLC的槽号
};
//PLC回复报文:
//6F00 1800 6B010100 00000000 0000000000000000 00000000 00000000 0100 0200 00000000 B200
//实例,读取多个标签名为 TAG、TAG1的报文总长度为86个字节
//6F003E006B01010000000000000000000000000000000000000000000100020000000000B2002E005202200624010AF020000A02200224010200060010004C0391035441470001004C03910454414731010001000100
//Header:6F003E006B01010000000000000000000000000000000000 24byte
//CommandSpecificData: 00 00 00 00 0100020000000000B2002E00 16byte
/*
CipMessage:
-服务代码 - 请求路径大小 - 请求路径 0AF0超时 20 00 CIP指令长度 (0A - 00之间的长度为32个字节)
-请求路径大小 请求路径 0200 标签的数量 0600 偏移量(初始值为:2 + 标签数量 * 2)
1000 偏移量 = 标签服务长度 + 初始偏移量(有几个标签就有几个偏移量)
4C 03 91 03 54414700 0100 标签TAG 4C039104544147310100 标签TAG1
PLC回复报文:
6F00006B01010000000000000000000000000000000000000000000100020000000000B200008A000000020006001300CC000000D00005003232323232CC000000D00005003232323232 76byte
Header:6F0034006B01010000000000000000000000000000000000 24byte
CommandSpecificData:000000000100020000000000B2002400 16byte
CipMessage: CC000000D00005003232323232
8A - 多个标签 0000 - 状态 0200 - 项数 0600 - 标签TAG偏移量 1300 - 标签TAG1偏移量 0000 - 状态0正常 D000 - 数据类型:string
0500:字符串长度(字符串类型特有的)
3232323232 - 数据 "22222":
目前常用的数据类型: C1 - BOOL C2 - SINT C3 - Short C4 - Int C7 - UShort C8 - UInt CA - Float CB - Double D0 - String
*/
//-----------------4.写入数据服务报文--------------------------
/*实例,往标签名为:TAG1 写入true 数据类型为 bool
写入报文:68byte
6F002C006B01010000000000000000000000000000000000 000000000100020000000000B2001C00 5202200624010AF00E004D03910454414731C1000100010001000100
header:6F002C006B01010000000000000000000000000000000000 24byte
CommandSpecificData:000000000100020000000000B2001C00 16byte
20062401 0AF0 0E00 4D 03 91 04 54414731 C100 0100 0100 01000100 28byte
-请求路径大小 20062401-请求路径,默认 0AF0-超时 0E00-CIP指令长度(绿色部分的长度)
4D-写入标识 03-(标签名的长度+1)/2+1 91-扩展符号 04-标签TAG1的长度 54414731 -标签名的ASCII表示
C100-数据类型 0100-默认项 0100-数据 TRUE(2byte) 01000100 - 默认最后一位为PLC槽号
PLC回复报文:
6F0014006B0101 00000 00000000000000000000000000000 000000000100020000000000B2000400CD000000 44byte
header:6F0014006B01010000000000000000000000000000000000 24byte
CommandSpecificData:000000000100020000000000B2000400 16byte
CIPMessage:CD 00 0000 CD-服务标识 00-填充字节 0000-状态好
注意:当写入字符串类型时,写入的数据长度为奇数时,需要在数据后填充一个字节0,必须为偶数
*/
//---- 5.扩展知识----------------------
/*首先建立起TCP连接,CIP通信端口默认为44818。TCP连接成功后,发送会话消息,获取四个字节的会话ID,就可以正常读写了。
000000000000000000000000000000 24byte
0x0000:状态正常(在报文里低位在前高位在后)
0x0001:发出了无效或不受支持的封装命令;
0x0002:接收器中的内存资源不足,无法处理命令;
0x0003:封装消息的数据部分中的数据形成不良或不正确;
0x0004:Reserved for legacy(RA);
0x0064:向目标发送封装消息时,始发者使用了无效的会话句柄;
0x0065:目标收到一个无效长度的信息
0x0069:不支持的封装协议修订
0x0000 - 成功
0x0004 - 它没有正确生成或匹配标记不存在
0x0005 - 引用的特定项(通常是实例)无法找到
0x0006 - 请求的数据量不适合响应缓冲区。 发生了部分数据传输
0x000A - 尝试处理其中一个属性时发生错误
0x0013 - 命令中没有提供足够的命令数据 / 参数来执行所请求的服务
0x001C - 与属性计数相比,提供的属性数量不足
0x001E - 此服务中的服务请求出错
0x0020 - 命令中参数的数据类型与实际参数的数据类型不一致