电工学习网

 找回密码
 立即注册
查看: 875|回复: 1

实用干货:西门子PLC的TCPIP通信程序的一种算法及框架

[复制链接]
发表于 2019-9-30 12:26:26 | 显示全部楼层 |阅读模式
本文不涉及TCP/IP原理,也不涉及硬件知识,只是软件层面的一种实现TCP/IP通信的灵活的程序架构。
       该程序架构描述基于西门子S7系列plc,所有的数据描述以及结构定义都为西门子S7系列PLC。作为一种灵活的TCP/IP通信架构,该思路也可以用于其他品牌PLC 类似程序架构的参考。
       前言:
       PLC作为现场设备控制器,其与上位系统(高层MES系统,下文统称上位系统)数据交互通常采用TCP/IP方式。
       TCP/IP程序一般包括三个部分(一)看门狗程序(二)数据接收程序(三)数据发送程序。
       看门狗程序一般用于侦听PLC与上位系统之间的数据链路是否保持畅通,若握手应答机制没有及时响应,一般情况下都必须Report通信故障,同时也意味着PLC与上位系统之间的数据交互也存在问题。
       数据接收程序主要是依据事先约定的通信数据接口,将端口侦听到的数据解析并保存在PLC数据区域,并随着系统运行的推进及时更新数据的状态。关于数据接收大程序搭建,将在后续文章中描述。
       数据发送程序在PLC侧主要是依据设备运行状态,将数据交互接口中规定的数据及时发送到上位系统。在此,就需要涉及到如下几个问题
1.        数据在什么时候发送,比如立体仓库的堆垛机在完成入库任务后需要给WMS系统发送入库完成。但注意的是,数据发送的时机在一个系统中不是唯一的,比如立体仓库中的堆垛机有入库数据,搬运数据以及设备运行数据等
2.        数据在什么位置发送,比如物流系统中物料的跟踪,若某个物料跟踪失败则必须告知上位系统跟踪丢失的物料信息以及物料是在哪一台设备上丢失的
3.        发送什么数据,这个一般都是事先约定的,并且一个行业的信息基本都是可以约定成一个通用版本。
       同时,随着质量以及效率的要求,一般企业还要求将程序做成模块化,标准化。
本文主要描述一个数据发送的程序架构,通过该架构读者就可以将上述的几个问题得到解答,同时也可以依据该架构做成一个公司自身的标准程序。
术语
Event:一条需要发送的信息称之为Event,即一个Event就代表着一条发送数据。Event包括但不限于EventID、EventValue以及EventProperty。
FIFO:先进先出堆栈,主要描述待发送数据的堆栈区域。



(一)DB_Event事件数据块
       Event即代表一条需要发送的消息,在PLC中建立一个名字为DB_Event的数据块,该数据块中存储的就是一个PLC循环周期中需要发送的Event数据堆栈。
6370531245364954341590919.png

图1:DB_Event数据块示意图
       Entry_Used:当前数据堆栈中已经有的Event数量,通过事件写入函数FC_Write_Event更新其当前值。
       Entry_Present:当前数据堆栈中总共可用的Event数量,通过事件写入函数FC_Write_Event自动计算,其值为数组中的N。
       以上两个变量可以当成DB_Event的头文件,记录的是DB_Event中堆栈的当前状态。

除了上述两个变量DB_Event中将包含Event数组堆栈,一般的PLC程序的循环时间大约在30ms以内,在30ms以内能同时发生的Event的数量是有一定限制的,通过实际测试发现DB_Event中的包含20个数组完全能满足一个PLC循环的Event的上限。
       Entry[].Value:一个Event的信息的长度是事先约定好在接口文档中,该Value作为数据的一个指针一样,即通过该值可以在PLC数据区域搜索到这个Event需要的所有信息。
       Entry[].ID:一个ID代表着一类Event的信息,比如在立体仓库中会有入库、出库、盘移、异常转运、任务完成、任务中断以及请求状态等信息需要发送,那在程序结构中可以将这些信息分别用一个唯一的ID标记,如下表显示一样。
6370531242058134742057452.png
表1:Entry_ID说明示意图

       Entry[].Status:数据类型为一个32位数据的Word,该数据可以用于描述Event的一些其他属性信息。比如Event可能是不同技术要求的信息,有的Event是任务信息,有的Event可能是统计信息,而有的Event可能是操作事件信息……这些属性可以通过Word中不同的位来表示,也可以通过Word的值来表示Event的属性信息。

       DB_Event是发送程序架构的基础,设备执行过程中可以在任意一个节点通过调用FC_Write_Event函数,将Event内容写入DB_Event堆栈中。比如当堆垛机因为任何的设备故障或者人为原因导致的当前任务中断的情况下,FC_Write_Event都可以将8010写入Event堆栈中。
       设备在工艺执行过程中可能会有多次写入Event的情况,等待工艺过程执行完成后,在工艺控制程序下面插入一个Event解析程序,用于解析本次循环周期中的Event事件。
6370531248522662392910062.png

图2:Event解析程序位置图示

       定义一个Event解析功能块:FB_Data_Mes,设备控制程序结束后,该功能块根据DB_Event中Entry_Used的值,循环将要发送的数据写到发送缓存区DB_Send_FIFO。
6370531253356923298372737.png

图3:事件解析功能块FB_Data_Mes算法图示
              FB_Data_Mes的功能主要包括(一)根据进入Event堆栈数量循环解析Event_ID并将发送数据写入发送缓存区DB_Send_FIFO(二)当数据全部得以解析或者数据错误,将Event堆栈数据清除。详细算法流程如图3所示。
       (二)DB_Send_FIFO发送缓存数据块
       如图3所示的算法,在FB_Data_Mes执行过程中根据解析到的Event_ID将调用不同的ID程序,然后将要发送的数据放置到发送缓存区,结合表1简单示意程序逻辑如下。
       IF #s_Entries_Used > 1 THEN
           FOR #t_Counter_Entry := 1 TO #s_Entries_Used DO
               IF #s_Entry[#s_Entries_Used].ID = 8001 THEN
                   FC_Infeed(#s_Entry[t_Counter_Entry].Value);//请求入库任务信息
               END_IF;
                                          ……                                            //其他信息
               IF #s_Entry[#s_Entries_Used].ID = 8020 THEN
                   FC_Req_Status_Info(#s_Entry[t_Counter_Entry].Value); //请求位置信息
               END_IF;
           END_FOR;
       END_IF;
       上述的程序中的FC_Infeed或者FC_Req_Status_Info都是按照接口约定,根据Entry[].Value搜索接口约定中需要的数据,然后将这些数据统一写进数据发送缓存区域DB_Send_FIFO。
       这意味着DB_Send_FIFO中保存着需要发送到上位系统的数据缓存,按照PLC的循环机制,每一个扫描周期最好只发送一条Mes(发送多条端口数据可能被覆盖),所以DB_Send_FIFO中保存着当前周期还没有发送完的数据。
       所以,为保证所有需要发送的数据都能完整且正确的发送到上位系统,DB_Send_FIFO被定义为如下图结构。
6370531256444420997306917.png

图4:DB_Send_FIFO结构示意图
       DB_Send_FIFO分为四个部分(一)堆栈的当前状态(二)堆栈设置(三)数据发送状态(四)数据缓存区域。

堆栈的当前状态说明:
       Empty:若为True则表示当前缓存区是没有数据等待发送,否则意味着有数据等待着发送到端口缓存区。
       PreFull与Full:若为True则意味着待发送的数据缓存区即将被写满或已经被写满,这很大部分都可能是因为PLC与上位系统的连接中断造成的。
       Record_Length_Long:若为True则表示当前发送数据长度超出接口文档约定的数据长度。
       Wrong_Record_Length:若为True则表示当前发送数据长度不是接口文档约定的数据长度。
       Wrong_Prefull_Value: 若为True则表示设置的缓存区域数组数量错误,没有小于最大值。
       Block_Move_Fault:若为True则表示数据发送过程受阻,数据可能没有发送成功。

堆栈的设置说明:
       Prefull_Num_Of_Record:数据缓存区即将填满的警告,必须小于数组的最大值。
       Record_Data_Length:发送数据的最大长度,若所有数据长度一样则为发送数据的长度。

数据发送状态说明:
       Num_Record_Store:当前存储的需要发送的数据数量。
       Max_Num_Of_Record :数据缓存区域最大数组长度。
       Next_Record_Store:下一个需要保存的缓存数据的数组位置,小于等于最大数组长度。
       Next_Record_ Retrieve:下一个需要发送的缓存数据的数组位置,小于等于最大数组长度。

       Record[]:即发送数据的缓存数组,根据不同系统的性质(需要发送数据的量)确定整个数据缓存区域数组的最大长度,正常流程下一般有200个数组基本能满足大部分控制系统的数据发送量。

       FB_Data_Mes中解析后调用的ID程序就将搜索到的数据按照先进先出原则逐一写进DB_Send_FIFO的下一个数据保存区。
比如FC_Infeed按照接口定义的数据搜索完成后,通过FC_FIFO函数将其写进DB_Send_FIFO中合适的数组位置。

(三)FB_Data_Send数据发送功能块
FB_Data_Send为TCP/IP通信的数据发送程序,根据上文描述的内容,FB_Send_Data的功能就是将DB_Send_FIFO中缓存的数据发送到数据端口区。
FB_Data_Send的算法和FB_Data_Mes类似,都是根据DB_Send_FIFO中的当前状态,将要发送的数据发送到数据端口并更新DB_Send_FIFO的相关状态。
FB_Data_Mes在一个扫描周期中需要将DB_Event中的所有数据保存到DB_Send_FIFO的合适缓存位置,而FB_Data_Send在一个扫描周期中只发送DB_Send_FIFO中的一条数据。
6370531261257101248000370.png

图5:数据发送程序结构图示
(四)后记:使用说明
根据上述描述,FB_Data_Send、FB_Data_Mes、FC_Write_Event以及两个数据块能做成一个标准的程序块,当PLC与上位系统需要进行TCP/IP数据通信则只要完成以下几个步骤,那整个TCP/IP发送架构即能搭建完成。
1.        定义好通信数据接口,如表1一样将整个数据通信定义完全。
2.        根据每一类数据类型定义一个Event_ID号,这个ID号可以是数据接口中定义好的。
3.        根据Event_ID完成每一个ID函数的编写并在FB_Data_Mes中完成调用。
4.        在设备控制程序中需要发送消息的地方调用FC_Write_Event函数,写入不同的Event_ID即表示着要发送的数据类型。
当程序库完成后,若TCP/IP通信数据有增加也只要按照上述步骤即可完成程序的搭建。
整个架构的灵活之处在于,当需要在某个位置发送某类数据的时候,只要在相应位置处调用FC_Write_Event函数,那该类型数据的发送程序就完成且不会出现错误。
整个架构的好处在于便于公司将行业的数据发送形成一个完整的程序库,并且可以形成库文件说明,包括Event_ID等的说明。后续有新进工程师,只要按照库文件说明,即可以完成相关程序的编写以及对整个程序架构的理解。

建议:根据上文描述,当某个Event被写进DB_Event中后并不一定能在当前循环被FB_Data_Send发送到数据端口,所以建议TCP/IP的数据接口中的每一天数据都有个时间标志数据段,这样上位系统就可以根据收到的信息了解到该消息生成的时间以及被发送的时间。


回复

使用道具 举报

发表于 2019-10-6 22:42:40 | 显示全部楼层
路过,在想PLC对我们身边有哪些用处。

回复 支持 反对

使用道具 举报

|电工学习网 ( )

GMT+8, 2019-10-19 00:06

Powered by © 2011-2019 www.diangon.com 版权所有 免责声明 不良信息举报

技术驱动未来! 电工学习网—专业电工基础知识电工技术学习网站。

栏目导航: 工控家园 | 三菱plc | 西门子plc | 欧姆龙plc | plc视频教程

快速回复 返回顶部 返回列表