赞
踩
开个坑,在项目中利用川崎机器人自带的TCP实现了与欧姆龙PLC通讯,仅作为总结记录
1、川崎机器人TCP通讯命令
川崎机器人TCP通讯命令如图
本程序中,川崎机器人作为客户端使用,用到的命令有:TCP_CONNECT、TCP_SEND、TCP_RECV、TCP_CLOSE,外加TCP_STATUS指令,该指令作为通讯连接状态判断。详细的通讯命令用法可参考手册。
2、川崎机器人TCP通讯特性
调试过程中,发现川崎机器人在发送和接收套接字的时候,当要发送或接收的文本中有“H00”这个字节时,川崎机器人会将后面所有的字节认定为“H00”,所以,我在写发送报文的时候将报文拆分成字符串数组处理,保证数组中每个字符串中间不含有“H00”,如下:
.$fsend[1] = $CHR(^H46)+$CHR(^H49)+$CHR(^H4e)+$CHR(^H53)+$CHR(^H0)+$CHR(^H0)+$CHR(^H0) ;报文头 川崎机器人一个ASCII字符串中出现00即Null的时候后面的字符全部置为00
.$fsend[2] = $CHR(^H1a)
.$fsend[3] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0)
.$fsend[4] = $CHR(^H2) ;发送命令代码
.$fsend[5] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0)+$CHR(^H0) ;均为固定字符
.$fsend[6] = $CHR(^H80)+$CHR(^H0)
.$fsend[7] = $CHR(^H2)+$CHR(^H0)
.$fsend[8] = $CHR(^H33)+$CHR(^H0)+$CHR(^H0)
.$fsend[9] = $CHR(^H37)+$CHR(^H0)+$CHR(^H0)
.$fsend[10] = $CHR(^H1)+$CHR(^H1)+$CHR(^H82)+$CHR(^H5)+$CHR(^Hdc)+$CHR(^H0)+$CHR(^H0)
.$fsend[11] = $CHR(^H4)
FINS TCP是欧姆龙公司定义的一套通讯协议,本项目使用欧姆龙CP1H-E型号PLC,该PLC自带一个以太网口,作为服务器,川崎机器人利用套接字通讯来作为客户端;
固定字符(读写握手都有的字符)
.$fsend[1] = $CHR(^H46)+$CHR(^H49)+$CHR(^H4e)+$CHR(^H53)+$CHR(^H0)+$CHR(^H0)+$CHR(^H0) ;报文头 川崎机器人一个ASCII字符串中出现00即Null的时候后面的字符全部置为00
.$fsend[3] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0)
.$fsend[5] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0)+$CHR(^H0) ;均为固定字符
FINS TCP在建立TCP连接后需先发送握手命令报文如下
46 49 4E 53 (ASCII码:FINS;FINS TCP通讯报文头)
00 00 00 0C (数据长度;字节数,从该字节后计算)
00 00 00 00 (命令,握手)
00 00 00 00 (错误;固定为0)
00 00 00 37 (最后一个字节为本站IP最后一位)
发送完上述报文后PLC会回复PLC的节点号,该命令仅在建立TCP连接后发送,在建立FINS TCO 连接后再次发送会报错。
;握手 inspect: .$fsend[2] = $CHR(^Hc) ;发送字节数 .$fsend[4] = $CHR(^H0) ;发送命令代码 .$fsend[6] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0) .$fsend[7] = $CHR(^H37) ;节点号 TCP_SEND rets,sock1,.$fsend[1],7,2 ;发送命令,返回值,套接字号,发送内容,发送字符串数组数量,超时时间 IF rets<>0 THEN;发送数据失败 IF sock1>0 GOTO close GOTO inspect ELSE $state = "连接成功" END ;握手返回 正常返回不做数据处理 inspectrecv: .num = 0 ;返回数组数量 .$recv[1] = "" ;清空返回接收 TCP_RECV retr,sock1,.$recv[1],.num,3,255 ;接收指令 返回值,套接字号,返回值,返回字符串数组数量,超时时间,返回数组最大字符数 IF retr<>0 THEN IF sock1>0 GOTO close GOTO inspectrecv END
读取报文如下
46 49 4E 53 (ASCII码:FINS;FINS TCP通讯报文头)
00 00 00 1A (数据长度;字节数,从该字节后计算)
00 00 00 02 (命令,固定)
00 00 00 00 (错误;固定为0)
80 (需要回复)
00 02 00 (固定)
33 (目标节点号即IP最后一位)
00 00 (固定)
37 (本站节点号)
00 00 (固定)
01 01 (读操作/写是0102)
82 (DM区,其他见下图)
05 DC (寄存器号为D1500)
00 (起始位号)
00 04 (读取寄存器个数,一个寄存器占两个字节)
sendr:
.$fsend[2] = $CHR(^H1a)
.$fsend[4] = $CHR(^H2)
.$fsend[6] = $CHR(^H80)+$CHR(^H0)
.$fsend[7] = $CHR(^H2)+$CHR(^H0)
.$fsend[8] = $CHR(^H33)+$CHR(^H0)+$CHR(^H0)
.$fsend[9] = $CHR(^H37)+$CHR(^H0)+$CHR(^H0)
.$fsend[10] = $CHR(^H1)+$CHR(^H1)+$CHR(^H82)+$CHR(^H5)+$CHR(^Hdc)+$CHR(^H0)+$CHR(^H0)
.$fsend[11] = $CHR(^H4)
TCP_SEND rets,sock1,.$fsend[1],11,2
IF rets<>0 THEN;发送数据失败
IF sock1>0 GOTO close
GOTO sendr
END
读取报文发出后将会收到返回报文 如下
46 49 4E 53 (ASCII码:FINS;FINS TCP通讯报文头)
00 00 00 1A (数据长度;字节数,从该字节后计算)
00 00 00 02 (命令,固定)
00 00 00 00 (错误;固定为0)
00 (无需回复)
00 02 00 (固定)
37 (目标节点号即IP最后一位)
00 00 (固定)
33 (本站节点号)
00 00 (固定)
01 01 (读操作/写是0102)
00 00 (错误码)
XX XX XX XX XX XX XX XX (返回结果)
读取报文如下
46 49 4E 53 (ASCII码:FINS;FINS TCP通讯报文头)
00 00 00 20 (数据长度;字节数,从该字节后计算)
00 00 00 02 (命令,固定)
00 00 00 00 (错误;固定为0)
80 (需要回复)
00 02 00 (固定)
33 (目标节点号即IP最后一位)
00 00 (固定)
37 (本站节点号)
00 00 (固定)
01 02 (写操作/读是0101)
82 (DM区,其他见下图)
03 E8 (寄存器号为D1000)
00 (起始位号)
00 04 (写取寄存器个数,一个寄存器占两个字节)
XX XX XX XX XX XX XX XX (写入内容)
sendw:
.$fsend[2] = $CHR(^H20)
.$fsend[4] = $CHR(^H2)
.$fsend[6] = $CHR(^H80)+$CHR(^H0)
.$fsend[7] = $CHR(^H2)+$CHR(^H0)
.$fsend[8] = $CHR(^H33)+$CHR(^H0)+$CHR(^H0)
.$fsend[9] = $CHR(^H37)+$CHR(^H0)+$CHR(^H0)
.$fsend[10] = $CHR(^H1)+$CHR(^H2)+$CHR(^H82)+$CHR(^H3)+$CHR(^He8)+$CHR(^H0)+$CHR(^H0)
.$fsend[11] = $CHR(^H3)
TCP_SEND rets,sock1,.$fsend[1],17,2
IF rets<>0 THEN;发送数据失败
IF sock1>0 GOTO close
GOTO sendw
END
先贴个源码 慢慢写分析
.PROGRAM autostart.pc() #0; FinsTCP通讯程序 !!!请不要修改!!! ; ******************************************************************* ; ; Program: autostart.pc ; Comment: ; Author: by ; ; Date: 2023/1/5 ; ; ******************************************************************* ; ; ;初始化 .ip[1] = 192 ;服务器IP .ip[2] = 168 .ip[3] = 0 .ip[4] = 51 .port = 9600 .$fsend[1] = $CHR(^H46)+$CHR(^H49)+$CHR(^H4e)+$CHR(^H53)+$CHR(^H0)+$CHR(^H0)+$CHR(^H0) ;报文头 川崎机器人一个ASCII字符串中出现00即Null的时候后面的字符全部置为00 .$fsend[3] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0) .$fsend[5] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0)+$CHR(^H0) ;均为固定字符 ;输出信号转换 status: BITS 2001,1 = SIG(1007) ;心跳 .pcrun = BITS(2200,5) ;PC执行状态判断 IF .pcrun==3 THEN SIGNAL 2014 ELSE SIGNAL -2014 END .s1[1] = BITS(2001,8) ;输出点转八位数值 .s1[2] = BITS(2009,8) .s1[3] = BITS(2017,8) .s1[4] = BITS(2025,8) .$fsend[12] = $CHR(.s1[2]) ;输出值转位ASCII字符 .$fsend[13] = $CHR(.s1[1]) .$fsend[14] = $CHR(.s1[4]) .$fsend[15] = $CHR(.s1[3]) IF INT(hanjietime*100)>250 THEN .$fsend[16] = $CHR(250) hanjietime = 2.5 ELSE .$fsend[16] = $CHR(INT(hanjietime*100)) END IF INT(lengquetime*100)>250 THEN .$fsend[17] = $CHR(250) lengquetime = 2.5 ELSE .$fsend[17] = $CHR(INT(lengquetime*100)) END .$recv[2] = "" ;初始化接收字符 ;连接状态判断 TCP_STATUS .str1,.str2[1],.str3[1],.str4[1],.str5[1],.$str6[1] ;连接状态监控指令,返回值为总连接数,端口号,套接字号,主错误,子错误,IP地址 IF .str1==0 GOTO connect IF .str3[1]==0 THEN PRINT "请重启电源 " END IF .str3[1]>0 AND sock1>0 GOTO sendr ;连接服务器 connect: TCP_CONNECT sock1,.port,.ip[1],5 ;连接指令,套接字号,端口号。ip地址,超时时间 IF sock1<=0 THEN;通信失败 GOTO connect $state = "连接失败" ELSE $state = "通信打开" END TWAIT 4 ;握手 inspect: .$fsend[2] = $CHR(^Hc) ;发送字节数 .$fsend[4] = $CHR(^H0) ;发送命令代码 .$fsend[6] = $CHR(^H0)+$CHR(^H0)+$CHR(^H0) .$fsend[7] = $CHR(^H37) ;节点号 TCP_SEND rets,sock1,.$fsend[1],7,2 ;发送命令,返回值,套接字号,发送内容,发送字符串数组数量,超时时间 IF rets<>0 THEN;发送数据失败 IF sock1>0 GOTO close GOTO inspect ELSE $state = "连接成功" END ;握手返回 正常返回不做数据处理 inspectrecv: .num = 0 ;返回数组数量 .$recv[1] = "" ;清空返回接收 TCP_RECV retr,sock1,.$recv[1],.num,3,255 ;接收指令 返回值,套接字号,返回值,返回字符串数组数量,超时时间,返回数组最大字符数 IF retr<>0 THEN IF sock1>0 GOTO close GOTO inspectrecv END ;读 sendr: .$fsend[2] = $CHR(^H1a) .$fsend[4] = $CHR(^H2) .$fsend[6] = $CHR(^H80)+$CHR(^H0) .$fsend[7] = $CHR(^H2)+$CHR(^H0) .$fsend[8] = $CHR(^H33)+$CHR(^H0)+$CHR(^H0) .$fsend[9] = $CHR(^H37)+$CHR(^H0)+$CHR(^H0) .$fsend[10] = $CHR(^H1)+$CHR(^H1)+$CHR(^H82)+$CHR(^H5)+$CHR(^Hdc)+$CHR(^H0)+$CHR(^H0) .$fsend[11] = $CHR(^H4) TCP_SEND rets,sock1,.$fsend[1],11,2 IF rets<>0 THEN;发送数据失败 IF sock1>0 GOTO close GOTO sendr END ;读返回 recvr: .num = 0 .$recv[1] = "" TCP_RECV retr,sock1,.$recv[1],.num,3,30 IF retr<>0 THEN SIGNAL -5 IF sock1>0 GOTO close GOTO recvr ELSE $shuju = .$recv[2] ;返回值转存 BITS 2101,8 = ASC($shuju,2) ;返回值ASCII字符转十六进制数字赋给内部输入 BITS 2109,8 = ASC($shuju,1) BITS 2117,8 = ASC($shuju,4) BITS 2125,8 = ASC($shuju,3) BITS 1,1 = SIG(2131) ;专用输入转存 BITS 2,1 = SIG(2115) BITS 3,1 = SIG(2114) BITS 4,1 = SIG(2107) BITS 5,1 = SIG(2106) BITS 6,1 = SIG(2101) END ;写 sendw: .$fsend[2] = $CHR(^H20) .$fsend[4] = $CHR(^H2) .$fsend[6] = $CHR(^H80)+$CHR(^H0) .$fsend[7] = $CHR(^H2)+$CHR(^H0) .$fsend[8] = $CHR(^H33)+$CHR(^H0)+$CHR(^H0) .$fsend[9] = $CHR(^H37)+$CHR(^H0)+$CHR(^H0) .$fsend[10] = $CHR(^H1)+$CHR(^H2)+$CHR(^H82)+$CHR(^H3)+$CHR(^He8)+$CHR(^H0)+$CHR(^H0) .$fsend[11] = $CHR(^H3) TCP_SEND rets,sock1,.$fsend[1],17,2 IF rets<>0 THEN;发送数据失败 IF sock1>0 GOTO close GOTO sendw END ;写返回 recvw: .num = 0 .$recv[1] = "" TCP_RECV retr,sock1,.$recv[1],.num,3,255 IF retr<>0 THEN IF sock1>0 GOTO close GOTO recvw END GOTO status ;跳转至初始位置 close:;##########关闭通信连接########## IF sock1<0 GOTO connect TCP_CLOSE .retc,sock1;关闭通信指令 IF .retc<>0 THEN $state = "关闭失败" TCP_CLOSE .ret1,sock1;强制关闭通信 END $state = "通信关闭" GOTO connect .END
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。