我正在使用结构化文本为施耐德 PLC 编写一个程序,并且我正在尝试使用面向对象编程来完成它。
作为 PLC 编程的新手,我编写了一个简单的测试程序,如下所示:
okFlag:=myObject.aMethod();
IF okFlag THEN
// it's ok, go on
ELSE
// error handling
END_IF
aMethod
必须执行一些操作,等待结果(有一个“超时”检查以避免死锁)并返回TRUE或FALSE
这就是我在程序执行过程中所期望的
1)当到达
okFlag:=myObject.aMethod();
时,执行aMethod
里面的代码,直到返回结果。当我说“执行”时,我的意思是在下一个扫描周期中,aMethod
的执行从之前到达的点继续。
2)检查方法调用结果并执行程序主流程
这就是发生的事情:
1)
aMethod
被执行,但程序流程继续。也就是说,当它到达 aMethod
的末尾时,它会返回一个值,即使 aMethod
应该等待的事件仍在执行。
2) 在下一个周期,再次调用
aMethod
并从头开始
这是我找到的第一个解决方案:
VAR_STATIC
imBusy: BOOL
END_VAR
METHOD aMethod: INT;
IF NOT(imBusy) THEN
imBusy:=FALSE;
aMethod:=-1; // result of method while in progress
ELSE
aMethod:=-1;
<rest of code. If everything is ok, the result is 0, otherwise is 1>
END_IF
imBusy:=aMethod<0;
以及主程序:
CASE (myObject.aMethod()) OF
0: // it's ok, go on
1: // error handling
ELSE
// still executing...
END_CASE
这似乎有效,但我不知道这是否是正确的方法。
Schneider 的一些库使用返回布尔值的方法,并且似乎在我的程序中按照我的预期工作。也就是说:当循环第一次到达方法调用时,程序流程会以某种方式“偏离”,以便在下一个循环中再次进入该方法,直到完成。有没有办法有这种行为?
一般来说,OOP 并不是人们在使用 IEC61131 语言时会采用的方法。您最好的选择可能是将代码实现为状态机。我过去曾使用这种方法来简化复杂的序列,以便工厂维护人员更容易解释。
如果您打算采用这种方法,我通常会建议尝试将状态机本身与工作代码分离;您可以实现 X 个步骤的状态机,然后让您的工作代码引用状态机步骤。
一个简单的例子可能如下所示:
stepNo := 0;
IF (start AND stepNo = 0) THEN
StepNo = 1;
END_IF;
(* there's a shortcut unity operation for resetting this array to zeroes which is faster, but I can't remember it off the top of my head... *)
ActiveStepArray := BlankStepArray;
IF stepNo > 0 THEN
IF StepComplete[stepNo] THEN
stepNo := stepNo +1;
END_IF;
ActiveStepArray[stepNo] := true;
END_IF;
然后在其他代码部分你可以放入...
IF ActiveStep[1] THEN
(* Do something *)
StepComplete[1] := true;
END_IF;
IF ActiveStep[2] THEN
(* Do Something *)
StepComplete[2] := true;
END_IF;
(* etc *)
这种方法的好处是,您实际上可以将所有状态机代码(包括跳转、重置等)放入 DFB 中,测试它,然后搁置它,然后只使用活动步骤、步骤完成和任何您需要的其他输入。
你的代码仍然总是会执行整个逻辑部分,但如果你真的想避免这种情况,那么你将不得不使用大量 IF 语句,这会妨碍可读性。
希望有帮助。
为什么不使用 SFC 在很多情况下它会让你的生活更轻松,因为它本身就是状态机语言。执行子程序,等待条件执行另一个..冲洗并重复。 :)
不要只为 ST 挂起,其他 IEC 语言在其他一些任务中表现更好,并且尽可能保持清晰。工业PLC编程圈不应该像许多其他编程领域那样有“这是我的蛋糕”的心态,因为申请时间可以是40年,而你在20年前离开公司去寻找更好的工作,程序是几乎总是位置/客户或至少特定于硬件。
http://www.automation.com/pdf_articles/IEC_Programming_Thayer_L.pdf
关于如何在结构化文本中进行面向对象编程,有几种可能的方法:
可以用任何编程语言编写主要面向对象的应用程序:
QM_AddToQueue
、QM_RemoveFromQueue
等)。这当然会导致代码比现代 C++ 中的代码更庞大,但完全可以生存。如果对象太多,请将它们分组。
如果需要多态性(情况并非总是如此,但可能类似于不同事件的共享队列),“对象结构”可以包含所有情况的字段和枚举标记以区分它实际是什么类型。如果字段数量很少并且许多字段是共享的,那么这种方法就足够了。