Function Block
- A function block is a type, and variables can be declared as an instance of the function block.
- Function blocks contain both state (variables) and behavior and are the primary building blocks for programming in a object oriented manner.
- Each instance variable of a function block contains its own state which exists in memory.
Syntax
The FUNCTION_BLOCK keyword begins the function block declaration while the END_FUNCTION_BLOCK keyword closes the function block declaration.
indicates that the function has a return value. Any number of variable blocks can be added, but keep in mind that local variables are initialized on every call.
FUNCTION_BLOCK FB_MyFb
// Variable declarations
VAR
a : INT;
END_VAR
// Body
a := a + 1;
END_FUNCTION_BLOCK
Instantiation
In the example below, both instA and instB contain independent state. The Count in instA does not have to match the Count of instB. In this way, we have encapsulated the behavior (an object that counts up on a rising edge trigger) in a re-usable object.
FUNCTION_BLOCK FB_Counter
VAR_INPUT
Edge : BOOL;
END_VAR
VAR
ONS : BOOL;
END_VAR
VAR_OUTPUT
Count : INT;
END_VAR
// Implement a 'rising edge' trigger
IF Edge AND NOT ONS THEN
Count := Count + 1;
END_IF;
END_FUNCTION_BLOCK
VAR
instA : FB_Counter;
instB : FB_Counter;
END_VAR
Scope
Considering our FB_Counter example, there are various rules related to the variables that are defined in the function block. This follows the object-oriented principle of encapsulation which is really just a fancy term for access control. In the case of function blocks:
- Input variables can be read or assigned outside the scope of the function block, but only from the scope in which the instance is declared.
- Local variables cannot be accessed outside of the scope of the function block.
- Output variables can be read, but not assigned outside the scope of the function block (again only from the scope in which the instance is declared)
instA.Edge := TRUE; // Can assign to input variables
instA(); // Count up
print(instA.Count); // 1 - Can 'read' output variables, not assign
instA.ONS := FALSE; // Cannot access local variables outside the scope
instB(Edge := FALSE); // Does not count
print(instB.Count); // 0
Inheritance
A function block can EXTEND at most one function block, although the function block being extended may itself also extend another function block. Inheritance provides access to the extended function block's members to the so-called derived function block. The function block that is being extended is often called a 'base' function block.
This practice is normally used when the derived function block is adding state (more variables) or adding / changing the behavior of the base function block.
The base function block is a dependency of the derived function block. If the state/behavior of the base function block changes, this may cause breaking changes to the derived function block as well.
You must explicitly call the base function block within the body of the derived function block in order to execute the body of the base function block using SUPER^(). You may also pass parameters to the call. Consider the order of execution between the base and derived function block in deciding where and when to call the base function block.
In this example, we add a Maximum to the counter that resets to zero when the maximum count has been exceeded. This example represents a change in behavior of the Count variable.
FUNCTION_BLOCK FB_LimitedCounter EXTENDS FB_Counter
VAR CONSTANT
MAX_COUNT : INT := 2;
END_VAR
SUPER^(); // Always have to explicitly call the base FB
// Reset the count if it exceeds the maximum
IF Count > MAX_COUNT THEN
Count := 0;
END_IF;
END_FUNCTION_BLOCK
VAR
inst : FB_LimitedCounter;
i : INT;
END_VAR
FOR i := 1 TO 4 BY 1 DO
inst(Edge := TRUE); // Count up
inst.Edge := FALSE;
print(inst.Count);
END_FOR;
Methods
For more details on methods, refer to the Methods page.
Properties
Properties are not supported yet.
Interface
For more details on interfaces, refer to the Interfaces page.