在S7-1200/1500 PLC编程中,使用结构化文本(ST)实现以太网TCP异步通信时,T_SEND 与 T_RECV 是两个核心系统函数块。它们不依赖循环扫描周期同步执行,而是通过触发信号和完成状态位协同工作,从而在单个OB(如OB1)中安全、高效地管理多路并发通信任务。以下为零依赖、可直接复用的实操指南。
一、先决条件确认
-
硬件与固件
- CPU型号为 S7-1200(固件 V4.0+)或 S7-1500(任意版本);
- 已在TIA Portal中配置好以太网接口IP地址,并启用“允许从远程伙伴访问”;
- 目标服务器(如PC、HMI、另一台PLC)已开启TCP监听端口(例如
5000),且防火墙放行该端口。
-
通信资源预留
- 每个
T_SEND/T_RECV实例占用1个“通信连接资源”; - S7-1200最多支持8个并发TCP连接(含TCON),S7-1500默认支持64个(可扩展至256);
- 禁止在同一个DB中重复声明多个未命名的
T_SEND实例——必须为每个实例分配独立的背景DB。
- 每个
-
数据类型准备
- 定义发送缓冲区:
SendBuffer : ARRAY[0..999] OF BYTE(最大1000字节,实际长度由LEN参数控制); - 定义接收缓冲区:
RecvBuffer : ARRAY[0..999] OF BYTE; - 声明连接ID变量:
ConnID : UINT := 1(值范围1–65535,全局唯一,不可为0)。
- 定义发送缓冲区:
二、建立TCP连接(TCON)
T_SEND 和 T_RECV 不自动建连,需先调用 TCON 函数块完成三次握手。
-
声明TCON背景DB
在DB中定义结构体变量MyTCON : TCON,其成员包括:ID:连接标识符(UINT,与后续T_SEND/T_RECV的ID一致);CONNECT:指向连接描述结构体的指针(P#MyConnectionData);DONE、ERROR、STATUS:状态输出位。
-
配置连接描述结构体
在同一DB中声明:MyConnectionData : TSAP_CONN_REQ := ( remote_address := (ip_address := '192.168.0.100', port := 5000), local_address := (port := 0), // 0 = 自动分配本地端口 connection_type := 1, // 1 = TCP active_establishment := TRUE // TRUE = PLC主动发起连接 ); -
触发连接
设置MyTCON.EN为TRUE;
等待MyTCON.DONE = TRUE且MyTCON.ERROR = FALSE;
若MyTCON.STATUS <> 0,查TIA Portal在线帮助中的STATUS代码表定位故障(如16#01F4= 目标主机拒绝连接)。
⚠️ 注意:
TCON只需执行一次。连接建立后保持活跃,直到调用TDISCON或CPU重启。
三、T_SEND异步发送全流程(关键步骤)
T_SEND 在使能信号上升沿触发发送请求,立即返回,不阻塞扫描周期。
-
声明T_SEND实例及背景DB
新建FB(如FB_Send_ASCII),在其背景DB中声明:tSendInst : T_SEND; SendBuffer : ARRAY[0..255] OF BYTE; SendLen : UINT := 0; -
构造待发送数据(以ASCII字符串为例)
将字符串逐字符写入SendBuffer:SendBuffer[0] := 16#48; // 'H' SendBuffer[1] := 16#65; // 'e' SendBuffer[2] := 16#6C; // 'l' SendBuffer[3] := 16#6C; // 'l' SendBuffer[4] := 16#6F; // 'o' SendLen := 5; -
调用T_SEND
在FB的主体逻辑中编写:tSendInst( ID := ConnID, DATA := ADR(SendBuffer), LEN := SendLen, DONE => bSendDone, ERROR => bSendError, STATUS => wSendStatus ); -
处理发送结果
- 当
bSendDone = TRUE:表示数据已成功提交至TCP协议栈(不保证对方收到); - 当
bSendError = TRUE:检查wSendStatus:16#80A2= 连接已断开;16#80A3= 发送缓冲区满(需降低发送频率或增大缓冲区);
- 重发策略:若失败,清零
bSendDone和bSendError后,在下一扫描周期重新触发(即再次调用T_SEND,无需重连)。
- 当
四、T_RECV异步接收全流程(防丢包设计)
T_RECV 持续轮询接收缓冲区,每次仅提取当前已到达的全部字节,不等待完整报文。
-
声明T_RECV实例及背景DB
在FB(如FB_Recv_ASCII)背景DB中声明:tRecvInst : T_RECV; RecvBuffer : ARRAY[0..255] OF BYTE; RecvLen : UINT := 0; BytesReceived : UINT := 0; -
调用T_RECV
tRecvInst( ID := ConnID, DATA := ADR(RecvBuffer), MAX_LEN := SIZEOF(RecvBuffer), DONE => bRecvDone, ERROR => bRecvError, STATUS => wRecvStatus, LEN => BytesReceived ); -
解析接收数据(关键!)
T_RECV不提供报文边界识别。必须自行约定帧格式。推荐使用定长头+变长体:- 前2字节为
LEN(高位在前,大端序),表示后续有效数据长度; - 例如收到
00 05 48 65 6C 6C 6F→LEN=5,有效数据为48 65 6C 6C 6F("Hello")。
解析逻辑:
IF bRecvDone AND (BytesReceived >= 2) THEN // 提取LEN字段(大端) nExpectedLen := WORD_TO_UINT(RecvBuffer[0] * 256 + RecvBuffer[1]); // 判断是否收齐整帧 IF BytesReceived >= (2 + nExpectedLen) THEN // 复制有效数据到应用区 FOR i := 0 TO nExpectedLen-1 DO AppData[i] := RecvBuffer[2 + i]; END_FOR; // 更新已处理字节数,为下次接收腾出空间 MoveBlock( SRC_ADDR := ADR(RecvBuffer[2 + nExpectedLen]), DST_ADDR := ADR(RecvBuffer[0]), SIZE := BytesReceived - (2 + nExpectedLen) ); BytesReceived := BytesReceived - (2 + nExpectedLen); END_IF; END_IF; - 前2字节为
-
错误应对
bRecvError = TRUE且wRecvStatus = 16#80A2:连接中断,应停止调用T_RECV并尝试重连;BytesReceived = 0:无新数据,属正常现象,无需处理。
五、双工通信协调策略(避免资源冲突)
同一连接ID上,T_SEND 与 T_RECV 可同时运行,但需规避以下风险:
| 风险类型 | 表现 | 解决方案 |
|---|---|---|
| 发送抢占接收 | T_SEND 正在提交大数据包时,T_RECV 被调用导致内部缓冲区竞争 |
在T_SEND的BUSY输出为TRUE期间,跳过本次T_RECV调用(T_SEND.BUSY在数据提交完成前保持TRUE) |
| 接收缓冲区溢出 | T_RECV未及时读取,新数据覆盖旧数据 |
设置MAX_LEN ≤ 接收缓冲区大小;在bRecvDone为TRUE后立即处理数据,不延迟至下周期 |
| 连接状态不同步 | T_SEND发现连接断开,但T_RECV仍在调用 |
所有通信函数块共用同一ConnID,并在任一模块检测到STATUS=16#80A2时,统一触发重连流程 |
示例协调逻辑(在主程序OB1中):
// 全局连接状态
bConnOK := (MyTCON.DONE AND NOT MyTCON.ERROR) OR (tSendInst.BUSY OR tRecvInst.BUSY);
IF NOT bConnOK THEN
// 断连处理:复位所有函数块使能位,延时1s后重新TCON
tSendInst.EN := FALSE;
tRecvInst.EN := FALSE;
MyTCON.EN := FALSE;
IF TON_Restart.Q THEN
MyTCON.EN := TRUE;
END_IF;
ELSE
// 正常通信:仅当非BUSY时调用T_RECV
IF NOT tSendInst.BUSY THEN
tRecvInst.EN := TRUE;
ELSE
tRecvInst.EN := FALSE;
END_IF;
tSendInst.EN := bSendTrigger; // 由应用逻辑控制
END_IF;
六、调试与诊断技巧
-
在线监控必看变量
TCON.STATUS:连接阶段问题定位;T_SEND.STATUS/T_RECV.STATUS:实时查错(TIA Portal中右键变量→“转到声明”可查看状态码文档);T_SEND.LEN输入值 vsT_SEND.DONE后实际发出字节数(若小于输入值,说明被流控截断)。
-
Wireshark抓包验证
- 过滤规则:
ip.addr == 192.168.0.100 && tcp.port == 5000; - 关键观察点:
- SYN → SYN-ACK → ACK(建连);
- TCP Payload长度是否与
T_SEND.LEN一致; - 是否出现
TCP Retransmission(表明网络丢包或对方处理慢)。
- 过滤规则:
-
资源泄漏自检
- 若多次重连后通信失败,检查:
TCON.ID是否重复使用(必须每次新建连接时递增ID);T_SEND/T_RECV的背景DB是否被其他逻辑意外覆写。
- 若多次重连后通信失败,检查:
七、性能优化清单(实测有效)
- ✅ 将
SendBuffer和RecvBuffer声明在全局DB中,避免FC/FB局部变量频繁分配; - ✅
T_SEND.LEN设置为固定值(如256),避免每次计算长度带来的周期抖动; - ✅ 使用
MOVE指令替代循环赋值填充SendBuffer(如MOVE(ADR('Hello'), ADR(SendBuffer), 5)); - ✅ 对高频小数据(如每100ms发1字节),改用
T_CONFIG配置UDP连接,降低TCP握手开销; - ✅ 在S7-1500中,启用“优化块访问”并勾选“异步执行”,使
T_SEND/T_RECV在后台线程运行,彻底脱离OB1周期限制。
八、典型错误代码对照表
| 现象 | 错误代码(STATUS) | 根本原因 | 修正动作 |
|---|---|---|---|
| 无法建连 | 16#01F4 |
目标IP不可达或端口未监听 | 用ping和telnet 192.168.0.100 5000验证网络通路 |
| 发送失败 | 16#80A3 |
TCP发送窗口满 | 降低发送频率,或增加T_SEND调用间隔至≥50ms |
| 接收截断 | BytesReceived < LEN字段值 |
报文未一次性到达 | 在T_RECV后添加重试逻辑:若BytesReceived < 2,10ms后再次调用 |
| 连接闪断 | 16#80A2 频繁出现 |
网络不稳定或对方主动关闭 | 在TCON后添加心跳机制:每30秒发送1字节保活包 |
T_SEND 与 T_RECV 的本质是将TCP协议栈能力暴露为ST可调度的异步服务。掌握其触发-响应-状态闭环逻辑,即可在不引入复杂状态机的前提下,构建稳定工业级通信链路。

暂无评论,快来抢沙发吧!