贵州建站互联网科技有限公司舞钢市城市建设局网站
贵州建站互联网科技有限公司,舞钢市城市建设局网站,给网站做广告,网站网页设计教程1. 初识AG_SEND/AG_RECV#xff1a;它到底是什么#xff0c;和TSEND有啥不同#xff1f;
很多刚开始接触西门子S7-300/400系列PLC#xff0c;特别是需要进行跨网络、跨站点数据交换的朋友#xff0c;都会在博途#xff08;TIA Portal#xff09;或者经典的STEP 7里遇到一…1. 初识AG_SEND/AG_RECV它到底是什么和TSEND有啥不同很多刚开始接触西门子S7-300/400系列PLC特别是需要进行跨网络、跨站点数据交换的朋友都会在博途TIA Portal或者经典的STEP 7里遇到一对“兄弟”功能块AG_SEND和AG_RECV。我第一次用的时候也犯迷糊这不就是发送和接收数据吗和TSEND、TRCV有啥区别直接用TSEND不香吗结果一用就踩坑了。这里我必须先给你划个重点AG_SEND/AG_RECV和TSEND/TRCV是两套完全不同的通讯机制应用场景有硬性区别绝对不能混为一谈。简单来说TSEND/TRCV是“软”通讯主要用在S7-1200/1500这些新型PLC上或者S7-300/400在同一局域网同网段内进行开放式TCP/IP通讯它更依赖CPU自身的处理能力。而AG_SEND/AG_RECV是“硬”通讯它的核心是CP通讯处理器。当你PLC上插了CP343-1、CP443-1这类通讯模块时AG系列指令就是用来指挥这个“专职通讯员”干活的。你可以把CPU理解成公司老板CP模块就是老板手下的业务专员。老板自己也能接打电话处理业务类似TSEND但效率不高事务一多就忙不过来。而AG_SEND/AG_RECV就是老板直接给业务专员CP模块下指令“小张把这批数据发到上海分公司去。” 具体的打包、寻址、发送、接收确认这些累活全由CP模块这个硬件独立完成不占用CPU的扫描周期。所以它的优势非常明显通讯性能稳定、不干扰主程序运行、适合跨网段甚至跨广域网的稳定数据传输。如果你做的项目是工厂总部与远程分站、或者与第三方非西门子设备比如上位机、视觉系统进行稳定TCP/IP通讯AG_SEND/AG_RECV往往是更可靠的选择。那么AG_SEND、AG_LSEND、AG_SSEND这一堆“SEND”兄弟还有AG_RECV、AG_LRECV、AG_SRECV这些“RECV”姐妹又是什么关系呢别急它们其实是一个家族的核心功能一样只是“能力”和“特长”不同。AG_SEND是基础款发送数据长度有限制AG_LSEND是“加长版”专门发送大数据包AG_SSEND是“加急版”发送效率更高。接收端也是类似。我们这篇文章就从最常用、也最容易出错的AG_SEND和AG_RECV说起把从硬件组态、编程配置到数据处理的完整链条以及我踩过的那些坑给你掰开揉碎了讲清楚。2. 硬件组态与连接配置万丈高楼的地基在用AG_SEND/AG_RECV之前硬件组态这一步绝对不能出错这是所有通讯的基础。很多朋友程序写得没问题但就是不通八成问题出在这儿。我以最经典的S7-300系列PLC搭配CP343-1通讯模块为例给你捋一遍关键步骤。首先在STEP 7或博途的硬件配置视图里正确插槽上添加你的CP模块。添加完成后双击模块进入属性设置这才是重头戏。你需要找到“以太网地址”分配给CP模块设置一个固定的IP地址、子网掩码和网关。这里有个小经验如果通讯双方不在同一个子网网关一定要填对否则数据包发不出去我早期就因为这个查了半天线。然后关键来了你需要创建一个新的连接。在“连接”选项卡里点击新建选择连接类型为“TCP连接”或“ISO-on-TCP连接”。TCP是标准协议兼容性好ISO-on-TCP是西门子优化的适合大数据量连续传输稳定性更高根据你的第三方设备支持情况来选。创建连接时会需要你填写“伙伴”的地址也就是你要通讯的那台设备另一台PLC、电脑服务器等的IP地址和端口号。端口号建议双方约定一个固定的比如2000。这里特别注意一个参数“ID”和“LADDR”。这两个参数是你后面编程时AG_SEND和AG_RECV功能块上必须填写的“接头暗号”。ID是这个连接在连接列表中的编号是一个十进制数比如1。LADDR是本地地址它指的是CP模块的硬件地址通常是一个十六进制的数比如W#16#100这个值一定要在模块的属性里看清楚并记下来。我习惯在硬件组态完成后把这两个值截图保存或者写在程序的注释里编程时直接复制粘贴避免手输错误。注意在S7-300/400中AG系列指令的LADDR参数通常填的是CP模块的“硬件标识符”Hardware Identifier这个值在模块属性-“地址”选项卡里可以看到它是一个像256、272这样的十进制数有时也需要转换成十六进制格式填入。务必以在线模块属性中查到的为准。配置完伙伴参数后还有一点容易忽略数据收发的工作方式。对于发送方通常选择“主动连接建立”对于接收方选择“被动连接建立”。当然也可以都设为主动但需要确保连接时机。组态完成后记得编译保存并将硬件配置下载到PLC中。只有这一步地基打牢了上面的程序大楼才能盖得稳。3. AG_SEND发送功能块详解与实战编程硬件组态好了我们开始写发送程序。在OB1主循环组织块或其他周期性调用的块里调用AG_SEND功能块。它的管脚看起来不少但常用的就那几个我们一个一个来攻破。EN/ENO这个不用多说使能端通电能流就运行。ACT这是发送的“触发开关”。它需要的是一个上升沿信号这一点至关重要。你不能用一个常“1”的信号挂在ACT上那样每个扫描周期都会试图发送会导致通讯堵塞或错误。正确的做法是用一个按钮的上升沿、某个条件首次满足时的脉冲、或者时钟存储器位产生的脉冲来触发。我常用的一个土方法是在程序里做一个“发送请求”位当需要发送数据时把这个位置1然后用这个位的上升沿去触发ACT发送完成后立刻在程序里把这个请求位复位。ID填你在硬件连接中配置的那个连接ID十进制格式。LADDR填CP模块的本地地址十六进制格式比如W#16#100。SEND发送数据区的起始指针。这是核心参数它告诉功能块从内存的哪个地方开始取数据。通常我们指向一个数据块DB的某个区域。格式是类似P#DB10.DBX0.0 BYTE 100这样的ANY指针。它表示从DB10的0.0字节开始最多可以发送100个字节。注意这里定义的是“缓冲区”的最大范围实际发送多少字节由LEN决定。LEN本次实际要发送的字节长度。这个长度必须小于等于SEND指针定义的区域长度。比如SEND指针定义了100字节你LEN可以填58就只发送前58个字节。DONE输出管脚。发送成功完成后这个位会变成“1”但只持续一个扫描周期。所以你不能用它来直接点亮一个常亮的指示灯否则灯只会闪一下。通常我们用DONE信号来复位“发送请求”位或者置位一个“发送成功”的标志位这个标志位需要自己用程序保持住。ERROR/STATUS错误和状态输出。当发送过程中出现问题时ERROR会置1同时STATUS会输出一个错误代码。编程时一定要习惯性地用ERROR信号去做报警提示并把STATUS代码记录下来查错的时候非常有用。下面我举个实际的编程例子。假设我要把DB10中从0字节开始的58个字节数据通过ID1的连接发送出去。CALL AG_SEND // 调用功能块 ACT :#Send_Request_Pulse // 发送请求脉冲上升沿 ID :1 // 连接ID LADDR :W#16#100 // CP模块地址 SEND :P#DB10.DBX0.0 BYTE 100 // 发送缓冲区指针 LEN :58 // 发送58字节 DONE :#Send_Done_M // 发送完成标志一个周期 ERROR :#Send_Error STATUS :#Send_Status_Word程序里#Send_Request_Pulse是我用其他逻辑产生的一个单脉冲。当#Send_Done_M为1时我就知道数据发出去了。这里有个大坑等你跳字节长度限制。根据西门子官方手册对于S7-400 PLC标准AG_SEND最多只能发送240个字节。如果你的数据包超过240字节还用AG_SEND那对不起永远发不出去ERROR灯常亮。这时候就必须请出它的兄弟——AG_LSEND长发送。4. AG_LSEND发送大数据与间隔发送策略当你需要发送的数据超过240字节时就必须使用AG_LSEND。它的管脚和AG_SEND几乎一模一样用法也类似。但是这里我踩过一个实实在在的坑而且网上资料很少提。我用的是CP443-1模块当我用AG_LSEND发送数据时如果LEN长度设置小于241字节比如我设200字节功能块就是不动作DONE永远不亮也不报错就像没调用一样。折腾了好久后来和西门子技术支持交流怀疑是某些固件版本CP模块的“特性”。最终的解决方案是使用AG_LSEND时无论实际数据多少LEN参数强制设置为至少241字节。即使你只想发100字节也把LEN设为241功能块会自动处理只发送有效数据部分。这个经验让我少走了很多弯路。发送大数据包时另一个必须考虑的问题是发送间隔。CP模块再厉害处理大数据也需要时间。如果你在前一个数据包还没发送完成DONE信号没来时就立刻触发下一个ACT上升沿会导致什么后果很可能会造成数据包重发、丢包甚至通讯连接中断。特别是周期性地发送上千字节的大数据包必须做好流量控制。我的实战经验是对于2000字节左右的数据包建议两次发送的间隔至少保持在4秒以上。这不是一个固定值和网络质量、CP模块性能有关但4秒是一个比较安全的经验值。如何实现间隔呢有几种方法利用DONE信号自锁用DONE信号结合定时器确保一次发送完成后至少等待几秒才允许下一次发送触发。使用时钟脉冲如果数据是周期性发送的可以直接使用OB35循环中断组织块并在OB35里用计数器进行分频。比如OB35每100ms执行一次我计数到40次即4秒才触发一次发送。状态机控制如果发送逻辑复杂有多个不同的数据包需要发送最好设计一个简单的状态机确保同一时间只有一个发送任务在进行。例如用一个简单的定时器实现间隔// 假设 #Send_Data_Ready 是数据准备好的标志 // #Send_Enable_Timer 是一个定时器预设值4秒 IF #Send_Data_Ready AND NOT #Send_Busy AND #Send_Enable_Timer.DN THEN #Send_Request_Pulse : TRUE; // 产生脉冲 #Send_Busy : TRUE; // 置位“发送忙” RESET #Send_Enable_Timer; // 复位定时器 END_IF; IF #Send_Done_M THEN // 发送完成 #Send_Busy : FALSE; #Send_Data_Ready : FALSE; // 清除准备标志 START #Send_Enable_Timer; // 启动4秒间隔定时器 END_IF;这样就能保证即使有连续发送请求也会被强制间隔开大大提升了通讯的稳定性。5. AG_RECV接收功能块与数据填充“天坑”说完发送我们来看接收端。AG_RECV功能块看起来比AG_SEND简单因为它没有ACT管脚这意味着什么意味着只要EN端使能这个块在每个PLC扫描周期都会尝试去接收数据。所以你通常需要一直使能它让它像哨兵一样持续监听网络端口。它的关键管脚EN/ENO常通即可。ID/LADDR和发送端对应填写接收方这边硬件组态里定义的连接ID和CP模块地址。RECV接收数据区的指针。格式同SEND比如P#DB20.DBX0.0 BYTE 200。这里定义了一个200字节的“水池”用来存放收到的数据。NDR新数据就绪信号。这是最重要的输出信号当有新数据包成功接收到时NDR会置1同样只持续一个扫描周期。你必须捕捉到这个脉冲。LEN当NDR为1时LEN会输出本次实际接收到的数据字节长度。ERROR/STATUS同发送端。编程模式通常是这样CALL AG_RECV EN :TRUE ID :1 LADDR :W#16#100 RECV :P#DB20.DBX0.0 BYTE 200 // 接收缓冲区 NDR :#New_Data_Received_M // 新数据到达脉冲 LEN :#Received_Data_Length ERROR :#Receive_Error STATUS :#Receive_Status_Word当你看到#New_Data_Received_M脉冲来了就知道数据到了长度在#Received_Data_Length里数据已经躺在DB20从0字节开始的位置了。但是最诡异、最坑人的问题来了——数据填充问题这个问题官方手册语焉不详我是在项目现场调试时被坑得焦头烂额才发现的。假设你的RECV指针定义了一个200字节的区域P#DB20.DBX0.0 BYTE 200。现在发送方发来了60个字节的数据。接收没问题NDR亮LEN显示60DB20的前60个字节是正确数据。那么DB20里从第61到第200字节是什么呢是随机数是0不它们会保持上一次接收数据后残留的值这还不是最糟的。更极端的情况如果发送方只发来了1个字节的数据。AG_RECV会怎么处理它会把这1个字节的数据填充到你定义的整个200字节的接收区域里也就是说DB20.DBB0, DBB1, DBB2 ... 一直到DBB199全部变成了这同一个字节的值同理如果发送2个字节它会用这两个字节不断重复直到填满200字节。这个特性简直堪称“天坑”。如果你接收后直接把这个DB块的数据用于计算或显示后果不堪设想。6. 数据处理与避坑指南如何优雅地应对接收数据面对AG_RECV这个“自动填充”的坑我们该怎么办这里我分享两种经过实战检验的解决方案你可以根据项目情况选择。方案一接收后立即转移并清空这是最稳妥、最安全的方法。思路是不把接收缓冲区DB直接当作用户数据区而是作为一个临时的“码头”。数据到了“码头”立刻用卡车程序把它运到安全的“仓库”另一个DB或存储区同时把“码头”清理干净等待下一批货物。 具体步骤定义一个专用的接收缓冲区DB比如DB20大小足够如200字节。定义一个用户数据区DB比如DB21用于存放处理后的有效数据。编程当AG_RECV的NDR信号为1时触发一个移动指令。使用SFC20BLKMOV或者直接使用循环将DB20中从0字节开始、长度为LEN实际接收长度的数据复制到DB21的目标位置。关键一步复制完成后立即调用一个填充指令如SFC21FILL将整个DB20缓冲区全部填为0或某个初始值。这样无论发送方发来什么长度的数据你DB21里得到的永远是正确长度的有效数据且没有残留垃圾。这个方法编程稍复杂但一劳永逸适用于所有场景。方案二保证收发数据长度严格一致如果你能完全控制通讯双方这是一个更简洁的方法。思路是发送方每次发送固定长度的数据包接收方的RECV缓冲区也正好定义为这个长度。比如双方约定每次通讯都是58字节。那么发送方LEN固定58接收方RECV指针也固定为BYTE 58。这样发送方发来的数据正好填满接收缓冲区不存在填充或残留问题。这种方法简单高效但缺乏灵活性一旦协议变更就需要修改双方程序。在实际项目中我强烈推荐方案一。因为它更健壮能适应数据长度变化也便于调试和问题追踪。你可以在数据转移后把实际接收长度LEN值也存下来这样你就知道这次收了多少有效数据。最后关于AG_RECV在S7-400上的一个传闻官方帮助文档确实提到过在S7-400的TCP连接上使用AG_RECV可能存在限制或不可用。但很奇怪我在多个S7-400CP443-1的项目上使用都正常。不过为了规避未知风险如果你的PLC是S7-400并且有条件的话可以优先考虑使用AG_LRECV长接收或者研究一下新型CPU的TSEND/TRCV是否满足需求。毕竟用经过充分验证的、没有官方警告的方案心里更踏实。通讯调试本身就是一个不断踩坑、填坑的过程。AG_SEND/AG_RECV这套指令功能强大一旦掌握能解决很多复杂的跨网络通讯问题。关键是把组态做扎实把发送间隔安排好把接收数据的“填充坑”用稳妥的方案绕过去。多利用STATUS代码查错多在线监控数据流慢慢地你就会发现这些看似复杂的指令其实都是纸老虎。