4、S7通讯(下):使用TSEND_C/TRCV_C指令实现数据收发

好,咱们接着上回聊。上节课我们把S7通讯的底层原理和连接机制讲清楚了,今天直接上干货——怎么用TSEND_C和TRCV_C这两个指令,把两台S7-1200的数据真正跑起来。

说实话,我刚接触这两个指令时也犯过迷糊。TSEND_C和TRCV_C看起来比老版的TCON、TSEND、TDISCON要复杂,但用顺手之后你会发现,它其实把连接管理给封装好了,反而更省心。

4.1 TSEND_C指令详解

TSEND_C,全称是"带连接管理的发送指令"。你想想看,以前我们要先建连接、再发数据、最后还得手动断开,三步走。现在呢?一个指令全搞定。

它的工作逻辑是这样的:

  • REQ上升沿触发:一旦检测到上升沿,就开始干活
  • 自动建立连接:如果连接还没建立,它会自动帮你建
  • 发送数据:把指定地址区的数据发出去
  • 发送完保持连接:数据发完了,连接还留着,方便下次再用

我在项目中遇到过一个问题:有同事用TSEND_C时,每次发送完都把连接断掉,结果下一轮发送又要重新建连,效率低得吓人。其实没必要,保持连接开着就行,除非你确定很长时间不再通讯。

关键参数说明:

参数数据类型说明
REQBOOL发送请求,上升沿触发
IDCONN_ANY连接ID,必须与配置的连接号一致
DATAVARIANT要发送的数据区,可以是数组、结构体
DONEBOOL发送完成标志,一个周期的高电平
BUSYBOOL正在发送中,为1时别发新请求
ERRORBOOL错误标志
STATUSWORD状态码,出错了就看它

4.2 TRCV_C指令详解

TRCV_C是接收端,和TSEND_C是天生一对。它的逻辑也类似:

  • EN_R使能接收:只要这个脚为1,就一直监听
  • 自动接收:有数据来了自动收,不需要你手动触发
  • 数据到达通知:收完了,NDR会闪一下

嗯,这里要注意:TRCV_C的EN_R脚不能随便乱动。我见过有人用脉冲去触发EN_R,结果数据收不全。正确的做法是:上电后就把EN_R置1,让它一直处于监听状态。

我的小技巧:在OB1里调用TRCV_C时,把EN_R接一个始终为1的M点或者直接接"TRUE"。这样最省心,数据不会漏。

4.3 实战:两台S7-1200交换数据

光说不练假把式。咱们直接上手一个实际案例:两台S7-1200通过以太网交换数据。一台做主站(主动发),一台做从站(被动收)。

4.3.1 硬件组态

两台1200用网线直连,或者通过交换机连都行。IP地址要配好:

  • PLC_1(主站):192.168.0.10
  • PLC_2(从站):192.168.0.20

子网掩码统一用255.255.255.0。这个别搞错,我见过有人把子网掩码写成255.255.0.0,结果两台设备死活ping不通。

3.2 连接配置

在PLC_1这边,需要新建一个S7连接。操作路径:

  1. 打开设备组态,双击"网络视图"
  2. 选中PLC_1的网口,拖出一条线连到PLC_2的网口
  3. 在弹出的对话框里选择"S7连接"
  4. 连接属性里,本地ID填一个,比如"W#16#100"

说白了,这个ID就是TSEND_C和TRCV_C里要填的那个ID参数,必须一致。

4.3.3 主站程序(PLC_1)

我习惯在OB1里调用TSEND_C,用一个定时器循环触发发送:

// 网络:"MySendDB"
// TSEND_C 指令调用
// REQ:M0.0(由定时器产生1秒脉冲)
// ID:W#16#100
// DATA:P#DB1.DBX0.0 BYTE 10
// 发送DB1中的前10个字节

这里有个坑:DATA参数如果用P#指针写法,一定要确保DB块是优化的块。如果是标准DB,地址可能会偏移。我建议直接用符号寻址,比如"DataBlock".SendArray,这样最稳妥。

4.3.4 从站程序(PLC_2)

从站这边用TRCV_C接收:

// 网络:"MyReceiveDB"
// TRCV_C 指令调用
// EN_R:TRUE(一直使能)
// ID:W#16#100
// DATA:P#DB2.DBX0.0 BYTE 10
// 接收到的数据存入DB2的前10个字节

注意:接收数据区的大小必须大于等于发送数据区的大小。如果你发10个字节,接收区至少也得10个字节。少了会报错,多了没事,只收前10个。

4.4 数据校验与状态监控

程序写完了,怎么知道数据有没有传对?我一般会看这几个地方:

  • DONE/NDR标志:发送完成或接收完成时,这两个位会闪一下
  • STATUS状态码:正常是16#0000,出错了查手册
  • 数据对比:在监控表里同时看发送区和接收区的值

我曾经遇到一个怪问题:数据能发出去,但接收端收到的全是0。查了半天,发现是接收区的DB块没有取消"优化的块访问"。取消掉之后,一切正常。所以啊,做S7通讯时,DB块最好取消优化,地址固定下来,不容易出幺蛾子。

4.5 知识体系总览

下面这张图把今天讲的核心逻辑串起来了,你看一眼就能明白整个数据流向:

TSEND_C / TRCV_C 数据交换流程 PLC_1(主站) 发送数据区 DB1.DBB0~9 TSEND_C ID: W#16#100 以太网(S7连接) PLC_2(从站) TRCV_C ID: W#16#100 接收数据区 DB2.DBB0~9 状态监控:DONE / BUSY / ERROR / STATUS 发送完成 → 接收通知(NDR) 状态监控:EN_R / NDR / ERROR / STATUS 一直使能,等待数据到达

从图上可以看得很清楚:PLC_1的发送数据区通过TSEND_C指令,经过以太网S7连接,传到PLC_2的TRCV_C指令,最终存入接收数据区。两边通过相同的连接ID(W#16#100)来匹配。

4.6 常见问题与避坑

最后,我把自己踩过的坑总结一下,你遇到了直接对照着查:

避坑指南:

  • 连接ID不一致:TSEND_C和TRCV_C里的ID必须和组态里配的一样,少一位都不行
  • 数据区大小不匹配:接收区不能小于发送区,否则数据截断或报错
  • DB块优化问题:做S7通讯时,建议取消DB块的优化访问,地址更可控
  • EN_R没一直使能:TRCV_C的EN_R要常置1,别用脉冲触发
  • REQ触发太频繁:发送请求间隔不要太短,给接收端留处理时间

好了,今天的内容就到这儿。TSEND_C和TRCV_C这对组合,说白了就是S7通讯的"黄金搭档"。你只要把连接配好、数据区定好、触发逻辑写对,剩下的交给PLC自己处理就行。

个人建议:刚开始做实验时,先发一个字节试试水。通了之后再慢慢增加数据量。这样排查问题快,不至于一上来就被一堆数据搞晕。


公众号:蓝海资料掘金营,微信deep3321