Runtime - Krystian-L-Lis/Stage GitHub Wiki
#Guide #Runtime
Do not repeat yourself, but PLC programming often requires us to do this:
VAR
fbMotorControl : MotorControl;
END_VAR
fbMotorControl();
This is fine when there are only a few function blocks. But what if there are many, each with unique names and types?
VAR
fbMotorControl1 : MotorControl;
fbMotorControl2 : MotorControl;
fbMotorControl3 : MotorControl;
fbMotorControl4 : MotorControl;
fbMotorControl5 : MotorControl;
fbTemperature1 : TemperatureSensor;
fbTemperature2 : TemperatureSensor;
fbTemperature3 : TemperatureSensor;
fbTemperature4 : TemperatureSensor;
fbPressure1 : PressureSensor;
fbPressure2 : PressureSensor;
fbConveyor1 : ConveyorControl;
fbConveyor2 : ConveyorControl;
fbConveyor3 : ConveyorControl;
fbLighting1 : LightingControl;
fbLighting2 : LightingControl;
fbLighting3 : LightingControl;
fbLighting4 : LightingControl;
END_VAR
fbMotorControl1();
fbMotorControl2();
fbMotorControl3();
fbMotorControl4();
fbMotorControl5();
fbTemperature1();
fbTemperature2();
fbTemperature3();
fbTemperature4();
fbPressure1();
fbPressure2();
fbConveyor1();
fbConveyor2();
fbConveyor3();
fbLighting1();
fbLighting2();
fbLighting3();
fbLighting4();
This is overwhelming. Of course, it is possible to iterate over them, but we would still need four separate update loops. Each loop requires its own management to ensure it doesn't go out of bounds. Wouldn't it be nice to somehow add them automagically to some kind of execution loop and eliminate the need for all the calls in the code?
The Runtime provides exactly this capability. Additionally, as with everything in Stage, it does not require inheritance.
On top of that, Runtime provides an initialization method that is executed during the first loop of the program, after every FB_Init
method has been executed. This allows the creation of couplings between individual function blocks using the EC system. Although it uses more memory than the call-after-init
attribute, there is a good reason to prefer it. The IDE will notify you if you make a typo, unlike the attribute. Similar to the cyclic execution functionality, it also does not require inheritance.
Use the Execute
function block in tandem with I_Execute
to notify the Runtime to add a given function block to the cyclic execution loop.
Example:
FUNCTION_BLOCK ExecutableFb IMPLEMENTS I_Execute
VAR
_exe : Execute(THIS^);
END_VAR
METHOD Execute
// Logic
END_METHOD
Use the Init
function block in tandem with I_Init
to notify the Runtime to execute this function block during the first iteration of the program, before the execution cycle.
Example:
FUNCTION_BLOCK InitiableFb IMPLEMENTS I_Init
VAR
_init : Init(THIS^);
END_VAR
METHOD Init
// Logic
END_METHOD
Now that we have both executable and initiable function blocks, we can execute them!
Example:
PROGRAM Main
VAR
initFb1 : InitiableFb;
initFb2 : InitiableFb;
initFb3 : InitiableFbOtherType;
initFb4 : ARRAY[1..5] OF InitiableFb;
exeFb1 : ExecutableFb;
exeFb2 : ExecutableFb;
exeFb3 : ExecutableFbOtherType;
exeFb4 : ARRAY[1..5] OF ExecutableFb;
END_VAR
Runtime();
That's all! There is no need to modify any parameters. Everything works without additional user input. And because the composition is used, the FB may implement multiple interfaces, so we can have a FB that is both initiable and executable.
Note: Both initialization and execution occur in the order of declaration.
Warning: The system does not check if a given function block is registered multiple times. You can use
Phase
and thenPhase
argument to determine when methods are called.
< Previous | Home | Next >