前言:
在当前项目中,我们面临一个复杂的通信需求场景。具体而言,存在一个设备A,它仅能以MODBUS-TCP客户端的身份与我们的1500 PLC进行通信。同时,还有另外两个设备B和设备C,它们仅支持作为MODBUS-TCP服务器被访问。这导致了一个挑战:我们的1500 PLC需要同时扮演双重角色——作为服务器响应设备A的请求,以及作为客户端主动与设备B和设备C进行通信。
在寻找这些资料以及验证的过程中耗费了我三四天的时间,导致时间大量的浪费所以我将这份案例分享给大家希望大神口下留情,废话就不多说了马上开始:
所需软件:
TIA Portal V16
PLCSIM Advanced
下文中仅需要这两款软件即可实现,都是搞技术的,相信大家可以找到学习版
正文:
1、1500作为客户端与设备B\设备C做通讯
MD_CLIENT指令
该指令的描述为“通过PROFINET进行通讯,作为Modbus TCP客户端”,引脚的定义我们不再过多讲述,在博图中F1一下指令就知道了,我们这里快速过一遍,这里我使用的是SCL语言写的,东西都是一样的,我直接将意思注释在程序中
#MB_CLIENT_Instance(REQ := #REQ[0], //启动命令
DISCONNECT := 0, //0与服务器进行连接,1断开连接
MB_MODE := 1, // 常用的为0和1 ,0为读,1为写
MB_DATA_ADDR := 00001, //ModbusTCP地址常用的为00001,10001,30001,40001
MB_DATA_LEN := 128, //这里指的是数据的长度,也就是说你有多少个数据bool量
DONE => #DONE[0], //指令完成
ERROR => #ERR[0], //指令报错
STATUS => #as[0], //指令状态
MB_DATA_PTR := #DADT.int_bool, //需要数据的区域,注意
CONNECT := #IP_v4); //IP_V4的结构体
以下是程序图片:
写BOOL
读BOOL
读取REAL
写REAL
注意新手常犯的一个错误 MB_CLIENT_Instance 指令在读取一个设备的不同数据时所使用的块必须是同一个块也就是说MB_CLIENT_Instance背景数据块为DB1,那么这4的指令的数据块也为DB1
程序代码:
变量定义:
程序代码:
//轮询机制
IF NOT #REQ[0] AND NOT #REQ[1] AND NOT #REQ[2] AND NOT #REQ[3] THEN//当所以都无启动时启动写BOOL
#REQ[0] := 1;
ELSIF #REQ[0] AND (#DONE[0] OR #ERR[0]) THEN//当写BOOL完成或报错后且REQ[0]为1时启动读BOOL并关闭#REQ[0]
#REQ[0] := 0;
#REQ[1] := 1;
ELSIF #REQ[1] AND (#DONE[1] OR #ERR[1]) THEN//当读BOOL完成或报错后且REQ[1]为1时启动读REAL并关闭#REQ[1]
#REQ[1] := 0;
#REQ[2] := 1;
ELSIF #REQ[2] AND (#DONE[2] OR #ERR[2]) THEN//当读REAL完成或报错后且REQ[2]为1时启动写REAL并关闭#REQ[2]
#REQ[2] := 0;
#REQ[3] := 1;
ELSIF #REQ[3] AND (#DONE[3] OR #ERR[3]) THEN//当写REAL完成或报错后且REQ[3]为1时启动写BOOL并关闭#REQ[3]
#REQ[3] := 0;
#REQ[0] := 1;
END_IF;
//#MB_CLIENT 功能块必须为同一个块可只是启用了不同的数据,否则服务器端会默认为多个TCP链接,导致运行效率降低或直接报错
#MB_CLIENT_Instance(REQ := #REQ[0],//写bool
DISCONNECT := 0,
MB_MODE := 1,
MB_DATA_ADDR := 00001,
MB_DATA_LEN := 128,
DONE => #DONE[0],
ERROR => #ERR[0],
STATUS => #as[0],
MB_DATA_PTR := #DADT.int_bool,
CONNECT := #IP_v4);
#MB_CLIENT_Instance(REQ := #REQ[1],//读BOOL
DISCONNECT := 0,
MB_MODE := 0,
MB_DATA_ADDR := 10001,
MB_DATA_