PLC报警消息处理
在TIA Protal中,大致有以下几种方式可以获取报警信息:
- HMI侧组态报警
- Program_alarm
- Prodiag
第一种方式基本上是最常用和最简单的,基本步骤是先创建报警变量再组态报警文本,由HMI定时去轮询变量,通过监控变量值的变化触发。优点是配置简单,但是效率比较低,工作量比较大(以前项目上我会新建一个报警excel来处理,每次检查报警表的时候就是我头最大的时候,特别是涉及到中英切换报警翻译的时候)。
第二种方式就是在程序中调用Program_Alarm实现报警推送,PLC中变量值的变化来推送报警消息。好处是处理在PLC侧,所以和HMI的通信负载比较低,另外一方面在PLC侧编程可以一定概率的实现自动化推送,客观降低工作量,增加效率。缺点是对设备有要求,PLC1200就不用想了,它只支持1500;另外报警文本存PLC内部的话其实还是很占PLC数据工作存储器资源的,数据量大了之后PLC可能吃不消(直接导致工作存储器不够用)。
第三种方式是使用Prodig技术,博图从V14开始就集成了prodiag功能了(它还有很多很好玩的应用,以后我可能单开一篇来写),这种技术极大的提升了编程效率,但是呢,依旧只支持1500。
所以1200的用户,还是老老实实用第一种方法吧。
1. HMI侧组态报警
以前我遇到很多非标项目,小项目很多人喜欢一个报警条目占用一个bool。最后传给HMI侧的时候HMI变量表里面就传了一大堆bool量的报警信息,这是非常占用HMI的Tag点位的。所以我这里用word来表示最多16条报警(为什么可以这么做,自己体会一下),这样的好处一是报警集中(毕竟一个或者多个word可以单独组合某一个设备单元的报警集合),二是传一个word给HMI只会被看作一个Tag,但是信息量1:16,简直遥遥领先..
废话不多说,开始演示吧。
- 自己做一个Bool2Word的块,目的是收集在程序里做的报警
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#FB_BoolToWord_Instance_Alarm1(In_Alarm00 := "_HolderLoadStation".HoistCylinder.Error_Initial,
In_Alarm01 := "_HolderLoadStation".HoistCylinder.Error_Target,
In_Alarm02 := "_HolderLoadStation".HoistCylinder.Error_Pg,
In_Alarm03 := "_HolderLoadStation".GripCylinder.Error_Initial,
In_Alarm04 := "_HolderLoadStation".GripCylinder.Error_Target,
In_Alarm05 := "_HolderLoadStation".GripCylinder.Error_Pg,
In_Alarm06 := FALSE,
In_Alarm07 := FALSE,
In_Alarm08 := FALSE,
In_Alarm09 := FALSE,
In_Alarm10 := FALSE,
In_Alarm11 := FALSE,
In_Alarm12 := FALSE,
In_Alarm13 := FALSE,
In_Alarm14 := FALSE,
In_Alarm15 := FALSE,
Out_Alarm => "_AlarmDB".HolderLoadStationAlarm1);.这是外部管脚,具体报警怎么来的取决于你报警逻辑怎么写的
程序变量接口定义:
- In_Alarmxx:Input,bool
- Alarm:Static,word
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18REGION 输入映射
#Alarm.%X0 := #In_Alarm00;
#Alarm.%X1 := #In_Alarm01;
#Alarm.%X2 := #In_Alarm02;
#Alarm.%X3 := #In_Alarm03;
#Alarm.%X4 := #In_Alarm04;
#Alarm.%X5 := #In_Alarm05;
#Alarm.%X6 := #In_Alarm06;
#Alarm.%X7 := #In_Alarm07;
#Alarm.%X8 := #In_Alarm08;
#Alarm.%X9 := #In_Alarm09;
#Alarm.%X10 := #In_Alarm10;
#Alarm.%X11 := #In_Alarm11;
#Alarm.%X12 := #In_Alarm12;
#Alarm.%X13 := #In_Alarm13;
#Alarm.%X14 := #In_Alarm14;
#Alarm.%X15 := #In_Alarm15;
END_REGION.这是内部程序,为了直观,我把报警一个一个赋值给了Word对应的bit.
.其实有一种叫做AT
的指令,可以在变量定义的时候直接把Array[0..15] of bool
映射给一个Word
。这样可以做到零代码映射,但是对FB有要求(FB不能被优化,想想为什么),感兴趣的朋友可以去玩一下。
完事之后再去HMI的HMI报警里面,把你定义好的报警文本和报警变量对应上,Ctrl+C/Ctrl+V吧。
.报警文本自己手动定义。你写个Hello World都行
.报警类别需要定义,不同的报警类别在HMI的报警控件中有不一样的处理显示规则
.触发变量和触发位配合使用,一个Word有16个位
触发器地址根据你的触发变量和触发位自动填入。
最后去画面上做出你的报警控件来,HMI选择报警视图。拽到画面上就OK。
.在HMI里面,选择
记录
,再选择报警记录
,新增一个报警日志
,设置名字
,记录数
,存储位置
。然后你就得到一个历史记录报警。
.选中报警视图
的当前报警状态
,然后你就得到一个实时报警记录。
- 至此,第一种方法就已经实现了,但是在开始第二种方法之前我对一种方法做了一个更深的探索,用来提高我写报警文本的效率(甚至可以说我压根就不想手动写报警文本)。
这里依旧简单记录一下:
我在上面的Bool2Word块里面加了一坨新的程序段,如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34REGION 数值变化记忆
// Statement section REGION
IF #In_FirstScan THEN
#AlarmMemory := #Alarm;
END_IF;
#plus(CLK:=(#AlarmMemory<>#Alarm));
IF #plus.Q THEN
#ValueChange := TRUE;
#AlarmMemory := #Alarm;
END_IF;
END_REGION
REGION 读取变量符号名做为报警文本
// Statement section REGION
IF #In_FirstScan OR TRUE = #ValueChange THEN
#AlarmText[0] := GetSymbolName(variable := #In_Alarm00, size := 0);
#AlarmText[1] := GetSymbolName(variable := #In_Alarm01, size := 0);
#AlarmText[2] := GetSymbolName(variable := #In_Alarm02, size := 0);
#AlarmText[3] := GetSymbolName(variable := #In_Alarm03, size := 0);
#AlarmText[4] := GetSymbolName(variable := #In_Alarm04, size := 0);
#AlarmText[5] := GetSymbolName(variable := #In_Alarm05, size := 0);
#AlarmText[6] := GetSymbolName(variable := #In_Alarm06, size := 0);
#AlarmText[7] := GetSymbolName(variable := #In_Alarm07, size := 0);
#AlarmText[8] := GetSymbolName(variable := #In_Alarm08, size := 0);
#AlarmText[9] := GetSymbolName(variable := #In_Alarm09, size := 0);
#AlarmText[10] := GetSymbolName(variable := #In_Alarm10, size := 0);
#AlarmText[11] := GetSymbolName(variable := #In_Alarm11, size := 0);
#AlarmText[12] := GetSymbolName(variable := #In_Alarm12, size := 0);
#AlarmText[13] := GetSymbolName(variable := #In_Alarm13, size := 0);
#AlarmText[14] := GetSymbolName(variable := #In_Alarm14, size := 0);
#AlarmText[15] := GetSymbolName(variable := #In_Alarm15, size := 0);
#ValueChange := FALSE;
END_IF;
END_REGION.
GetSymbolName
具体怎么用,可以按Ctrl+F1
,博图帮助系统会告诉你答案。
把你In_Alarm
所连接的变量符号名改成的报警文本内容(你可以选择在DB内建Struct或者引用UDT,让你的符号名更有层级)。如图:
现在回到HMI侧,在HMI变量表
新建你的AlarmDB_Word
和AlarmDB_Text
(就是在PLC程序里面建立的报警字和对应报警文本数组,数组格式我定义成Array[0..15] of WString[60]
);
找到你想处理的AlarmDB_Word
对应的离散量报警
,在对应报警文本
的地方,先双击
进入文本编辑框内,再右键
,选择插入变量域
,弹出过程子窗体,选择需要连接的变量,最后确认。如图:
.当然你也可以选连接文本列表,这又是其他玩法了,感兴趣可以玩一玩。
至此,我们就实现了用符号名来代替我们要手动键入的报警文本,是不是很神奇。
但是你反过头来再来想想,这个柔性报警有什么缺点:还记得我使用了GetSymbolName
吗,最后输出要求的格式是WSTRING
,这是个什么概念我们来算一算,一个string[60]占用62个byte长度。那么一个WString[60]就要占用124个byte长度,我们一个报警word一共产生了Array[0..15] of WString[60]
也就是124*16=1984个byte
,接近2KB
,如果多用几个就更多了,回头看一下我们的PLC数据存储器才多大,我用的1215也就125KB工作寄存器(代码+数据)。
上面的题外话说多了,那么下面我们接着做Program_Alram。
2. Program_Alarm
这个操作方法比较简单,简单描述就行。
如图,在FB里面建立一个(或多个)和报警相关的参数
在FB代码编辑界面引用Program_Alarm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//增加报警块
#Program_Alarm(SIG:=#statAlarm.trigger,
TIMESTAMP:=_ldt_in_,
SD_1:=#statAlarm.text,
SD_2:=_variant_in_,
SD_3:=_variant_in_,
SD_4:=_variant_in_,
SD_5:=_variant_in_,
SD_6:=_variant_in_,
SD_7:=_variant_in_,
SD_8:=_variant_in_,
SD_9:=_variant_in_,
SD_10:=_variant_in_,
Error=>_bool_out_,
Status=>_word_out_);.我只简单填写了
trigger
和一个报警text
,其他更多的信息可以按Ctrl+F1
获取博图帮助。
.正式使用场景因为每一条报警都需要调用一次Program_Alarm
,所以最好使用多重实例
,在循环迭代
(for循环遍历多重实例构成的数组)中调用来最大程度减少程序量;
.在PLC的
PLC监控的报警
中选择报警
,填入报警文本
(这是HMI弹出报警页面的的报警内容),填入信息文本
(这是点入报警文本之后的详细帮助信息。)
.在HMI上拖拽一个报警视图
出来,把确认信息和这里的对应好
就这么简单就可以自动生成一个Program_alarm了,记得要去HMI侧拖一个报警视图
出来并选择相关确认信息,这一步工作还是要做的。
它的问题还是会占用一部分数据寄存器的内存,但是当我们使用1500的时候,就算1511应该也是1MB的工作寄存器起步了,所以影响应该还好。
再次提醒,这个块仅支持1500。
3. Prodiag
- prodiag的基本使用方法其实很容易,这里先对基本使用做一个简易过程描述。
在1500的PLC里面,对你想使用的的变量右键(不一定非的是DB
,对于FB的基本数据类型
,IO
等等一样可以右键),我这里在FB里面新建了一个静态变量。如图:
.新建后,右边监控列会出现一个监控的
小图标
,如图不想监控了,右键这个小图标选择删除就行。
点完后的界面如下:
.监控类型可以选择
操作数
,互锁
,动作
,还有一些其他的。(比如当你选择互锁之后,就会多出一个条件让你填写),我们就拿操作数
为例,右边可以选择触发器
,下面可以选择延时
,监控类别
,等等很多,有兴趣可以自己玩一玩。
.报警文本的格式是<类别> : <监控类型> : <ProDiag FB 的名称> : <监控 ID> : <实例名称> : <参数名称> : <变量地址> : <变量名称> : <变量注释>
,注意,这意味着它甚至可以把你的变量符号
,变量地址
,变量注释
当作报警文本
的一部分输出出来。
.详细文本域
用来帮你添加你想添加的详细文本内容。
做完上面的之后,我们的选择触发器是FALSE
,意味着当该变量为假的时候PLC就会给HMI推送一条报警信息,这甚至不需要去HMI界面做任何的配置。因为它的技术是PLC推送技术,不需要HMI去轮询或者监控的。
- 在一些稍微大一点的项目中,可能会专门建立一个
Prodiag_FB
来做专门的监控管理。
在这种情况下,监控内容就具有了更多的结构化属性
,也更利于程序分类。
如下:
.选择
添加新块
,语言选择PRODIAG(含IDB)
,就可以建立一个ProdiagFB,图是建立完成并监控了一个数据后的样子。
.具体什么时候该建立什么样的监控PRODIAG(含IDB)
,监控的内容应该是什么,监控类别的分类应该怎么划分。这就是项目上用来做结构化和标准化分类所需要考虑的了,这里就不详细谈论了。
4. 总结
虽然笔者对西门子PLC报警应用的总结虽然就到这了,但技术在不断的发展和更新,很多新技术值得去尝试,还需要不断的去学习总结才行。