ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

西门子PLC Socket通信实战:TCON/TSEND/TRCV指令详解与避坑指南

西门子PLC Socket通信实战:TCON/TSEND/TRCV指令详解与避坑指南 1. 为什么Socket通信在西门子PLC项目里越来越绕不开干了十来年自动化我越来越明显地感觉到一个变化以前做项目PLC就是个孤岛接几个按钮、继电器、变频器跑个逻辑就完事了。现在不一样了甲方张口就是“数据要上MES”“设备状态要进看板”“扫码枪要跟PLC联动”这些需求背后几乎都指向同一个东西——Socket通信。Socket通信说白了就是PLC跟外部设备之间开一条“网络管道”双方按照约定好的格式收发数据。它不像Modbus那样有固定的寄存器地址表也不像Profinet那样是西门子自家的闭环生态。Socket给的是最原始的网络字节流灵活度极高但代价是什么都要自己定义。这就像给你一根网线两端怎么说话、说什么话、语速多快全得自己商量。我见过太多同行在这个环节翻车。有人用开放式用户通信指令写了一半发现连接数不够有人数据发出去对方收不到排查半天发现是字节序搞反了还有人压根没搞清楚ISO-on-TCP和TCP的区别就上手结果跟第三方设备死活握不上手。这些问题不是PLC编程逻辑的问题而是对Socket通信机制理解不到位造成的。这篇文章我打算把西门子PLC做Socket通信这件事从头到尾拆一遍。不管你是用S7-1200、S7-1500还是老当益壮的S7-300/400底层逻辑是相通的。我会讲清楚TCON、TSEND、TRCV这些指令到底怎么用参数怎么配连接怎么管坑在哪里以及怎么用最笨但最稳的办法把通信跑通。适合有一定PLC基础、正准备做设备联网或者跟第三方系统对接的朋友。零基础也能看但最好先摸过博途或者STEP 7的界面。2. 西门子PLC做Socket通信的整体设计思路2.1 开放式用户通信到底开放了什么西门子的开放式用户通信Open User Communication本质上就是让PLC的以太网口不再只服务于Profinet和S7通信而是可以像PC一样建立标准的TCP/IP连接。这个“开放”体现在两个层面一是协议开放支持TCP、ISO-on-TCP、UDP三种传输层协议二是数据开放发什么内容、什么格式、什么时候发完全由程序控制。为什么西门子要搞这么一套东西因为工业现场的设备太杂了。视觉系统可能是康耐视的扫码枪可能是基恩士的机械手可能是发那科的这些设备不一定支持Profinet但几乎都支持TCP/IP。PLC作为产线的控制核心天然就应该承担起“数据汇聚点”的角色。开放式用户通信就是给PLC装了一张“通用嘴”什么协议都能聊。但这里有个关键点很多人忽略开放式用户通信是“主动”的。PLC既可以做客户端主动去连别人也可以做服务端等着别人来连。这两种角色的程序写法完全不同连接建立的方向决定了谁先发起、谁负责重连、谁管理连接资源。2.2 TCP、ISO-on-TCP、UDP到底选哪个这是第一个要做出的技术决策选错了后面全是麻烦。我先把三者的核心差异摆出来特性TCPISO-on-TCP (RFC1006)UDP连接方式面向连接面向连接无连接数据边界字节流无边界保留消息边界保留消息边界可靠性可靠有重传可靠有重传不可靠不重传头部开销20字节207字节8字节典型用途通用设备对接西门子设备间、S7通信实时性要求高、允许丢包PLC指令TCON/TSEND/TRCVTCON/TSEND/TRCVTUSEND/TRCVTCP是最通用的跟PC软件、视觉系统、扫码枪对接基本都用它。但TCP有个“粘包”问题——发送方发了三次数据接收方可能一次全收到也可能分五次收到因为TCP只保证字节顺序不保证消息边界。这就需要在应用层自己做协议解析。ISO-on-TCP是西门子对TCP的“改良版”在TCP基础上加了7个字节的TPKT头部里面包含了数据长度信息所以接收方知道一条消息到哪里结束。如果你跟西门子自己的设备或者支持RFC1006的系统通信用这个省心很多。UDP适合什么场景比如你只是周期性广播一些状态信息丢一两帧无所谓或者对延迟极其敏感、不能接受TCP重传带来的抖动。但工业现场大多数场景还是求稳UDP用得相对少。我的建议很直接跟第三方设备对接先问对方支持什么。如果对方只说“支持TCP”那就老老实实用TCP然后在应用层定义好消息长度或者结束符。如果对方支持ISO-on-TCP优先用这个省去粘包处理的麻烦。2.3 连接资源不是无限的得算着用这是很多新手容易踩的坑。S7-1200和S7-1500的开放式用户通信连接数是有限制的不是你想建多少就建多少。以S7-1200为例CPU 1214C最多支持8个开放式用户通信连接其中主动连接和被动连接共享这个池子。S7-1500的CPU 1516-3 PN/DP最多支持128个连接但其中给开放式用户通信的也有单独上限。具体数值一定要查对应CPU的技术数据手册别拍脑袋。为什么要有这个限制因为每个连接都要占用PLC的内存和通信处理器资源。PLC不是服务器它的主职工作是跑控制逻辑通信只是副业。连接数开太多扫描周期会受影响严重的时候甚至会导致CPU停机。实际项目里怎么规划我一般按这个原则需要频繁交互的设备比如视觉系统、机械手用长连接一直保持着只是偶尔发个信号的设备比如某些仪表用短连接发完就断。长连接数量控制在CPU上限的60%以内留出余量给调试和临时接入。3. 核心指令拆解与参数配置实操3.1 TCON连接建立的第一步TCON指令是建立通信连接的核心。它的作用就是根据你配置的连接参数主动或被动地建立一个TCP或ISO-on-TCP连接。在博途里TCON的调用需要配合一个TCON_IP_v4或TCON_IP_v6的数据结构。这个结构里包含了连接类型、本地端口、远程IP、远程端口、主动/被动模式等关键信息。我拿一个实际例子来说。假设我们要让S7-1200作为客户端去连接一台IP为192.168.1.100、端口号为8500的视觉系统。配置大概是这样的连接类型TCP 主动连接TRUEPLC主动去连对方 本地端口0自动分配 远程地址192.168.1.100 远程端口8500这里有个细节本地端口填0表示由系统自动分配一个空闲端口。如果你填了固定值比如2000那就要确保这个端口没有被其他连接占用。我一般建议新手填0省去端口冲突的排查。TCON的REQ引脚用上升沿触发。注意不是每个扫描周期都触发那样会反复尝试建立连接。正确的做法是用一个上升沿检测比如用R_TRIG指令只在需要建立连接的那一刻触发一次。TCON执行后DONE置位表示连接建立成功ERROR置位表示失败STATUS里会有具体的错误代码。这个STATUS值一定要会看它是排查问题的第一手线索。3.2 TSEND把数据推出去连接建立之后就可以用TSEND发数据了。TSEND的关键参数有三个DATA是发送数据的地址和长度LEN是实际发送的字节数CONNECT是TCON建立的那个连接ID。这里最容易出问题的是DATA的数据类型。TSEND的DATA引脚接受的是ANY指针类型你可以填P#DB1.DBX0.0 BYTE 100这样的格式表示从DB1的第0字节开始发100个字节。但要注意这个DB必须是优化的块还是非优化的块在S7-1200/1500里如果DB是优化的绝对地址访问会受限。我一般建议做通信用的DB块取消“优化的块访问”属性用标准地址访问省得指针算错。LEN参数填实际要发送的字节数。如果你填的LEN大于DATA实际有效的长度会把后面的垃圾数据也发出去。如果小于就只发前面一部分。这个值最好用变量控制根据实际数据长度动态变化。TSEND的REQ同样用上升沿触发。DONE置位表示数据已经成功交给通信处理器发送出去了注意是“交给发送缓冲区”不是“对方已经收到”。TCP是异步的TSEND的DONE只代表本地发送动作完成。3.3 TRCV把数据收进来TRCV是接收指令参数跟TSEND类似。DATA是接收缓冲区的地址LEN是期望接收的最大字节数CONNECT还是那个连接ID。TRCV有个EN_R引脚使能接收。这个引脚一般一直置TRUE让PLC随时准备接收数据。当有数据到达时NDR引脚会置位一个扫描周期表示“新数据到了”。这时候你去读DATA里的内容就是刚收到的数据。但这里有个大坑TRCV的LEN参数。如果你填了100但对方只发了50个字节TRCV会一直等直到收满100个字节或者超时。这就会导致数据明明到了但NDR不置位程序读不到。正确的做法是LEN填你协议里定义的最大消息长度然后在应用层根据实际收到的长度TRCV的RCVD_LEN参数来解析有效数据。还有一个更隐蔽的问题如果对方发数据的频率很快而你的TRCV调用周期跟不上数据可能会在通信处理器的缓冲区里堆积。TRCV每次只取一条消息如果缓冲区里有三条你需要调用三次TRCV才能全部取完。所以TRCV的调用不能只在NDR置位时做一次而应该循环调用直到没有新数据。3.4 连接管理建立之后别忘了断开TDISCON指令用来断开连接。什么时候需要断开如果对方设备要重启、要修改IP、或者你的程序要切换到另一个连接目标就得先断开再重连。但很多项目里连接建立之后就再也不管了。这本身没问题长连接就是应该一直保持。但你要考虑异常情况如果网络闪断连接断了PLC这边可能还认为连接是好的继续TSEND结果数据发不出去。所以健壮的程序应该定期检查连接状态发现断了就重新TCON。怎么检查可以看TCON的STATUS也可以用一个心跳机制定期发一个心跳包如果连续几次TSEND都报错就判定连接断开触发重连逻辑。4. 完整实操过程从零搭建一个PLC与PC的Socket通信4.1 硬件与软件环境准备我拿手头的一套设备来演示S7-1200 CPU 1214C DC/DC/DC博途V16一台普通Windows PC。PLC的IP设为192.168.0.10PC的IP设为192.168.0.100两者在同一个网段。PC端我用一个简单的TCP调试助手来模拟第三方设备。这类工具网上很多功能都差不多可以创建TCP服务端或客户端可以手动发数据可以看接收到的数据。实际项目里对方可能是视觉系统、扫码枪或者上位机软件但调试阶段用这个最方便。博途里需要做的准备工作新建项目添加CPU配置IP地址然后在程序块里新建一个用于通信的DB块取消优化访问里面定义一个100字节的数组作为发送缓冲区再定义一个100字节的数组作为接收缓冲区。4.2 连接参数的数据结构配置在博途里TCON指令需要一个CONNECT参数这个参数的数据类型是TCON_IP_v4。我一般会在DB块里定义一个这种类型的变量然后在程序里赋值。具体配置如下InterfaceId64这是PLC以太网口的硬件标识符在设备组态里能看到 ID1连接的唯一编号自己定别跟其他连接冲突 ConnectionType16#0BTCP的代码ISO-on-TCP是16#0CUDP是16#13 ActiveEstablishedTRUE主动连接 RemoteAddress192.168.0.100 RemotePort2000 LocalPort0InterfaceId这个值很多人不知道怎么填。在博途的设备视图里双击PLC的以太网口在属性里能看到“硬件标识符”S7-1200一般是64S7-1500可能是64或者其他的。填错了连接建不起来。ConnectionType的代码要记准TCP是16#0BISO-on-TCP是16#0CUDP是16#13。这个在西门子文档里有但经常有人填错。4.3 程序逻辑的完整实现程序结构我分成三块连接管理、发送逻辑、接收逻辑。连接管理这块用一个状态机来控制。状态0是空闲状态1是正在建立连接状态2是连接已建立状态3是连接断开需要重连。状态0如果StartConnect为TRUE调用TCON进入状态1 状态1等待TCON的DONE或ERROR。DONE则进入状态2ERROR则回到状态0并记录错误 状态2连接正常可以TSEND和TRCV。如果TSEND连续报错3次进入状态3 状态3调用TDISCON然后回到状态0发送逻辑用一个上升沿触发。比如PC端发来一个请求PLC收到后回复一个响应。或者PLC周期性主动发送状态数据用定时器触发TSEND。接收逻辑把TRCV的EN_R一直置TRUENDR置位时把数据从接收缓冲区拷贝到解析缓冲区然后调用解析程序。这里我贴一段核心代码的伪代码用SCL写// 连接管理 CASE #connState OF 0: // 空闲 IF #startConnect THEN #tconReq : TRUE; #connState : 1; END_IF; 1: // 连接中 #tconReq : FALSE; TCON(REQ : #tconTrigger, CONNECT : #tconParams, DONE #tconDone, ERROR #tconError, STATUS #tconStatus); IF #tconDone THEN #connState : 2; ELSIF #tconError THEN #connState : 0; END_IF; 2: // 已连接 // 发送和接收逻辑 IF #sendTrigger THEN TSEND(REQ : #sendTrigger, DATA : #sendBuffer, LEN : #sendLen, CONNECT : #connId, DONE #sendDone, ERROR #sendError); END_IF; TRCV(EN_R : TRUE, DATA : #recvBuffer, LEN : 100, CONNECT : #connId, NDR #recvNdr, ERROR #recvError); 3: // 断开重连 TDISCON(REQ : TRUE, CONNECT : #connId); #connState : 0; END_CASE;这段代码是简化版实际项目里还要加错误处理、超时计数、心跳检测等。4.4 联调过程与数据验证程序下载到PLC后先在PC上打开TCP调试助手创建服务端监听2000端口。然后PLC上触发StartConnect观察TCON的STATUS。如果一切正常TCON的DONE会置位STATUS为0。PC端的调试助手会显示有一个客户端连进来了。然后PLC触发TSEND发送一串测试数据比如“Hello PLC”。PC端应该能收到这串字符。反过来PC端发送“Hello PC”PLC的TRCV的NDR置位接收缓冲区里应该能看到这串字符。联调的时候我习惯用博途的在线监控功能把TCON、TSEND、TRCV的STATUS和NDR、DONE这些引脚都监控起来。哪个环节出问题一目了然。数据验证要注意字节序。西门子PLC是大端模式PC是小端模式。如果你发的是多字节的数值比如一个32位整数PC端收到的字节顺序是反的。解决办法是在发送前用SWAP指令把字节序转一下或者双方约定好都用大端。5. 常见问题与排查技巧实录5.1 连接建立失败STATUS代码速查TCON的STATUS值是最重要的排查依据。我整理了几个常见的STATUS (十六进制)含义排查方向0000成功无8081连接已存在检查是否重复调用TCON8082连接资源不足减少连接数或换CPU8083连接参数错误检查IP、端口、InterfaceId8085连接被对方拒绝对方服务未启动或端口不对8086连接超时网络不通或对方无响应8090连接被本地断开检查TDISCON是否被误触发8091连接被远程断开对方主动断开了连接8085和8086是最常见的。8085一般是PC端的服务端没开或者防火墙拦了。8086一般是IP地址不对或者网线没插好。我遇到过好几次是PC的防火墙把入站连接挡了关掉防火墙就好了。5.2 数据发出去对方收不到TSEND的DONE置位了但对方没收到数据。这种情况先确认TSEND的DONE到底代表什么——它只代表数据交给了本地通信处理器不代表对方收到了。排查步骤第一确认连接是好的TCON的STATUS为0。第二确认LEN参数正确别发了个空数据。第三确认DATA指针指向的地址有有效数据。第四在PC端用抓包工具看数据到底有没有发出去。我遇到过一次TSEND的DATA填的是P#DB1.DBX0.0 BYTE 100但DB1是优化块绝对地址访问无效发出去的全是零。把DB1改成非优化块就好了。5.3 接收数据不完整或粘包TCP的粘包问题前面提过。如果你用TCP协议接收方收到的数据可能不是一条完整消息。解决办法有两种一是用ISO-on-TCP自带消息边界二是在应用层定义协议比如每条消息前面加4个字节的长度头接收方先读长度头再根据长度读消息体。我一般推荐第二种虽然麻烦点但通用性强。具体做法是接收缓冲区设大一点比如1024字节。TRCV收到数据后先看前4个字节解析出消息长度然后判断缓冲区里的数据够不够一条完整消息。如果够就取出来处理如果不够就等下一次TRCV。5.4 连接数超限导致CPU报警S7-1200的开放式用户通信连接数有限超了会报错严重的时候CPU会进入停止模式。我见过一个项目程序里动态创建连接每次触发都TCON一次但从来不TDISCON连接数很快用完了。解决办法连接用完之后一定要TDISCON。如果确实需要多个连接算好总数别超过CPU上限。S7-1200 1214C最多8个1215C最多16个具体查手册。5.5 心跳机制的设计与实现长连接不能光靠TCP自身的保活机制那个时间太长了默认要两个小时。实际项目里要自己做心跳。我的做法是PLC每隔5秒发一个心跳包内容可以是一个固定的字符串或者一个递增的计数器。同时监控TSEND的ERROR如果连续3次发送失败就判定连接断开触发重连。PC端也要配合收到心跳包后回复一个心跳响应。如果PLC连续3次没收到响应同样判定断开。这样双向检测可靠性高很多。心跳间隔设多少看项目要求。一般5到10秒比较合适太短了增加网络负担太长了故障发现不及时。6. 进阶话题多设备通信与性能优化6.1 一个PLC跟多台设备同时通信实际项目里PLC往往要同时跟好几台设备通信。比如一台S7-1500要跟3台视觉系统、2台机械手、1台上位机同时交换数据。这时候连接管理就很重要了。我的做法是给每个连接分配一个独立的连接ID和状态机用一个数组来管理。每个连接的状态机独立运行互不干扰。但要注意所有连接共享CPU的通信资源。如果同时有大量数据收发通信处理器的缓冲区可能会满。这时候TSEND会报错STATUS可能是8082或者80A1。解决办法是降低发送频率或者增大缓冲区或者升级CPU。6.2 数据量大时的分片传输如果要发的数据超过TRCV的LEN或者超过通信处理器的单次传输上限就需要分片。比如要发1000个字节但单次最多发200个字节那就分5次发。分片传输的关键是双方要约定好分片规则。我一般用这样的协议每条消息前面加一个头包含总长度、分片序号、分片总数。接收方根据这些信息重组数据。分片传输会增加延迟所以如果数据量确实大考虑用ISO-on-TCP或者换更高速的通信方式。6.3 通信对扫描周期的影响开放式用户通信的指令调用会占用扫描时间。TCON、TSEND、TRCV这些指令执行一次的时间取决于数据量和通信处理器的状态。数据量大的时候单次调用可能占用几毫秒。如果扫描周期本来就很紧张比如1毫秒那通信指令的调用就要分散到不同的扫描周期里。我的做法是用一个计数器每个扫描周期只处理一个连接的通信轮询着来。这样单次扫描的负担就小了。另外TRCV的EN_R一直置TRUE会持续占用资源。如果不需要一直接收可以只在需要的时候置TRUE。6.4 与Modbus TCP的对比与选择有人会问既然有Modbus TCP为什么还要用SocketModbus TCP确实简单有现成的指令库不用自己定义协议。但它的局限性也很明显数据模型固定只有线圈和寄存器复杂的数据结构表达不了。Socket的优势就是灵活。你可以发JSON、发XML、发二进制自定义协议想怎么来就怎么来。代价就是什么都要自己写。我的选择标准是如果对方设备支持Modbus TCP而且数据量不大、结构简单优先用Modbus TCP省事。如果对方只支持原始TCP或者数据结构复杂那就用Socket自己定义协议。7. 我个人在实际项目中的几点体会做Socket通信这些年踩过的坑比写过的代码还多。最大的体会就是协议设计比编程本身更重要。很多问题不是PLC程序写错了而是一开始协议就没定义清楚。发送方和接收方对数据格式的理解不一致后面怎么调都是白搭。所以我现在做项目第一步永远是跟对方坐下来把协议写清楚用什么协议、端口号多少、数据格式是什么、字节序是大端还是小端、心跳怎么发、异常怎么处理。这些写明白了编程就是体力活。第二个体会是调试工具要趁手。我电脑上常备TCP调试助手、Wireshark、串口调试助手这几样。Wireshark尤其重要它能抓到网络上的原始数据包看到底发了什么、收了什么。很多在PLC程序里看不出来的问题抓包一看就明白了。第三个体会是别怕用最笨的办法。我见过有人为了追求“优雅”把通信程序写得极其复杂状态机套状态机结果出了问题自己都理不清。其实通信程序最重要的是稳定不是优雅。用最简单的状态机把每种情况都考虑到比什么设计模式都管用。最后分享一个小技巧在通信DB块里留一个“调试缓冲区”把每次发送和接收的数据都存一份带上时间戳。出了问题的时候把这个缓冲区导出来一看什么时候发了什么、收了什么一清二楚。这个习惯帮我省了无数排查时间。
返回列表