揭示plc程序错误的普遍性

1、引言
可编程序控制器(简称plc)是一种工业自动控制中使用的计算装置。它广泛应用于钢铁、石油、化工、电力、建材、机械制造、汽车、轻纺、交通运输、航天、环保及文化娱乐等各个行业。小到家用设备,大到航天器材,都有plc的应用。
典型的plc由一个专用的cpu,一个存储器和一组输入输出端口构成,如图1所示。它通过输入端口接收来自传感器的信号,并通过输出端口发出控制信号驱动同它连接的外部设备。存储器中安放控制程序,系统的活动由控制程序所驱动。
plc系统每隔一定的时间间隔(比如5毫秒)从输入端口读入信号,执行计算,然后向输出端口发送输出信号。每一“输入-计算-输出”周期称为一个扫描周期。plc程序在每个扫描周期中重复执行一遍。plc的简单应用有洗衣机控制,电梯控制。复杂的应用有自动机床控制,自动化工程控制。
plc程序设计具有不寻常的软件编程模式。设计中需要考虑多个并行线程,它们之间的交互作用,以及在时间域上的行为。在plc的五种主要的编程语言当中,源自继电器控制系统的梯形图语言采用了一种简单的方式巧妙地处理了并行程序设计问题,然而,由于plc编程问题的固有复杂性,以及测试手段的缺乏,许多plc程序中依然存在大量的错误。
为了解决这一问题,灵芯实验室正在开发plc测试系统,为plc程序的调试提供解决方案。在这一系统的试用过程中,在两本plc入门教科书的6个简单程序例子中发现其中的4个程序里面至少包含8个错误。
●一个抢答器程序在两个参赛者同时按下抢答按钮时,只有其中一个人的警报器能够发出警报;
●一个喷泉程序中,喷水组在几个指定时间上没有按要求停止喷水,或开始喷水;
●一个交通灯控制程序中,绿灯闪烁控制不正常;系统启动的时候,一个方向绿灯亮,另一个方向的红灯却不亮;强通结束之后,交通灯没有立即恢复正常运行;
●在另一个交通灯程序中,按下停止按钮之后,所有的灯熄灭,但两个方向人行道上却亮红灯。
我们认为这一发现是不同寻常的。虽然每个程序员和教师都会犯编程错误,但是我们还从未在任何一本程序设计的教科书中发现如此高比例的程序错。这一现象初步证实了plc程序 错误的广泛性和严重性。
本文将逐一分析上述每一个程序的错误,指出错误原因。其中大部分程序,我们给出纠正了错误的新程序。期望这一分析能够帮助plc程序员和教师提高plc程序设计的正确性。plc程序的执行原理以及梯形图的语义将在例子的介绍中同时给予解释。我们相信,通过分析错误来学习是掌握遍程技巧的好方法。
图1 plc构造原理图
2、抢答器程序
题目:抢答器程序
来源:plc应用技术开发与实践
编程平台:西门子公司 s7-200
问题描述:
(1)主持人控制开始按钮;
(2)3个抢答者每人控制自己的抢答按钮;
(3)开始按钮按下之后所有警报器断电;
(4)之后每个抢答按钮按下将使自己的警报器得电,并锁住其他抢答者输入信号的有效性。
变量分配:
i0.0 主持人按钮;
i0.1,i0.2,i0.3 分别为三个抢答者按钮;
q0.0,q0.1,q0.2 分别为对应于抢答者的警报器输出;
原书给出的抢答器梯形图程序(见图2)。
图2 抢答器梯形图程序
plc程序语义:
上述梯形图程序的语义可以用比较简短的方式表达出来:
q0.0 := (i0.1 or q0.0) and ~i0.0 and ~q0.1 and ~q0.2;
q0.1 := (i0.2 or q0.1) and ~i0.0 and ~q0.0 and ~q0.2;
q0.2 := (i0.3 or q0.2) and ~i0.0 and ~q0.0 and ~q0.1;
其中~i0.0表示i0.0的逻辑非。
plc的程序周期性地重复执行,每个周期时间很短。在一个周期中,plc将读入输入值(这里是i0.1,i0.2和i0.3),经过对上述程序的计算之后,把输出变量(这里是q0.0,q0.1和q0.2)的值送到外部。注意上述程序在每个周期中都重复执行。在每个周期中,程序的执行由上往下由左至右。
当一个抢答按钮按下之后(比如i0.1=1),对应的输出(q0.0)马上变成1。在下一周期中,即使该按钮方开(i0.1=0)程序的输出依然会保持为0,原因是程序依靠自反馈作用(or q0.0)。同时,由于在另外两个程序段中含有~q0.1,因此它们的输出都无法变成1,直到主持人按钮i0.0把q0.0重新置0为止。
●程序问题
如果两个抢答者在同一时刻按下按钮,在程序中处于前面的抢答者的警报器输出正常,另一个抢答者的警报器没有输出。
●程序分析
本问题分成三个程序段,它们本应并行执行方能达到公平的效果。但plc的cpu只能顺序执行程序,因此在程序中位置处于前面的抢答者的输出产生之后,后面的程序输出就被立即阻断。因此两个按钮同时按下时,只有其中的一个得到响应。
plc的编程模式来源于继电器电路控制系统,在那些系统中,上述三个程序段对于三个并行运行的电路,但是转到cpu中之后,这些程序就不得不顺序执行。并行模型与顺序执行的冲突是许多程序错误的原因。在作者先前的论文中就对这一问题进行了分析[1]。
在顺序执行的机器上面实现plc并行语义是可能的。但是依然需要小心各种陷阱。下面的第一次尝试存在一个错误,再后面一个程序改正了这个错误,通过了程序测试。
●程序修正尝试
克服上面问题的一个自然的想法是使用中间变量保存每个程序段的输出。这一思路导致下面的程序实现(见图3):
图3 程序修正尝试程序实现图
使用这一程序时,如果两个抢答者的按钮同时按下,对应的两个警报器会同时响。但是,在下一周期,两个警报器的输出又会同时恢复到0。原因是每一个抢答输入都会导致另一个抢答无效,两个抢答输入就会同时导致对方无效。
●最终程序
下面的程序克服了上述问题,并且通过了基本的测试检查(见图4)。
它同前面程序不同之处在于把q0.0等变量的管辖范围放宽了,因此一旦q0.0为1,只要主持人按钮不按下,它的值就能继续保持下去。
图4 基本测试检查结果
3、喷泉程序
题目:plc在喷泉中的应用
来源:plc应用技术开发与实践
编程平台:三菱公司fx2n系列
问题描述
(1)喷泉有a,b,c 3组喷头;
(2)按动开始按钮后,a组先喷,10秒后停,然后b组和c组同时喷;
(3)b和c喷10秒后b停,再10秒后c停;
(4)a,b又喷,5秒后,c也喷,持续10秒后全部停;
(5)再5秒后重返上述(2)到(4)步;
(6)按动停止按钮后,a,b,c 3组喷头全部停。
输入输出变量分配:
x0001:开始按钮
x0002:结束按钮
y0001:a组喷头
y0002:b组喷头
y0003:c组喷头
内部继电器:m0—m5
定时器分配(见图5):
t0:a组喷10秒; 0—10
t1:b,c组喷10秒; 10—20
t2:c组喷10秒; 20—30
t3:a,b组喷5秒;30—35
t4:a,b,c组喷10秒; 35—45
t5:a,b,c组停喷5秒; 45—50
同前一程序相比,这一程序中增加了t0,t1等定时器。定时器用t标识,它的上方是定时器变量名,下方是预定的定时延迟。本例使用的是ton类型定时器,这种定时器只要输入端由0转1计时就开始,在计时过程中,输入端必须始终保持为1,一旦定时器到时,它所对应的变量就立即由0转1。在计时过程中,如果输入端转0,则计时停止,定时器到时之后,只要输入端继续为1,那么计时器变量也继续保持为1,一旦输入变0,计时变量也转为0。本例中的定时器按十分之一秒为单位计时。
这个程序含有三个错误,它的某些喷头在预定停止的时刻没有停止,在预定开始的时刻没有开始。
程序错误(1):按照要求程序开始后20秒,c组喷发应该停止,但该程序却没有停止c的喷发。
原因分析
c的喷发受到m1,m2和m3的控制,它们分别控制c组的第一,第二和第三次喷发。在第二次喷发结束之后,m2为0,喷发本应停止,但调试中发现c的输出(y0002)继续为1,单步调试发现, 此时m1为1,由此造成c组输出继续。分析发现,产生m1的梯形图有错。应该使用m1来产生反馈,但程序中用了b组的输出变量y0001。 该变量恰好在c组第二次喷发之后重新置1,因此造成了c组继续喷发。将此处改成m1之后这一错误即可消除。
程序错误(2):程序开始后50秒,a组喷发应该重新开始,但实际运行中并未开始。
原因分析:
这是一个定时时间写错的简单错误。定时器t4设定的时间应为5秒(50),但梯形图中错写成100(该书指令表程序中也是写50,梯形图中是一个失误)。
程序错误(3):在纠正了上面两个错误之后,程序依然无法通过测试。50秒之后,c组不应该开始喷发,但实际运行中喷发。
原因分析:
50秒之后,程序进入下一周期。此时程序该如何运行在原书中没有清楚描述,这属于描述不全。根据程序的具体实现,可以看出作者的意图是在50秒之后把整个喷发过程重演一遍。基于这样的理解,程序应该在50秒之后开始a组喷发,但程序运行结果是,不但a组喷发,而且c