摘要: 本文介绍了如何通过梯形图读取V6.0版本400H的状态灯,并通过对之前读V4.5版本400H状态灯读取的SCL程序进行解析,介绍如何修改为V6.0版本的代码。
1 参考手册和梯形图编程
1.1 SFC 51读取系统状态列表或部分列表
通过系统功能 SFC 51“RDSYSST”(读取系统状态),可以读取CPU或者从站的系统状态列表或部分系统状态列表,参考下面手册:
SIMATIC 用于S7-300/400 系统和标准函数 的系统软件 卷1/2 参考手册
https://support.industry.siemens.com/cs/cn/zh/view/44240604
其中,可以使用SSL-ID = W#16#xy74读取CPU的LED状态
图1-1 SFC 51里相关的帮助
1.2 梯形图实现方法
在调用SFC 51时,为了便于分析读到的数据记录,需要在共享DB里声明一个结构体变量SSL_HEADER,再声明足够数量的结构体变量来保存LED状态数据,400H V6版本单个CPU有15个指示灯,冗余控制器有30组,所以案例中声明了30组。
图1-2 在DB块里的变量声明
推荐在扫描周期1秒以上OB调用SFC 51,例如:OB32。在调用 SFC 51 时,通过将值“常1”赋给输入参数REQ 来启动读取,通过赋给不同的状态列表SSL_ID实现不同的功能。在本文档中要读取CPU的所有LED状态,可设置参数SSL_ID=W#16#0074,梯形图的调用如下所示:
图1-3 SFC 51调用
程序执行后,读出的LED灯的状态会放在声明的数组里,在下图中读到了30组数据记录,前边是主CPU的15组,后边是备CPU的15组数据,如下所示:
图1-4 读到的状态灯数据记录
对读到的数据解释如下:
首先N.DR是读到的LED数量,本例中冗余状态灯读到了30组,如果单机运行模式,就只能读到15组。
读到的数据记录顺序和实际CPU上LED灯的顺序并不相同,需要参考手册来判断,每一个指示灯的数据分为3部分:
- 第一个数据是指示灯的代码LED_ID,它分为两部分,高地址部分为CPU特征,低地址为LED灯的组号。例如:图中第一组数据的LED_ID为W#16#F802,其中F8表示是左侧机架的CPU为MASTER,02代表指示灯的顺序号,从下图中查到是INTF灯的状态。
图1-5 LED指示灯的顺序 如果RACK 1为主CPU,那么第一组数据的LED_ID就为16#F9XX,关于F9的解释参考下面的说明:W#16#F9XX里,F为固定值1111,而9里的Bit 3=1表示主CPU,Bit 0-2为1,表示数据来自于RACK 1且为主CPU的数据。
图1-6 LED指示灯状态值的说明
- 第二个数据是该LED是否点亮
- 第三个数据LED_BLINK表示该LED是否闪烁 如果右侧CPU为主,那么第一组数据的ID会变化,前面数据的LED_ID以16#F9开头,下面是部分数据截图。
图1-7 RACK 1 CPU为主时数据记录 通常在画面上根据布尔量显示状态时,需要连接固定的DB地址,所以RACK 1为MASTER时,将数据记录的前后两组数据的进行交换,让RACK 0的数据总在最前面,下图中DB296的变量声明和DB295相同,只是最后多了三个整数,用于BLKMOV的返回值。
图1-8 数据处理第一部分 接下来,当RACK1为主CPU时,通过两次交叉拷贝到新的DB296,将两组数据重新排序,RACK0数据固定在前。
图1-9数据处理第二部分 在将数据按照先RACK0后RACK1排好序后,如果想把所有灯的LED 状态放到一个字里,可以将每一个LED_ON数据里的第1位移到事先声明的BOOL量里,如下所示:
图1-10 将LED_ON状态从BYTE转成BOOL量 同样的方法 ,将BLINK的状态也移到BOOL量里,就可以在WINCC上显示了。 注:经过测试,故障灯的顺序是:
- 1.INTF:内部错误
- 2.EXTF:外部错误
- 3.RUN:运行
- 4.STOP:停止
- 5.FORCE:强制
- 6.BUS1F:BUS1总线故障,指MPI/DP接口下挂从站有故障
- 7.BUS2F:BUS2总线故障,指DP接口下挂从站有故障
- 8.REDF:400H系统有冗余故障
- 9.MSTR:灯亮时该CPU为主站
- 10.RACK0:机架0
- 11.RACK1:机架1
- 12.IFM1F:上侧同步链路故障
- 13.IFM2F:下侧同步链路故障
- 14.MAINT:灯亮时CPU需要维护
- 15.BUS5F: BUS5总线故障,指成PN接口下挂从站有故障
1.3 故障代码分析
在调用SFC 51时,如果执行过程中报错,可以结合故障代码和手册来分析。
例如在下图中执行出错,返回值为“-32639”。
图1-11 读V6.0 400H 状态灯出错
在变量表里将返回值按16进制显示,得到结果为W#16#8081,在手册或者在线帮助 里,查到故障原因是DR提供的数据区太短,长度为104字节,而V6.0 400H需要120个字节。
图1-12 分析故障原因
2 SCL例程解析
前边介绍的梯形图读取400H LED灯状态,受到梯形图的功能限制,对数据的加工处理不大方便。在PCS 7项目里,还要考虑在CPU故障时报警等复杂功能,如果用SCL结构化编程语言,可以大提高编程效率并实现复杂的功能。关于SCL的基础,请参考下面文档:
《S7-SCL编程 》
https://support.industry.siemens.com/cs/cn/zh/view/109481384
接下来对官网的读取V4.5版本400H的SCL例子进行分析,解读它的编程思路和如何修改为适用V6.0版本。通过下面的链接,可以下载到4.5版本的状态灯读取指南和SCL源代码。
《如何读取冗余控制器状态灯》
https://support.industry.siemens.com/cs/cn/zh/view/90318924
关于SCL源文件导入项目,参考:
图2-1 导入SCL源文件
2.1 SCL功能块结构
PCS7系统中,使用SCL编辑器来开发在AS控制器中运行的各功能块,必须在格式和内容上遵循一定的标准。下图所示即为一个通用功能块的结构。
图2-2 SCL功能块结构
2.2 SCL功能块头和功能块属性
功能块头中包含了该功能块一些基本的操作信息(我们把它叫做功能块属性Block Attributes)。使用各种不同的功能块属性,我们可以完成各种不同的功能,这些属性将会在功能块的属性对话框中显示。下图所示为各参数实际在功能块中所表征的意义。
图2-3功能块属性
- FUNCTION_BLOCK:用户可以定义该功能块的块名(最多8个字符)。在编译SCL代码之前,用户需要手动在符号表中为该功能块分配符号名;
- TITLE:PCS7中将不使用该属性,仅仅会在功能块属性对话框中的注释中显示。通常将TITLE的属性设置的与FUNCTION_BLOCK属性一致;
- NAME:和FUNCTION_BLOCK属性设置相同。如果使用在线帮助系统,此属性和FAMILY属性将成为索引在线帮助文件的两个关键字;
- FAMILY:如果用户需要对各功能块进行分组管理,则需要设置此参数。
- AUTHOR:此属性用于设置功能块的作者名。
- KNOW_HOW_PROTECT:用于保护功能块。如果激活此功能,则相应功能块将不能更改。
为了能够将需要的变量自动编译到OS,在图2.1 增加了两个属性,其中S7_m_c是“控制和监视”功能,“S7_alarm_ui”是上传消息的属性,如果是PCS 7项目,要设置为1,如果是STEP 7 WINCC,设置为0。
2.3 变量声明
在功能块开始部分要进行变量声明,以配合代码部分的数据处理。
- 输入变量
有下列需求时,我们需要定义输入参数:
- 从不同的功能块获取参数时;
- 在CFC下需要对该功能块输入参数常量时;
- 在OS上操作该功能块的某个参数时;
- 在OS面板上以参数的形式显示某过程值;
- 需要生成功能块相关的报警信息(Message ID for Alarm Blocks);
在下图中的声明里,主要引脚功能如下 :
- EV_ID:是为实现报警消息上传用的,参数严格照下面定义。
- RUNUPCYC:CPU开始运行的报警抑制周期数
- SSL_ID: CPU的状态列表ID,为16#0074。
- REQ:SFC 51的触发信号。
图2-4 输入变量声明
在上图中,不仅声明了变量,还在大括号里声明了引脚的参数,用于定义该功能块与其他功能块之间或上位机PCS7 OS的接口,也可以通过定义它的系统属性来定制各种特性,常用参数属性见下表:
系统属性 | 相关性 | 注 释 | 类 型 | 默认值 |
---|---|---|---|---|
S7_sampletime | 时间相关 | 带有该属性的参数将会自动更新为当前循环OB的循环周期 | 功能块相关 | FALSE |
S7_dynamic | CFC | CFC测试模式下的动态显示 | 实例相关 | FALSE |
S7_edit | CFC | CFC中参数/信号分类 | 实例相关 | FALSE |
S7_link | CFC | CFC中是否能被连接 | 功能块相关 | TRUE |
S7_param | CFC | CFC中是否能被参数化 | 功能块相关 | TRUE |
S7_visible | CFC | CFC中是否可见 | 实例相关 | TRUE |
S7_qc | CFC, OCM | 参数是否拥有质量代码 | 功能块相关 | FALSE |
S7_m_c | OCM | 定义该参数是否用于OCM属性 | 功能块相关 | FALSE |
S7_shortcut | OCM | OS面板中显示的模拟量标签名(16个字符Max.) | 实例相关 | NULL |
S7_string_0 | OCM | 输入或输入输出变量参数为"0"时的指示文本(16个字符Max.) | 实例相关 | NULL |
S7_string_1 | OCM | 输入或输入输出变量参数为"1"时的指示文本(16个字符Max.) | 实例相关 | NULL |
S7_server | Server | 消息ID的服务器类型(alarm_archiv) | 功能块相关 | NULL |
S7_a_type | Message Server | 消息ID类型标识 | 功能块相关 | NULL |
表2-1 引脚参数列表
- 输出变量
有下列需求时,我们需要定义输入参数:
- 将相应参数传递给另一个功能块;
- 在OS上对某个参数进行监控;
- 在CFC测试模式下对某个参数进行监控; 输出部分声明如下:
图2-5 输出变量声明 主要的参数:
- LENTHDR:读到的数据记录长度
- N_DR:读到的数据记录个数。
- LED_IDX:读到的指示灯数据的ID,数量应该与CPU的指标灯数量相等。
- CPU_FAILURE: CPU单侧停机。
- CPU_FAULT:CPU 有故障,例如:内部故障,外部故障等等。 注:LED_ID1 ~ 26部分为调试用的,用于显示读到的指示灯的ID。V4.5版本400H为26组数据,如果是V6.0控制器,那么两个CPU共计30组数据。如果是V6.0 CPU,所以这里应改为30组数据。
- 静态变量(VAR)
与临时变量不同,静态变量会在该功能块前后两次调用过程中传递值(Retained),而且此变量类型在功能块中嵌套调用其他功能块FB时非常有用。如果在该功能块中需要调用其他FB块,则需要在该功能块的静态变量中声明被调用块的多重实例Multiple Instance。静态变量声明示例如下图所示。
图2-6:静态变量声明示例
2.4 代码部分
2.4.1 报警的抑制
- AS控制器从Stop状态到Run状态的过程中,CPU需要处理相关的初始化代码,建立与上位机的通讯连接等等。系统启动后及开始执行循环程序,如果在启动初期,系统各控制回路同时有很多的报警信息需要上传到OS,势必导致此时CPU的负荷偏大。因此,通常情况下,PCS7功能块中都会有报警抑制的代码部分。此代码在系统启动初期(或该功能块被调用的前几个循环中)抑制该回路的报警输出。 具体做法:定义一个INT型输入变量”RUNUPCYC”。使用此参数,用户可以定义报警抑制的循环周期个数,在程序循环过程中动态计算循环个数,定义的循环周期个数结束后使能报警输出。 功能块程序执行过程中判断当前调用该功能块的OB时,需要用到系统功能SFC6(RD_SINFO)。在功能块程序执行过程中调用该功能,它可以读出当前调用该功能块的OB信息(参数TOP_SI),以及上一次调用的启动OB信息(START_UP_SI)。这两个参数有他们固定的数据结构(如下表所示),用户需要在程序的临时变量中定义两个临时变量结构体来存储信息。
图2-7:报警抑制相关变量声明
RD_SINFO: SFC 6读取 OB 启动信息,读出是否被OB100调用,如果检测到sbRESTART值为TRUE,那么肯定是被OB100调用,将sbRESTART复位。
图2-8:判断是否OB100调用
图2-9 :对CPU前3次扫描周期结束后ALARM_OUT置位
2.4.2 读取故障灯状态
如果一个功能块需要具有OCM属性,相应的参数能自动上传到OS(监视及控制),则需要设置该功能块及相关参数的监控属性(S7_m_c,仅对FB有效)。本例中需要将灯的状态上传到WINCC并显示,相应参数的OCM属性定义如下图所示
图2-10:OCM属性设置示例
1)读取指灯灯的数据记录
下面是代码里读取故障灯状态的部分。
图2-11 读取LED灯状态
在上面语句里,RDSYSST为SFC51符号名,实际上是调用SFC51,参数为之前声明里初始化的值,读出的数据放到在静态变里声明的数据DR里。
- SSL_ID 的初始值为W#16#0074;
- INDEX 的初始值为 W#16#0; 接下来,根据读到的数据记录数量判断是否CPU单机模式,当CPU为4.5版本时,单CPU运行只能读到主CPU的数据,数据记录条数为13(16#D),这时400H有故障,将CPU_FAILURE置位。 注:如果是V6.0版400H,此处应改为W#16#F。
2) 数据粗加工
读到的数据里,前边的数据总是主CPU的,由于并不一定是左侧机架为主CPU,所以要判断前半部分是否属于左侧CPU,如果它属于右侧CPU,那么要对数据记录前后部分交换位置,最后得到排序好的数据,便于在OS上显示。
图2-11 数据处理
- TEMP3:将来存放各个指示灯是否亮的数据。
- TEMP4: 存放各个指示灯是否闪烁的数据,每位存放一个指示灯的状态。 开始先用BYTE_TO_DWORD指令将第一个LED灯的ON值赋给TEMP3, 再用同样的指令将第一个LED灯是否闪烁的状态赋给TEMP4,接下来,以TEMP1为循环指针,循环次数为读到的数据记录个数减1,做循环处理如下: 用TEMP2取得第2组数据的ON值,并向左移位,并用它和TEMP3进行”OR”,从而在TEMP3得到两组灯的状态。 TEMP5得到第2组数据的BLINK状态。 循环N次后,在TEMP2和TEMP4里得到每个指示灯ON和BLINK的状态。 下面的程序,对第一组数据属于哪个机架的CPU,如果是16#F9开头,那么,对TEMP3和TEMP4的数据进行前后两组数据的颠倒。
图2-12 数据前后交换 接下来, 按照LED灯的排序,判断是否BUSF, IFM1F,REDF等亮起,在V4.5版本,这些灯亮起后,就得到DW#16#001C60E,用它和TEMP 3进行与,如果结果不等于 0,就说明至少有一个故障灯,如果是V6.0版本,这个值应该为DW#16#E3D8712C。
图2-13 故障判断 3) 将排序好的结果赋值
最后把加工的的数据分别赋给LED_ON和LED_BLINK,并且读到 的故障灯顺序号分别赋到LED_ID1 ~ 26。
图2-14 状态值输出
2.4.3 故障时消息上传
如果在功能块中需要产生功能块相关的报警消息,则需要在功能块的静态变量中定义相应报警功能块的多重实例。报警消息的传递、确认以及附属变量的传递等取决于CPU的特性。系统的标准功能库Standard Library中包含了所有能使用的与报警相关的功能块,如下表所示。
在PCS7中使用Alarm_8p功能块触发报警,而且需要设置功能块的报警组态窗口类型为PCS7类型(S7_alarm_ui:=1)。
如果功能块使用了报警相关功能块发送相应报警消息到OS,则首先需要定义一个输入DWORD型参数(例如,EV_ID)。当在CFC中调用该功能块时,此参数会自动从系统中获取唯一的ID。当编译OS时,每条报警的消息ID将自动通过此ID计算得到。因此,需要对该参数的系统属性进行相应的设置。加入系统属性”S7_server:=alarm_archiv”、”S7_a_type:=alarm_8p”(根据使用的报警功能块而定)。同时为了保护该参数不被用户无意中修改,需要设置”S7_visible:=false; S7_link:=false; S7_param:=false”,下图所示为EV_ID声明示例。
图2-15:EV_ID声明示例
在代码最后调用ALARM_8P将CPU_FAILURE CPU_FAULT消息上传,触发信号里均和ALARM_OUT做“与”判断,ALARM_OUT在CPU启动前3个周期为0,以实现前几个周期报警抑制功能。
图2-16 报警处理代码
报警功能块的输入如果没有被使用,可以在用户功能块的接口中定义,以便于用户对相应的功能进行使用。例如,alarm_8p功能块的附属变量即可通过接口的方式提供给用户使用,如下图所示。
图2-17 SCL编译注意事项
2.5 OS显示部分
首先将文档里的画面文件拷贝到OS项目下的GraCS文件夹。
SCL代码部分编译成FB功能块后,在CFC里调用并编译下载AS和OS,那么在将功能块的变量和消息编译到OS,画面上会自动生成块图标,运行后打开图标可以看到面板。
由于官方文档里的画面是为V4.5版本CPU开发的,在V6.0版本CPU下调用时,需要对面板进行调整,增加原来没有的两个LED,如有必要,还要修改文字显示、颜色和该指示灯在数据记录里的顺序。
图3-1 对画面进行调整