题目:
在自动化设备调试中,经常会遇到一种很头疼的情况:
设备一停机,HMI 上同时跳出十几个报警。
气压低报警、气缸不到位报警、电机运行反馈丢失、伺服未准备好、安全门打开……
现场人员一看报警画面,满屏都是红色。
但真正导致设备停机的,往往只有第一个故障。
后面的很多报警,只是连锁反应。
本例用 SCL 编写一个“首发报警记录器”,实现多路报警锁存,并记录第一个触发的报警编号。
设计分析:
普通报警逻辑一般只关心两个问题:
报警有没有发生?报警有没有复位?
但在实际项目中,仅仅知道“有报警”还不够。
设备停机以后,维护人员最关心的是:
第一个报警是谁?
比如一台设备有 32 路报警信号,如果第 7 路报警最先触发,就记录:
firstAlarmIndex := 7;
只要没有复位,后面即使第 3 路、第 12 路、第 20 路报警又触发,也不再覆盖首发报警编号。
这样调试时就很清楚:
先看首发报警,再看后续报警。
这个思路在输送线、包装机、装配设备、非标设备里都很实用。
创建功能块:
创建功能块 FB,命名为:
FirstAlarmRecorder
本例按照 32 路报警设计。
实际项目中可以根据设备规模改成 16 路、64 路,或者用可变限值数组继续扩展。
定义接口变量:
定义输入变量:
enable:功能使能;
reset:报警复位;
count:实际使用的报警数量;
alarmIn:报警输入数组。
定义输出变量:
anyAlarm:任意报警;
firstAlarmValid:首发报警有效;
firstAlarmIndex:首发报警编号;
alarmLatched:报警锁存输出数组。
定义静态变量:
statFirstAlarmValid:首发报警有效中间变量;
statAlarmOld:上一扫描周期报警状态,用来判断报警上升沿;
statAlarmLatched:报警锁存输出数组中间变量。
定义临时变量:
tempActiveAlarm:当前是否仍有报警输入存在;
tempI:循环变量;
validCount:有效报警数量。
程序代码:
调用方法:
在 OB1 或设备主 FB 中调用该功能块。
例如创建一个全局 DB:
GdbFirstAlarm
里面定义:
调用时可以这样写:
报警输入映射可以放在调用前或其它 FC 中:
HMI 报警画面中,普通报警可以读取:
AlarmLatched
首发报警可以读取:
FirstIndex
比如 FirstIndex = 6,就说明本次停机最先触发的是第 6 路报警。
工程注意事项:
首发报警不建议自动清除。
如果报警输入一消失,首发记录马上清零,那么维修人员赶到现场时,已经看不到第一现场了。
比较稳妥的做法是:
报警原因消除后,由操作员按复位按钮清除锁存报警和首发记录。
另外,报警编号一定要和 HMI 报警文本保持一致。
例如:
1:气压不足;
2:安全门打开;
3:急停未复位;
4:电机故障;
5:伺服故障;
6:气缸伸出超时;
7:气缸退回超时。
PLC 里是第 6 路,HMI 文本也必须是第 6 条。
否则程序没有问题,现场排故还是会乱。
常见问题:
第一,首发报警被后续报警覆盖。
这类写法很常见:
IF alarmIn THEN
firstAlarmIndex := 1;
END_IF;
这样每次有报警都会重新赋值,最后记录到的不是“首发报警”,而是循环扫描到的某一个报警。
第二,报警不锁存。
有些程序直接把报警输出等于报警输入:
alarmOut :=alarmIn;
这样报警信号一闪而过,HMI 上也可能一闪而过。
对于停机类、故障类报警,通常建议锁存。
第三,复位条件太宽。
如果报警输入还存在,按复位就把报警清掉,这种写法不适合故障诊断。
更合理的方式是:
故障输入消失后,才允许复位锁存。
第四,报警数组没有统一管理。
报警条件散落在多个 FC、FB、网络段里,后期增加 HMI 报警文本、报警等级、报警记录时都会麻烦。
项目稍微大一点,建议把报警输入、报警锁存、首发记录、HMI 报警编号统一规划。
总结:
本例学习了以下内容:
学习 BOOL 数组在报警管理中的应用;
学习 FOR 循环批量处理多路报警;
学习报警锁存的基本写法;
学习利用上一扫描周期状态判断报警上升沿;
学习首发报警记录在现场排故中的作用。
PLC 程序不是只要能让设备跑起来就行。
设备出问题以后,程序能不能帮现场人员快速定位原因,这才是项目经验的差距。
首发报警记录器代码不复杂,但在调试和售后阶段很值钱。
实例分享链接:
https://pan.quark.cn/s/eba22688c5f0