S7-1200 PLC-PLC通讯实战:PUT/GET指令与TIA组态全解析
简介这是一份面向西门子 S7-1200 用户的 PLC—PLC 通信案例程序包聚焦两台 S7-1200 基于 PROFINET 的数据交换适合需要搭建分布式控制、冗余系统或上位机联动场景的电气工程师与自动化专业学生。压缩包共 66 个文件体积 5.24MB以 QML、CNK、XML 等工程配置文件为主另含 SRT 字幕、PLF/IDX 索引、DAT 数据以及多种调试诊断类型文件按工程模块分区便于快速定位。已有 2347 人学习下载配套说明覆盖网络参数配置、通信接口定义、SFB14/SFB15 连接编程、在线调试与安全注意事项等关键环节集中展示了从组态、编写通信程序到在线诊断的完整链路。通过梳理示例工程读者可掌握两台 PLC 间 PROFINET 通信的完整实现路径熟悉数据格式与传输机制对理解西门子工业以太网、缩短自动化项目联调周期有直接帮助。1. 为什么S7-1200之间“PLC-PLC”通讯成了很多人卡壳的第一道坎做自动化项目的人都知道两台S7-1200要交换十几台变频器的状态、几条生产线的产量、甚至几个模拟量设定值看起来就是个“网线插起来、数据发过去”的事。可真上手你会发现明明两个PLC都是S7-1200网线也连了IP也能互相ping通了但数据就是过不去。要么读回来全是0要么程序编译报错要么通讯半分钟后自动断开。这个标题里的“免费案例程序”之所以很多人搜就是因为官方手册太散网上散落的程序要么版本老要么作者自己都没跑通。作为干过多个现场项目的人我可以负责任地说S7-1200之间的PLC-PLC通讯核心就是S7通信PUT/GET难点不在指令本身而在组态方式的配合、数据块地址的对应、以及那一个个看不见的默认开关。这篇文章把完整案例拆开从选型、组态、写程序到排错全过一遍。新手照抄也能跑通老手能跳着看参数与坑。2. S7-1200 PLC-PLC通讯选型为什么我首选S7通信PUT/GET2.1 三种常见方案S7通信、TCP原生通信、Profinet智能从站两台S7-1200之间交换数据工业现场常用的有三种方案。第一种是S7通信也就是调用PUT和GET指令这是西门子自家协议底层基于ISO-on-TCP不需要你去拼TCP报文指令内部自动处理握手和确认。第二种是用开放式通信TSEND_C/TRCV_C直接走TCP灵活性最高但你要自己定义报文格式、自己处理分包和粘包、自己做数据有效性标志如果只传几十个字节有点杀鸡用牛刀。第三种是把一台1200组态为另一台1200的Profinet智能从站那是做实时轴同步或高速IO交换的用法配置复杂普通数据交换根本没必要。所以如果只是把几十个字节的设备状态、产量计数、工艺参数互传我百分之百推荐S7通信。它有几个实实在在的好处一是指令内置了连接管理你不关心底层连接如何建立二是有明确的数据一致性机制一条PUT/GET指令执行时可以保证数据块整体一致不会出现读到一半被改写的情况三是诊断信息完善出错之后返回值能直接告诉你是连接问题、地址问题还是权限问题。2.2 启用S7通信的前提防护机制必须打开S7-1200从固件4.0开始默认是禁止远程PUT/GET访问的。很多人程序明明和教程一模一样但通讯就是起不来问题十有八九出在这里。在TIA Portal中选中做服务器的PLC右键进入“防护与安全”在弹出的设置里找到“连接机制”必须勾选“允许从远程伙伴进行PUT/GET通讯访问”。这一步不做哪怕两边IP通、程序编译过远程PLC那边数据永远是读不到也写不进。需要留意的是这个选项是针对服务器端PLC的。你两台PLC都要互相读写那么两台PLC都要把这一项勾上。另外如果你用的是一台S7-1200和一台S7-300或S7-1500做通讯那服务器端一般是老款PLC或1500同样需要在其属性中开放访问权限。我见过有人只开了一边的权限结果写过去没问题读回来超时排查半天才找到这里。2.3 通讯伙伴的IP规划与以太网组态S7通信只认IP地址和TSAP。在TIA Portal中给两台PLC都分配好固定IP例如PLC1用192.168.0.1PLC2用192.168.0.2子网掩码统一为255.255.255.0。一定不要用DHCP自动获取PLC重启后IP变了通讯直接断。另外S7-1200 CPU自带的PROFINET接口本身就支持S7通信不需要额外加通信模块。如果你的项目里有多个PLC超过16个连接要留意通讯连接资源限制但两台互传完全没问题。以太网组态时建议在一个项目里同时添加两台PLC分别设置IP后把两个网口都拖到同一条工业以太网总线上。这样TIA会自动识别它们处于同一子网编译下载后连接关系更清晰。实际现场只有一台电脑连两个PLC的交换机时你不需要建两个项目一个项目管理两站最方便后文案例也这么干。3. 用TIA Portal搭建双PLC通讯案例从新建项目到跑通最小代码3.1 新建项目并添加两台S7-1200打开TIA Portal V16以上版本新建项目命名为“PLC_PLC_Demo”。在项目树中双击“添加设备”分别添加两个CPU我用的是1214C DC/DC/DC固件版本V4.4。要注意固件版本低于4.0的CPU没有PUT/GET功能块如果你手里的硬件是老版本需要先升级固件。添加完两台设备后在“设备组态”视图里给两个CPU的PROFINET接口设置IP地址。在CPU属性里的“以太网地址”区域把IP和子网掩码填好。之后在网络的同一个子网内这两个网口之间会有一条绿色连线代表它们在同一个网络中。如果没有自动连线可以手动将两个网口的以太网地址拖到同一个以太网总线上。3.2 组态服务器端PLC的PUT/GET访问权限这是整个案例里最容易被忽略的环节。选中PLC2作为数据提供方右键进入属性找到“防护与安全”下的“连接机制”。在打开的页面里勾选“允许从远程伙伴进行PUT/GET通讯访问”。同样对PLC1也做一次因为后面两个PLC都要互相读和写。勾选之后编译保存然后分别下载到对应PLC。这里有一个小坑如果之后修改了这个选项必须重新下载整个系统数据只下载程序块不会生效。下载时TIA会提示“设备配置已更改”确认下载到存储卡然后复位PLC否则选项仍然不生效。我遇到过明明勾了但线上设备就是拒绝访问后来发现是接线生下载的时候只下载了程序没下载硬件配置。3.3 定义通讯数据块DB10与DB100在PLC1中新建一个数据块名字叫DB_COMM_SEND编号10勾选“优化的块访问”取消也就是使用标准访问。标准访问的好处是地址偏移可以人工控制方便和远程通讯地址对齐。DB10中建两个变量变量名数据类型偏移量初始值StartCmdBool0.0falseTargetSpeedInt2.00RunningStatusBool4.0false在PLC2中新建数据块DB_RECV编号20同样取消优化访问。里面建两个变量变量名数据类型偏移量初始值ReadyBool0.0falseFeedbackSpeedInt2.00这个案例里PLC1把StartCmd和TargetSpeed写入PLC2的DB20同时读取PLC2的Ready和FeedbackSpeed到自己的DB30中。因此PLC1还需要一个接收数据块DB_RECV_LOCAL编号30里面放Ready和FeedbackSpeed两个变量。注意PUT和GET指令的目标地址是远程PLC中的绝对地址需要用昵称字符串方式而源数据类型要和远程数据块严格一致。3.4 编写PUT和GET调用SCL程序在PLC1的组织块OB1中添加一个网络段并将编程语言切换为SCL。直接调用西门子指令“PUT”和“GET”并给它们各分配一个背景DB。TIA会提示块文件的生成。以下是一段可以直接抄的代码// PLC1主程序每分钟执行5次PUT/GET周期由时钟位M0.5控制 IF M0.5 THEN // 用0.1秒时钟位作为触发避免程序周期过短导致通讯频繁 // 读取PLC2的数据到PLC1的DB30 GET_DB( REQ : TRUE, ID : 1, // 连接ID必须与硬件组态或指令块属性一致 ADDR_1 : P#DB20.DBX0.0 BOOL, // 远程读取起始地址 RD_1 : DB30_DBX0_BOOL, RET_VAL : GET_RET ); // 将PLC1的数据写入到PLC2的DB20 PUT_DB( REQ : TRUE, ID : 1, ADDR_1 : P#DB20.DBX0.0 BOOL, SD_1 : DB10_DBX0_BOOL, RET_VAL : PUT_RET ); END_IF;这段代码有个关键点PUT和GET的REQ端不能持续为TRUE否则通讯会被占满CPU负载上升甚至和其他通讯指令冲突。常见做法是用一个周期脉冲位比如用系统时钟M0.50.1Hz或者自己写一个500ms脉冲。我一般用时钟位“Clock_100ms”来触发同时用上升沿后再保持1个扫描周期保证每条指令有一次完整的REQ。ADDR_1参数写法要注意P#DB20.DBX0.0 BOOL表示远程数据块DB20的位地址格式。如果你要读整块数据比如连续10个字应该写成P#DB20.DBX0.0 BYTE 20。TIA的在线帮助里有完整的P#语法。这里为了简单只传了第一个Bool位实际项目中建议用UDT结构体一次传多个变量后面最后一章会讲。3.5 编译下载并验证通讯结果编译整个项目分别将PLC1和PLC2下载。下载完成后将两个PLC都置于RUN模式。打开PLC1的监控表添加DB30中的Ready和FeedbackSpeed变量。手动将PLC2中的Ready置TRUE同时给FeedbackSpeed赋一个整数如1234。很快你会在PLC1的监控表中看到这两个值被同步过来。同理把PLC1的StartCmd置TRUETargetSpeed设为500再到PLC2的监控表中看DB20对应变量会看到已写入。注意观察PUT和GET的返回字RET_VAL如果为0表示无错误为十六进制16#8181表示远程连接被拒绝16#8090表示地址错误。具体代码可以再查系统手册。4. 通讯参数细节与调试方法为什么你的PUT/GET时灵时不灵4.1 指令触发周期与通讯负载平衡PUT和GET的REQ信号是边沿触发的但很多在线程序写成REQ : TRUE。如果REQ常TRUE通讯指令会连续不断地发送请求轻则导致数据刷新过快重则占用大量通讯连接资源造成其他指令如S7通讯上传下载超时。推荐的做法是做一个100ms到500ms的方波脉冲我习惯用系统时钟位“Clock_100ms”直接赋值REQ同时配合上升沿检测保证每条指令在一个周期内只触发一次。当通讯数据量较大时比如一次传64字节以上脉冲周期要适当加长到1秒。因为PUT和GET内部处理需要时间如果前一个请求还没完成下一个请求又来了数据队列会堆积返回字会出现16#8182仍在处理中警告。这时不要慌它只是提醒你频率太高不是致命错误。4.2 连接ID与远程地址的对应关系PUT/GET的ID参数不是随便写的它对应着PLC内部通讯资源中一条激活的连接。在TIA Portal中如果你只调用指令而不做连接组态ID可以填1表示使用该CPU的默认连接资源。但如果你同时使用了多个PUT/GET比如三组通讯建议分别为每条指令分配不同的ID并在“指令属性”中打开连接管理手动关联远程PLC的IP和TSAP。注意ID不要求唯一匹配远程PLC它只是一个本地的“钩子”。远程PLC不检查ID它只看IP和TSAP。所以即使两个调用都写ID1只要它们访问不同的IP也仍然能建立两条不同连接。我见过新手将ID理解成端口号写成500或102反而导致连接冲突。4.3 优化数据块访问标准访问还是优化访问我强烈建议S7通讯的数据块使用标准访问模式。优化访问的DB没有固定偏移量虽然TIA内部能通过符号访问但PUT/GET的ADDR_1参数需要的是绝对地址指向优化块时会提示“地址不可用”。你把DB属性中“优化的块访问”前面的勾去掉TIA会为每个变量生成偏移量。如果项目必须要用优化访问那只能改用符号寻址的S7通信新指令如PUT和GET的新版本但可移植性较差。另外远程DB的编号尽量不要用大于100的块因为S7-1200在标准访问下有些固件版本对DB编号和地址解析有限制。现场我用过DB105也是可以的但如果你遇到地址解析错误先把远程DB改成50以内的编号试试。4.4 诊断技巧用返回字和在线诊断列表定位PUT和GET的每个实例都有一个RET_VAL输出这是16位整型0表示成功。当你通讯不通时先看这个值。常见意义16#8090表示指向的地址没有找到或不可访问16#8181表示连接未建立或远程未授权16#8184表示连接被远程拒绝16#8204表示参数长度错误。不要上来就怀疑IP先看RET_VAL。如果RET_VAL是对的但数据不刷新检查一下REQ是否有脉冲。可以在监控表中强制M0.5为TRUE看数据是否立即变化。更直接的办法是在OB1里再增加一个定时器FB每500ms触发一次REQ同时在监控表里看到REQ位有规律地跳变。5. 避坑与常见问题排查这5个坑我都在现场踩过5.1 通讯建立后能连通一次但数据一直不变现象两台PLC能ping通监控表里RET_VAL也是0但远端变量变化后本地不更新。原因REQ信号是周期脉冲但数据读取需要在REQ为TRUE的扫描周期内完成。如果你用了常TRUE指令会连续读但监控表刷新周期如果跟不上看起来就是“没更新”。更常见的原因是你在两个不同的OB1网络段里分别调用PUT和GET它们共享同一个背景DB导致相互覆盖。解决将PUT和GET放在同一个网络段中公用一个REQ触发位。如果需要同时调用多个PUT/GET确保每个实例有自己的背景DB不要共用。5.2 通讯断断续续几分钟后恢复但马上又断现象两个1200之间交换数据刚开始正常运行几十分钟后数据停止CPU的RUN/STOP灯不闪网络指示灯正常。原因大概率是通讯连接资源被占满。S7-1200 CPU的通信资源有限而PUT/GET指令在REQ为TRUE时持续占用连接。如果程序里某个FB里有一个不用的PUT实例或者在OB100初始化里误调用了通讯指令那么每次上电都会建立一个连接从不释放。解决打开项目树中PLC的“在线诊断”查看通信连接列表看看是否存在“ESTABLISHED”状态但无数据交换的连接。把没用的PUT/GET实例禁用并且只让REQ以脉冲方式工作。另外检查是否有其他程序如HMI连接占用了连接资源把CPU上的Web服务器和HMI访问打开也会消耗资源必要时关闭。5.3 写入远程PLC的数据容易丢失或错误现象本地PLC的数据块已经更新但远程PLC看到的还是旧值或者偶尔能写入偶尔失败。原因S7通信PUT指令对数据一致性有要求如果你正在写入的远程DB块同时被远程PLC的程序写就会产生“写冲突”。西门子的DB块访问是点锁但没有绝对优先级。另外PUT指令默认使用的是“不同步”模式没有做握手。解决把需要通讯的数据区集中到一个专用DB中本地PLC只有通讯指令写这个DB远程PLC只有通讯指令读这个DB避免两边同时对同一地址操作。如果确实需要双向写就在DB里加一个“数据有效”标志位收到数据后把标志位置TRUE发送方等标志位置位后再发下一帧。这也是跨PLC通讯的通用套路。5.4 远程地址带符号名时编译报错现象按照别人的程序写ADDR_1 : PLC2_DB20.Ready编译报“未定义变量”或“接口不受支持”。原因PUT/GET指令的ADDR参数本质是一个ANY指针需要绝对地址。符号访问只在TIA的块接口中支持不能直接写到P#语法里。而且跨PLC引用符号名本来就不被允许。解决对远程数据块不使用符号名直接用P#DB20.DBX0.0 BOOL这种形式。如果嫌偏移量难记在远程PLC的数据块属性里把“优化的块访问”取消然后在变量表里可以看到每个变量的偏移量照着写就行。另一种办法是使用TIA库中的“TSEND_C”和“TRCV_C”配合结构体变量那就完全是另一种路径了。5.5 同一个程序在仿真实训上跑不通现象用TIA的S7-PLCSIM仿真两台PLC程序编译无误但通讯就是建立不了。原因老版本PLCSIM不支持S7-1200之间跨实例的PUT/GET仿真尤其是V13/V14版本只能仿真PLC与第三方S7软件通讯不能模拟PLC-PLC的通信。解决如果你必须仿真可以升级到PLCSIM V16及以上并勾选“支持远程连接”。更靠谱的方法是直接用真实两台PLC再加一个小交换机。我在项目交付前都会用真实PLC做过一次通讯验证避免现场翻车。如果你只有单台PLC可以用电脑装一个S7-PLCSIMV16高级版再配合网络通信库不过配置较繁琐我一般不推荐。6. 把通讯数据打包成UDT一次PUT/GET传完整个结构体当通讯变量超过十几个时逐个定义Bool和Word再分别写ADDR_1极其痛苦还容易漏。更优的做法是在全局数据块中定义一个UDT用户自定义类型把需要交换的数据全部放进一个字段然后PUT/GET时整块传输。下面我给出一个完整示例。在PLC2中新建UDT类型命名为UDT_PumpData包含以下字段字段名数据类型EnableBoolOverrideBoolSetSpeedIntActualSpeedIntCurrentRealFaultCodeWord在PLC2的数据块DB50中定义变量Pump1 : UDT_PumpData取消优化访问。TIA自动计算偏移量。在PLC1的DB40中定义相同的UDT变量Pump1_Remote : UDT_PumpData作为本地镜像。之后在PLC1里只需一条GET指令GET_DB_UDT( REQ : Clock_100ms, ID : 1, ADDR_1 : P#DB50.DBX0.0 BYTE 28, // 28字节 按UDT实际大小 RD_1 : DB40.Pump1_Remote, RET_VAL : GET_UDT_RET );这里的ADDR_1使用的是“BYTE 28”表明传输长度TIA会按实际UDT大小自动填充。注意长度不能乱写要和你定义的UDT的字节数一致。如果UDT里含有Real或Bool长度计算方式比较复杂你在离线项目里右键UDT类型选择“从数据类型生成”能看到它占用的字节数。更稳妥的办法是ADDR_1直接写P#DB50.DBX0.0让TIA根据RD_1的数据类型自动推断但前提是DB50的变量和RD_1类型完全一致。我用后一种更多写了BYTE容易出错。这种做法的好处是显而易见的一次指令传完所有泵的数据程序可读性高新增字段时不用改通讯代码。我在多个项目里把几十台设备的状态都用这种方式交换一条GET指令管理一片远程DB。同时注意UDT中不能用型为String或Variant的数据类型因为S7-1200的通信模块不保证这类可变长数据的一致性。如果你要传字符串用固定长度的Char数组代替。使用时还有个小技巧把数据完整性校验做成一个字节本地和远程各自计算异或后放入UDT的最后一个字节。接收方在收到数据后校验一次不一致则丢弃该帧并置FaultCode。这样可以避免偶发的通讯错误导致设备误动作。别看S7通信有可靠性现场电磁干扰大的时候多一个校验多一分安全。最后分享一个习惯凡是写跨PLC通讯我一定会把通讯DB单独建并且把每个变量后面注释里写上“来源PLC2 槽位2”“发送周期500ms”这类说明。过两三个月你回去调试会发现这些注释比通讯手册都值钱。通讯逻辑本身不难难的是你和同事都能在第一次看见代码时读懂它。希望帮到你。本文还有配套的精品资源点击获取