Allocated variables
Topics:
Do not use direct addressing
Direct addressing should not be used for allocated variables. Instead of direct addressing, the use of automatic addressing using the * placeholder is recommended. If the placeholders * (%I*, %Q* or %M*) are used, TwinCAT automatically performs flexible and optimized addressing.
There should also be no direct address accesses in the implementation part.
Static Analysis:
Verify using the following Static Analysis rules:
Thematically recommended Static Analysis rule:
Negative sample:
VAR
bInputSignal AT%IX4.0 : BOOL;
bVar : BOOL;
END_VAR
bVar := %IX0.0;
Positive sample:
VAR
bInputSignal AT%I* : BOOL;
END_VAR
Avoid multiple write accesses to outputs
Multiple write access to outputs should be avoided. Multiple write access to outputs occurs if outputs are written at more than one point in the program.
Exception to this rule: assignments in different branches of an IF or CASE statement.
Static Analysis:
Check with the help of Static Analysis rule:
The rule SA0004 is also included in the license-free variant Static Analysis Light.
Negative sample:
PROGRAM Sample_neg
VAR
bErrorLed AT%Q* : BOOL; // Machine's error LED
bErrorDrill : BOOL; // Drill error status
bErrorTransport : BOOL; // Transport error status
nTestCounter : WORD; // Simple counter
END_VAR
--------------------------------------------------------------------
bErrorLed := bErrorDrill OR bErrorTransport; // NON COMPLIANT: bErrorLed will be written more than once: See action CounterInc
CounterInc();
--------------------------------------------------------------------
--------------------------------------------------------------------
(* --- Method: CounterInc ---
This method increments the counter and checks if nCounterValue is equal to 0 *)
bErrorLed := (nTestCounter = 0); // NON COMPLIANT: bErrorLed will be written more than once: See program MAIN
nTestCounter := nTestCounter + 1;
Positive sample:
PROGRAM Sample_pos
VAR
bErrorLed AT%Q* : BOOL; // Machine's error LED
bErrorDrill : BOOL; // Drill error status
bErrorTransport : BOOL; // Transport error status
bErrorCounter : BOOL; // Test counter error status
nTestCounter : WORD; // Simple counter
END_VAR
--------------------------------------------------------------------
CounterInc();
bErrorLed := bErrorDrill // COMPLIANT
OR bErrorTransport
OR bErrorCounter;
--------------------------------------------------------------------
--------------------------------------------------------------------
(* --- Method: CounterInc ---
This method increments the counter and checks if nCounterValue is equal to 0 *)
bErrorCounter := (nTestCounter = 0); // COMPLIANT
nTestCounter := nTestCounter + 1;
Avoid overlapping memory areas of address variables
Overlapping memory areas of address variables should be avoided. Overlapping memory areas occur if the same storage space is used by several variables.
If an overlapping memory area is required for programming reasons, UNIONs can be used for stylistic purposes. Overlapping memory areas in other variables, e.g. address variables, should be avoided.
Static Analysis:
Check with the help of Static Analysis rule:
The rule SA0028 is also included in the license-free variant Static Analysis Light.
Negative sample:
PROGRAM Sample_neg
VAR
nTestWord AT%MW2 : WORD; // Test WORD
nTestLowByte AT%MB4 : BYTE; // NON COMPLIANT: overlaps with nTestWord
nTestHighByte AT%MB5 : BYTE; // NON COMPLIANT: overlaps with nTestWord
END_VAR
--------------------------------------------------------------------
nTestLowByte := 0; // NON COMPLIANT: writes nTestWord = 16#xx00
nTestHighByte := 0; // NON COMPLIANT: writes nTestWord = 16#00xx
nTestWord := 16#C0FF; // Writes nTestLowByte and nTestHighByte too
Positive sample:
// Structure for the positive sample
TYPE ST_2_BYTES :
STRUCT
nLow : BYTE; // Low byte
nHigh : BYTE; // High byte
END_STRUCT
END_TYPE
// Union for the positive sample
TYPE U_BYTE_WORD :
UNION
stLowHigh : ST_2_BYTES; // Struct with two bytes
nValue : WORD; // Test WORD to be united with the two-byte-struct
END_UNION
END_TYPE
PROGRAM Sample_pos
VAR
uTestWordToBytes AT%MW2 : U_BYTE_WORD; // Test union
nTestLowByte : BYTE; // COMPLIANT: not addressed
nTestHighByte : BYTE; // COMPLIANT: not addressed
END_VAR
--------------------------------------------------------------------
uTestWordToBytes.nValue := 16#C0FF; // A test value
nTestLowByte := uTestWordToBytes.stLowHigh.nLow; // Will be 16#FF
nTestHighByte := uTestWordToBytes.stLowHigh.nHigh; // Will be 16#C0
See also: