Structure of text blocks
Text blocks within DUTs, GLVs and POUs consist of declarations, expressions, assignments, calls, statements or loops.
Declarations
- Declarations consist of 3 to 5 columns:
- Variable name
- [Allocation (e.g. AT %Q*)]
- Data type
- [Initialization]
- [Comment]
- Whether the columns for allocation, initialization and comment exist depends on the respective program.
- Each declaration column within a program element starts at the same line level (example: all data types start at same line level).
- These variable declarations, if present, are created in a consistent order:
VAR_INPUT
END_VAR
VAR_IN_OUT CONSTANT
END_VAR
VAR_IN_OUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
END_VAR
VAR PERSISTENT
END_VAR
VAR CONSTANT
END_VAR
- Each declared variable is given an identifier that is as self-explanatory as possible. If further information is needed to clarify the purpose or functionality of the variable, it is described by means of a comment following the declaration (on the same line).
- Thematically related declarations are
- bundled in a declaration block,
- described with a comment
- and separated from other declaration blocks with a blank line.
Sample:
VAR
// Movement control
bExecuteMovements AT%I* : BOOL; (* Controls the movement
execution of car and bike *)
bMovementsDone AT%Q* : BOOL; (* Indicates if the car and
bike finished their movement *)
// General distance variables
nMovementTime : INT; // Elapsed movement time in seconds
nDistanceTotal : INT; // Total distance being covered by car and bike
nStartPosition : INT := 100; // General start position where car and bike begin to move
// Car
fbCar : FB_Car; // Car-FB whose movement is controlled
nDistanceCar : INT; // Distance being covered by car
// Bike
fbBike : FB_Bike; // Bike-FB whose movement is controlled
nDistanceBike : INT; // Distance being covered by bike
END_VAR
Expressions
- For expressions, each operator is separated by a space.
- Depending on the number and complexity of the subexpressions, parentheses can be used to visually illustrate the processing sequence and to enhance readability.
Examples:
nDistanceCar := fbCar.nStartPosition + (fbCar.nVelocity * nMovementTime);
nDistanceBike := fbBike.nStartPosition + (fbBike.nVelocity * nMovementTime);
nDistanceTotal := nDistanceCar + nDistanceBike;
Assignments
- Allocation operators for an assignment block start at the same line level.
- Equal line levels are achieved by the tab key.
- An allocation operator is followed by a space.
- Long assignments that exceed the screen width are split by means of a line break. The text part that ends up on a new line is indented (with the tab key) to a level after the allocation operator, e.g.:
bExpressionResult := bCondition1 AND (bCondition2 OR bCondition3)
AND bCondition4 AND (bCondition5 OR bCondition6);
- Thematically related assignments are
- bundled in an assignment block
- and separated from other blocks with a blank line.
Sample:
//=========================================================
// Submodule enable
// Sensors
fbSensorEStop.bEnable := bGeneralEnable AND bSensorEnable;
fbSensorStartPos.bEnable := bGeneralEnable AND bSensorEnable;
// Cylinder
fbCylinderSystem1Main.bEnable := bGeneralEnable AND bCylinderEnable;
fbCylinderSystem1Sub.bEnable := bGeneralEnable AND bCylinderEnable;
fbCylinderSystem2Main.bEnable := bGeneralEnable AND bCylinderEnable;
fbCylinderSystem2Sub.bEnable := bGeneralEnable AND bCylinderEnable;
// Axes
fbAxisSubfoil.bEnable := bGeneralEnable AND bAxisEnable AND NOT bStop;
fbAxisMain.bEnable := bGeneralEnable AND bAxisEnable AND NOT bStop;
//=========================================================
Calling methods/functions/function blocks
- Calls of methods/functions/function blocks with up to three parameters can be written single-line.
- Multiple single-line calls can be bundled into a text block.
- If the program elements have more than three parameters, they represent separate text blocks and are separated from other blocks by a blank line. Here the first parameter is in the line of the call or in the next line. The other parameters each start on a new line.
- The parameters beginnings are indented to the same level using the tab key.
- The allocation operators also start at the same line level.
- An allocation operator is followed by a space.
- If parameters are transferred to a function block or read at the same point in the program at which the instance is called, this occurs when the function block is called, and not immediately before or after the instance call.
- To increase the readability of the program code, a qualified call of methods/functions/function blocks is recommended. Here the assignment is formulated by explicitly naming the parameter name when it is called.
Negative sample:
fbTimerStart.IN := TRUE;
fbTimerStart.PT := T#10S;
fbTimerStart();
bStartExecution := fbTimerStart.Q;
Positive sample:
fbTimerStart( IN := TRUE,
PT := T#10S,
Q => bStartExecution);
Detailed sample:
//=========================================================
// Stop
// Cylinder
fbCylinderPos1.Stop(bExecute := TRUE);
fbCylinderPos2.Stop(bExecute := TRUE);
fbCylinderPos3.Stop(bExecute := TRUE);
// Axes
fbAxis1.Stop(bExecute := TRUE, bDone => bAxis1Stopped);
fbAxis2.Stop(bExecute := TRUE, bDone => bAxis2Stopped);
//=========================================================
Statements
- RETURN, CONTINUE, EXIT, JMP, IF, CASE
- JMP statement: jump statements can and should be avoided, since they reduce the readability of the code.
- IF statement:
- An IF statement constitutes a separate text block and is separated from other blocks by a blank line.
- Nested IF statements should be avoided, for better understanding and to improve the quality of software. Instead, a defined state should always apply, implemented using a CASE statement.
- All IF-ELSIF statements should include an ELSE branch.
See also the topic IF-ELSIF statements with ELSE branch in the section Programming. - The statements are indented one level, so that only the keywords IF/ELSIF/ELSE/END_IF are at the same level. The keyword THEN does not get its own line.
- Long conditions that exceed the screen width are split by means of a line break. The text part that ends up on a new line is indented using the tab key to a suitable level, relative to the first line – either to the level of the IF keyword, or, for nested conditions, to the level of the corresponding / equivalent subcondition, e.g.:
Sample:
IF a > 10 THEN
…
ELSIF a < 10 THEN
…
ELSE
…
END_IF
IF bCondition1 AND bCondition2 AND (bCondition3 OR bCondition4)
AND bCondition5 AND bCondition6
AND (bCondition7 OR bCondition8 OR bCondition9 OR bCondition10) THEN
…
END_IF
- CASE statement:
- A CASE statement constitutes a separate text block and is separated from other blocks by a blank line.
- The enumeration values are separated from each other by a blank line and indented by one level relative to the CASE statement, so that only the keywords CASE/ELSE/END_CASE are at the same level.
- In addition, a comment about each value block can be useful.
- The statements for an enumeration value start 1-2 lines below the value (not directly next to the value) and are indented by one level relative to this value.
Sample:
//=========================================================
// Cylinder sorting process
CASE eSortingState OF
E_SortingState.DetectionOfBox:
fbCylinder.MoveToBase();
sVisuMessage := 'System in detection mode.';
IF fbSensorDelay.bOut THEN
eSortingState := eSorting_MoveCylToWorkPos;
END_IF
E_SortingState.MoveCylToWorkPos:
fbCylinder.MoveToWork();
IF fbCylinder.bAtWorkPos THEN
eSortingState := eSorting_MoveCylToBasePos;
sVisuMessage := '';
ELSE
sVisuMessage := 'Waiting for cylinder in work pos.';
END_IF
E_SortingState.MoveCylToBasePos:
fbCylinder.MoveToBase();
IF fbCylinder.bAtBasePos THEN
eSortingState := eSorting_DetectionOfBox;
sVisuMessage := '';
ELSE
sVisuMessage := 'Waiting for cylinder in base pos.';
END_IF
ELSE
sVisuMessage := 'System in non-existent state. Please check application.';
END_CASE
//=========================================================
Loops (FOR, WHILE, REPEAT)
- The loop parameters are located in one line each (FOR ... DO, WHILE ... DO, REPEAT).
- The statements are indented by one level, so only the keywords FOR/END_FOR, WHILE/END_WHILE or REPEAT/UNTIL/END_REPEAT are at the same level.
Sample:
//=========================================================
// Initialize storage areas with FOR loop
FOR nAreaCounter := cStorageStart TO cStorageEnd BY 1 DO
aStorageAreas[nAreaCounter] := nAreaCounter;
END_FOR
//=========================================================
// Initialize delivery areas with WHILE loop
nAreaCounter := cDeliveryStart;
WHILE nAreaCounter <= cDeliveryEnd DO
aDeliveryAreas[nAreaCounter] := nAreaCounter;
nAreaCounter := nAreaCounter + 1;
END_WHILE
//=========================================================