Plcopen Coding Guidelines Version 1.0
Plcopen Coding Guidelines Version 1.0
PLCopen
for efficiency in automation
Technical Paper
PLCopen Promotional Committee Training
As part of the
Software Construction Guidelines initiative
Sub Committee
Coding Guidelines
PLCopen Document, Version 1.0, Official Release
DISCLAIMER OF WARANTIES
The name ‘PLCopen®’ is a registered trade mark and together with the PLCopen logos owned by
the association PLCopen.
This document is provided on an ‘as is’ basis and may be subject to future additions, modifications,
or corrections. PLCopen hereby disclaims all warranties of any kind, express or implied, including
any warranty of merchantability or fitness for a particular purpose, for this moment. In no event
will PLCopen be responsible for any loss or damage arising out or resulting from any defect, error
or omission in this document or from anyone’s use of or reliance on this document.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Table of Contents
1. INTRODUCTION ....................................................................................................................9
2. HOW-TO USE THIS DOCUMENT ....................................................................................10
2.1. METHODOLOGY USED TO BUILD THIS DOCUMENT ..............................................................11
2.2. DOCUMENT STRUCTURE .....................................................................................................12
2.3. RULES DESCRIPTION FORMAT .............................................................................................13
2.4. REFERENCES.......................................................................................................................15
3. NAMING RULES ..................................................................................................................16
3.1. ADDITIONAL RULES FOR VARIABLES ONLY ........................................................................16
3.1.1. Avoid physical addresses...................................................................................................16
3.1.2. Define type prefixes for Variables (if used).......................................................................17
3.2. TASKS, PROGRAMS, FUNCTIONS BLOCKS, FUNCTIONS, VARIABLES, UDTS AND
NAMESPACES .................................................................................................................................20
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Another way of looking to the rules is via their classification and number, as shown hereunder:
Rule # Chapter Name Page
3. Naming Rules 16
4. Comment Rules 35
C1 4.1. Comments shall describe the intention of the code 36
C2 4.2. All elements shall be commented 38
C3 4.3. Avoid nested comments 39
C4 4.4. Comments may not include code 40
C5 4.5. Use single line comments 41
C6 4.6. Define comments language 43
5 Coding Practice 44
CP1 5.1. Access to a member shall be by name 44
CP2 5.2. All code shall be used in the application 45
CP3 5.3. All variables shall be initialized before being used 47
CP4 5.4. Direct addressing should not overlap 51
CP5 5.5. Applications shall be well designed 53
CP6 5.6. Avoid external variables in functions, function blocks and 54
classes
CP7 5.7. Error information shall be tested 56
CP8 5.8. Floating point comparison shall not be equality or 58
inequality
CP28 5.9 Time and physical measures comparison shall not be 59
equality or inequality
CP9 5.10. Limit the complexity of POU code 60
CP10 5.11. Avoid multiple writes from multiple tasks 63
CP11 5.12. Manage synchronization among tasks 65
PLCopen
for efficiency in automation
CP12 5.13. Physical outputs shall be written once per PLC cycle 68
CP13 5.14. POUs shall not call themselves directly or indirectly 69
CP14 5.15. POUs shall have a single point of exit 71
CP15 5.16. Read a variable written by another task only once per 72
cycle
CP16 5.17 Tasks shall only call program POUs and not Function 74
Blocks
CP17 5.18. Usage of parameters shall match their declaration mode 75
CP18 5.19. Use of global variables shall be limited 77
CP19 5.20. Usage of jump and return should be avoided 81
CP20 5.21. Function block instances should be called only once 84
CP21 5.22. Use VAR_TEMP for temporary variable declaration 86
CP22 5.23. Select appropriate data type 88
CP23 5.24. Define maximum number of input/output/in-out variables 91
of a POU
CP24 5.25. Do not declare variables that are not used 94
CP25 5.26. Data types conversion should be explicit 95
CP26 5.27. A global variable may be written only by one PROGRAM 97
CP27 5.28. Avoid deprecated features 98
6. Languages 99
L1 6.1. Define indentation 99
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
1. Introduction
Although there are coding guidelines for many programming languages, these are nearly non-
existent for the important area of industrial control, e.g. IEC 61131-3 and its PLCopen extensions.
Nevertheless, the software in the industrial environments becomes more and more important, the
software projects become larger, and the costs of errors increase. Software nowadays absorbs half
of the initial project costs and between 40 and 80% deals with maintenance over the life cycle costs
of the software.
In order to deal with the complexity of larger programs one needs modern software development
processes supporting a structured approach. Also, we need to increase the efficiency in coding via
re-use of pre-defined functionalities and to help to better understand the program over the life cycle.
With the above message PLCopen invited interested parties to join the working group of Software
Construction Guidelines. The kick-off meeting resulted in several working groups for the different
areas of interest, including their working packages (targets):
Coding Guidelines
Software quality issues and software consistency
Creating PLCopen compliant Function Blocks
Structuring and decomposition via SFC (do’s & don’ts)
Guidance for documentation in software programs
Library usage
Software development process
The key topic of the new PLCopen Software Construction Guidelines working group is the
definition of Rules, Coding Patterns and Guidance and how to use them in Industrial Automation.
These rules will be published as technical documents, as well as possibly on websites and software
tools, and marketed by PLCopen.
The results of the working group should be based on the IEC 61131-3 1st and 2nd edition standard
but should be easily extensible to the 3rd edition which was released in February 2013.
The aim of the subgroup Coding Guidelines is to define a set of rules and to provide a PLCopen
proposal how these rules can be used. Nowadays large automation companies have their own rules
but many mid-size companies or IEC 61131-3 beginners are very interested in using PLCopen
guidelines. Such guidelines will have a great impact in expanding IEC 61131-3 further in the world.
The rules will be very useful to train users and can be a good basis for universities to help them
teach IEC 61131-3 programming more efficiently.
PLCopen
for efficiency in automation
Ad 1.
The purpose of this technical paper is to increase the quality of software. This requires an
organization with certain abilities or maturity, see for instance the Capability Maturity Model for
software.
Ad 2.
The IEC 61131-3 standard specifies different languages, but if any are not used, then those
language’s rules can be ignored.
Ad 3.
Besides this document, there are other sources that describe quality rules. Think of company
standards or general standards. Larger companies have already gained experiences and these
experiences recorded in their own standard. Research the available rules. There are also overall
software quality standards, such as McCall, etc. These standards are generally not directly
applicable to PLC programs, hence this technical paper.
Ad 4.
Once the programmer has collected all the rules, then a selection can be made to create a sub-set of
rules that will be applicable to the application. Of course, the sub-set may be the full set of rules.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Do:
instance.Z[1] := 'E';
Comments: none
- Identifier: Required - used to refer to a given rule easily. The current identifier has no
semantic, it is just a number.
- Importance: Required - high, medium, low – this shows the interpretation of the group of
the effect it has on the quality of the application software (high, medium or low)
- Targeted language: Required - some rules are only valid for some languages of the
IEC61131. Either it is all languages, or the languages where the rule can be applied are
listed.
- References: Required - when rules was found or inspired by a third party document, the
reference is given in this field
- Description: Required - this is a longer description of the rule to get clear context
- Guidelines: Required - this is a help for the developer to explain how to work around the
rule violation.
- Reasoning: Required - this gives reasons why this rule is a good idea.
PLCopen
for efficiency in automation
- Exceptions: Optional - sometimes it is possible not to follow a rule for good reasons in a
given case. This field lists the good reasons not to follow the rule.
- Example: Optional - the goal of the example is to help understand the reasoning of the rule
and the guidelines to work around the violation with an explanatory example.
o Don’t – the don’t part of the example uses red color to highlight bad coding practice
o Do – the Do part of the example uses green color.
- Comments: Optional - this field is used to complete the rule description. It may be used to
link with other rules or other subjects which may be out of the scope of this document.
Only fields Exceptions, Example and Comments are optional.
PLCopen
for efficiency in automation
2.4. References
The following standards and committees are referenced from this site.
IEC 61131-3
NAME: IEC 6-1131-3 edition 2 and 3
TITLE: Programmable controllers - Part 3: Programming languages
LOCATION: International Electrotechnical Commission
WEBSITE: http://www.iec.ch/index.htm
IEC 61131-8
NAME: IEC 6-1131-8 edition 1 (and in future edition 3)
TITLE: Programmable controllers - Part 8: Guidelines for the application and implementation
of programming languages
LOCATION: International Electrotechnical Commission
WEBSITE: http://www.iec.ch/index.htm
MISRA-C
NAME: Motor Industry Software Reliability Association C
TITLE: Guidelines for the Use of the C Language in Vehicle Based Software
EDITION: 2005
WEBSITE: http://www.misra.org.uk/
PLCopen
for efficiency in automation
3. Naming Rules
3.1. Additional rules for Variables only
3.1.1. Avoid physical addresses
Identifier: Rule N1
Importance: High
Targeted languages: Ladder, Structured Text, Sequential Function Chart, Function Block Diagram
References:
IEC 61131-3 6.5.5
IEC 61131-8 3.11.2
Description: Use of hardcoded, system dependent physical addresses shall be avoided
Guideline: Using physical addresses in programs is forbidden - always define a Variable.
Reasoning: Using physical addresses makes code less portable. To use a program on a different
manufacturer, or even a different instance on the same manufacturer requires it to be edited. It also
makes programs less readable as without a symbol table for reference it can be difficult to know
what each address is used for. Later system changes are also more error prone as some access to the
physical addresses may be skipped or overlooked.
Exceptions: In some communication protocols a physical addressing is needed to assign variables
to a physical location for the order in the communication structure.
Example, use case: none
Comments: It is recommended that the VAR_ACCESS method always be used when accessing
variables in remote programmable controllers because it is then possible to use meaningful names
for variables. There is always the likelihood that I/O physical addresses will be changed if the
remote programmable controller program is modified. It may be convenient to fix VAR_ACCESS
names for a number of different programmable controller programs.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
DINT di
LINT li
USINT usi
UINT ui
UDINT udi
ULINT uli
REAL r
LREAL lr
TIME tim
LTIME ltim
DATE dt
LDATE ldt
TIME_OF_DAY / TOD tod
LTIME_OF_DAY / TOD ltod
DATE_AND_TIME / DT dt
LDATE_AND_TIME / DT ldt
STRING str
WSTRING wstr
CHAR c
WCHAR wc
BYTE by
WORD w
DWORD dw
LWORD lw
PLCopen
for efficiency in automation
ENUM e
NAMED e
SUBRANGE sb
ARRAY a
STRUCT st
Type STRUCT ts
Reference ref
FUNCTION BLOCK fb
PROGRAM prg
CLASS cls
Note: ENUM and NAMED are proposed to use the same prefix.
For arrays, the datatypes does not have to be included.
As alternative, all user derived datatypes can be shown with one prefix: udt, no matter if it is an
ENUM, NAMED or any other.
Comments: none
PLCopen
for efficiency in automation
Keywords / reserved word list of IEC 61131-3 Ed.3 starting with a letter:
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Don't:
STARTMOTOR(); //Don't use all capitals as it confuses with constants.
startmotor(); //Don't use the same case as it is difficult to read
PLCopen PC2 Training Software Construction Guidelines © PLCopen (2016)
Coding Guidelines V.1.0 April 20, 2016 page 22/127
®
PLCopen
for efficiency in automation
Do:
StartMotor(); //UpperCamelCase makes it quick to read
Don’t:
Declaration of a structured data type (IEC 61131-3 6.4.4.6.1 Structured data type))
TYPE
ANALOG_SIGNAL_RANGE:
(BIPOLAR_10V,
UNIPOLAR_10V);
ANALOG_DATA: INT (-4095 .. 4095);
ANALOG_CHANNEL_CONFIGURATION:
STRUCT
RANGE: ANALOG_SIGNAL_RANGE;
MIN_SCALE: ANALOG_DATA;
MAX_SCALE: ANALOG_DATA;
END_STRUCT;
END_TYPE
Do:
TYPE
ANALOG_SIGNAL_RANGE:
(Bipolar10Volt,
Unipolar10Volt);
ANALOG_DATA: INT (-4095 ... 4095);
ANALOG_CHANNEL_CONFIGURATION:
STRUCT
Range: ANALOG_SIGNAL_RANGE;
MinScale: ANALOG_DATA;
MaxScale: ANALOG_DATA;
END_STRUCT;
END_TYPE
Do:
Naming example from PLCopen Motion Control
Over the years the suite of Motion Control specifications was defined within PLCopen. Consistency
in the naming conventions was realized after 2010.
Function Blocks: Prefix MC_, and capitalize first letter of each word, and no hyphenation between
words. Example: MC_MoveAbsolute
Enum elements: prefix to name is mc, and each word starts with a capital letter. So
mcNameName2. Example mcPositive, mcBlendingLow.
Data types and Structures: Prefix MC_ (except AXIS_REF), capitalized and underscore between
groups of words. Example: AXIS_REF; MC_BUFFER_MODE, MC_TP_REF, MC_INPUT_REF.
PLCopen
for efficiency in automation
Inputs and outputs: No prefix. Each word start with a capital letter. No hyphen between words.
Examples: Busy, CommandAborted, Master, BufferMode
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
VAR_GLOBAL
GlobalCalculationResult: REAL; // Global Variable Declaration
END_VAR
.....
Comments: none
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Do:
FUNCTION StartFeeding: BOOL; // Name explains function
Don't:
VAR
Go : BOOL; // too short
aaa: INT; // meaningless name
MaximumTemperatureForTheThermocoupleInput: REAL; //Too long
END_VAR;
Do:
VAR
i: INT; // FOR loop counters and indexes only
MaxTCTemperature: REAL; // Only use clear abbreviations (TC -=
Thermocouple)
END_VAR;
Comments: None
PLCopen
for efficiency in automation
NAMESPACE SomeCompany.XseriesCPU
FUNCTION_BLOCK MyCalculation // 2) The same name is used also.
...
END_FUNCTION_BLOCK
PLCopen
for efficiency in automation
PROGRAM MainProgram
VAR MyCal : MyCalculation;
// Usage of short type name above becomes ambiguous.
// Need to write "SomeCompany.XseriesCPU.MyCalcuration" for 2).
// No means to explicitly refer to 1).
END_PROGRAM
END_NAMESPACE
Do: Nothing is directly declared in the global namespace. All namespaces start with organization name.
NAMESPACE SomeCompany.XseriesCPU
USING PLCopen.Motion;
USING PLCopen.Safety;
PROGRAM MainProgram
USING OMAC.OPW.PackML3;
...
END_PROGRAM
PROGRAM CommProgram
USING IEC_61131_5;
...
END_PROGRAM
END_NAMESPACE
Comments: None
PLCopen
for efficiency in automation
Don't:
départ := true; // .... Lines of code
depart := false; //Using the special character 'é', leads to a
confusion between mnemonics.
Do:
Depart := True; // No accent in the variable name
// Autorise le départ du wagonnet // Accent in the
comment-
Comments: None
PLCopen
for efficiency in automation
3.2.7. Different element types should not bear the same name
Identifier: Rule N9
Importance: Medium
Targeted languages: All
References:
IEC 6-1131-3 6.9.1
MISRA-C_2004
JSF++ 135
Description: The elements types Tasks, Programs, Functions Blocks, Functions, Variables and
User Defined Types should not share the same name in the same scope.
Guideline: Do not use identical names for any tasks programs, functions and function blocks,
variables, UDTs and name spaces.
Reasoning: Using the same name for different object types would make code difficult to read.
Even if compilation is possible, errors in readability can introduce program mistakes.
Exceptions: none
Example:
Don't:
VAR_GLOBAL
MyCalculation: REAL; // Global Variable Declaration
END_VAR
Comments: none
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
4. Comment Rules
This chapter is related to commenting the program and the application so that it is easier to read,
understand and modify. The following guidelines are good practices about writing good comments.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Example:
Don't: Do:
Code blocks with no comments: Branch comments should add value:
IF IsValid(TCInput) THEN
IF IsValid(TCInput) THEN
// Scaling of the
Temperature := TCInput * //Temperature
TCScale + TCOffset;
Temperature := TCInput *
ELSE TCScale + TCOffset;
TCBadQuality := TRUE; ELSE
// Some error reading the
END_IF; // temperature value
TCBadQuality := TRUE;
Comments that add no value over the code:
END_IF;
IF IsValid(TCInput) THEN
// TCInput is valid
Whole block explained well by a single
Temperature := TCInput *
TCScale + TCOffset; comment:
ELSE // Check for a new maximum
// TCInput is not valid // temperature reading
CBadQuality := TRUE; MaxReading := nReadings[0];
END_IF; FOR index:=1 TO 10 DO
IF nReadings[Index] > MaxReading
THEN
MaxReading := nReadings[Index];
END_IF;
END_FOR;
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Guideline: In the released versions of programs there should be no nested comments, even if it's
possible during development and debug phases.
Reasoning: Editing of nested comments is a common source of accidently mismatching comment
delimiters and unintentionally commenting out code. This editing error can be missed by the
compiler if valid code can still be compiled.
As a general principle Code in comment should not be used for version control or configuration
management purposes; proper tools should be used for that.
Exceptions: None
Example:
Don't:
(* Any comment with the end marker has been forgotten
Critical_section_that_must_be_executed_which_is_found_in_the
comment();
(* <- The start marker comment is commented because the end marker
of the previous comment has been forgotten *)
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
*)
(* (* NESTED COMMENTS *) *)
Do:
<statement>; // End of line comment
// Block Comment
// <the following block...>
// <...>
<statement>;
PLCopen
for efficiency in automation
Comments: For existing code with (*, one can use the /* to exclude portions of code to
differentiate, if the system allows this.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
5. Coding Practice
5.1. Access to a member shall be by name
Identifier: Rule CP1
Importance: High
Targeted languages: All
References:
Misra-C_2004 rule 3.5
Description: When referencing user defined types like structures in the code, the references shall
be done using the member name and not using an offset between the beginning of the structure and
the position of the member in memory.
Guideline: Access to a member by offset should be avoided.
Reasoning: Referencing by offset is difficult to read, understand and maintain. If for some reason
one another member is inserted before, then all offsets of the following members have to be
recalculated. Moreover it relies on memory implementation (like big endian vs. little endian) and
especially, the offset of a given structure depends on the PLC type: the alignment rules are not
always the same.
Exceptions: None
Example:
Don't:
STRUCT EXAMPLE_STRUCT
X : DINT
Y : BOOL;
Z : STRING[40];
END_STRUCT;
VAR
instance : EXAMPLE_STRUCT AT %MW500;
END_VAR
// Write the first character of Z:
%MW504 := 'E';
Do:
instance.Z[1] := 'E';
Comments: none
PLCopen
for efficiency in automation
Unreferenced functions :
o re-use of an already existing application to create a new application slightly different
o developer mistake forgetting to call part of the application during development
o part of the code used in a specific environment : testing, simulation of missing
hardware
Code not reachable unconditionally - techniques used by developer to bypass part of the
code :
o due to unconditional go to followed by code without called label
o condition always false or true
Exceptions: A dead code with a nice comment delimiting and explaining correctly the reason why
the code was bypassed may be used. In such case, the code section should be small enough so that a
developer sees as evidence that it is dead code.
Example:
Do:
...
//
// The following section handles the optional device FOO.
// It is bypassed for application THIS_PARTICULAR_APPLICATION
because
// this device is not loaded for this application
IF FALSE THEN
// unreachable code
...
END_IF;
PLCopen
for efficiency in automation
Comments: none
PLCopen
for efficiency in automation
StateLastPosition := 50;
SpeedAverage := 0.0;
PLCopen PC2 Training Software Construction Guidelines © PLCopen (2016)
Coding Guidelines V.1.0 April 20, 2016 page 47/127
®
PLCopen
for efficiency in automation
...
END_PROGRAM
IEC 61131-3 also allows the user to specify default initial values for user-defined types. For
instance, consider a type declared by:
TYPE TempLimit : REAL:= 250.0; END_TYPE
Any declared variable of this new type TempLimit is initialized with the default value of 250.0
instead of 0.0 as would be the normal case for all REAL data. Thus, in the following declaration,
the variable BoilerMaxTemperature is initialized to 250.0, while the variable PipeMaxTemperature
is initialized to 0.0. If the value of zero is not a reasonable maximum temperature for the pipeline,
its correct value has to be set before the first usage of the variable. Forgetting this will cause
problems. In the present example, the maximum temperature for the boiler is initialized with a
proper default initial value. There is no need for a set-up before the first usage, which greatly
simplifies a programmable controller program and increases software reliability.
VAR_GLOBAL
BoilerMaxTemperature: TempLimit;
PipeMaxTemperature: REAL;
END_VAR
Comments: More examples of defining default initial values for user-defined types:
PLCopen
for efficiency in automation
END_STRUCT ;
END_TYPE
Initialization of derived structured data types, e.g.:
TYPE ANALOG_CHANNEL_CONFIG :
ANALOG_CHANNEL_CONFIGURATION
:= (MIN_SCALE := 0, MAX_SCALE := 4000);
END_TYPE
CONFIGURATION Cell_1
VAR_GLOBAL
Gvar1 : INT:= 5;
Gvar2 : INT:= 0;
PLCopen
for efficiency in automation
END_VAR
PLCopen
for efficiency in automation
// Wrong example
Temperature : INT AT %MW451;
... else where in the database definition
Level: REAL AT %MW450;
Temperature := %IW56;
IF Temperature > 56 THEN
StartFans;
END_IF;
PLCopen
for efficiency in automation
// Right example
Temperature : INT AT %MW444;
... else where in the database definition
Level: REAL AT %MW450;
// the direct addresses do not overlap
Temperature := %IW56;
IF Temperature > 56 THEN
StartFans;
END_IF;
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Guideline:
Functions, Function Blocks and Classes should not use external variables.
A good alternative to using external references to global variables can be to extend the parameter
list, and pass the variables needed for access.
Reasoning:
Good design principles allow Function, Function Blocks and Class POUs to be easily reused. The
inner workings are sometimes unknown to the user, and even unexposed. Using any external
reference detracts from or prevents reusing the POU. For example if a function accesses 10 external
references, then when you copy the function to a new project you must also copy the accompanying
global variable definitions including the code affecting these variables.
Function Blocks and Classes also have 'instances' with their own data. Directly using external
references can make it impossible to have multiple instances.
Encapsulation of data can minimize integration testing and remove functional testing for pre-tested
POUs as the known behavior cannot really change. However using data in external references
means the functionality now depends on that external data so requires full retesting to ensure no
issues have been introduced.
Also, using external references increases the chance of different POUs performing multiple writes
to the same variable. This is related to rule CP26 "A global variable may be written only by one
POU" and rule CP15 "Read a variable written by another task only once per cycle" so
avoiding externals can also avoid these accidental uses, which can be very difficult to find and
debug.
In addition, the code gets more complex, and the need for using and external variable can be a
signal that the program is not coherent and refactoring is necessary.
Finally, such a practice can introduce side-effects, like a function returning different results with the
same inputs, which makes it hard to verify correct operation. There should be a very good and well
documented reason for any such usage of external data.
PLCopen
for efficiency in automation
Example:
Don't:
FUNCTION CommandMotor
VAR_INPUT
Enable : BOOL;
Default: BOOL;
END_VAR;
VAR_OUTPUT
Command : BOOL;
END_VAR;
VAR_EXTERNAL
ModeAuto : BOOL;
END_VAR;
Do:
FUNCTION CommandMotor
VAR_INPUT
Enable : BOOL;
Default: BOOL;
ModeAuto : BOOL; //Here the variable is passed as a parameter
END_VAR;
VAR_OUTPUT
Command : BOOL;
END_VAR;
Command := Enable AND NOT Default AND ModeAuto;
END_FUNCTION;
Comments: This rule also applies to PROGRAM POUs when the programming systems support
this. PROGRAM is a reusable POU type which can have input/output/in/out parameters. See Table
47 No.2, Table 62 No.89 of IEC 61131-3.
PLCopen
for efficiency in automation
+---------+
| ADD |
|---------| En Eno |-
Result -| i1 Out |- CriticalThreshold
10000 -| i2 |
+---------+
In this case the result is used directly without checking the error information and then the
CriticalThreshold is changed even if there was an error raised by Instance call.
PLCopen
for efficiency in automation
Do:
+----------+
| Instance |
Cond -|En Eno |-
Eff1 -|P1 Out |- Result
Eff2 -|P2 xError |- xError
-|P2 iError |- iError
| |
+----------+
+---------+
| xError | ADD |
|---| |---| En Eno |-
| Result -| i1 Out |- CriticalThreshold
10000 -| i2 |
+---------+
In this case, the error information generated by the Instance call is effectively used and then the
CriticalThreshold is not changed.
Comments: None.
PLCopen
for efficiency in automation
Don't:
IF TEMP - OLD_Temp = 0.1 THEN
// execution of this branch is sensitive to rounding errors
....
END_IF;
Do:
IF TEMP - OLD_TEMP < 0.1 THEN
// executed code
END_IF;
or
Comments: None
PLCopen PC2 Training Software Construction Guidelines © PLCopen (2016)
Coding Guidelines V.1.0 April 20, 2016 page 58/127
®
PLCopen
for efficiency in automation
Don't:
IF Distance – InitialPosition = 12 THEN
// execution of this branch is sensitive to missing measured
// values
....
END_IF;
Do:
IF Distance – InitialPosition - 12 < ERROR_MARGIN THEN
// executed code
END_IF;
or
Comments: None
PLCopen
for efficiency in automation
Number of Statements 18
McCabe complexity of 12
Prater complexity of 3,89
Halstead complexity of 44,9
Elshof complexity of 0,14 (the lower the number, the more complex is the function).
FUNCTION_BLOCK CHARCURVE
VAR_INPUT
IN:INT;
N:BYTE;
END_VAR
VAR_IN_OUT
P:ARRAY[0..10] OF POINT;
END_VAR
VAR_OUTPUT
OUT:INT;
ERR: BYTE;
END_VAR
VAR
PLCopen
for efficiency in automation
I:INT;
END_VAR
IF N > 1 AND N < 12 THEN
ERR:=0;
IF IN<P[0].X THEN
ERR:=2;
OUT:=DINT_TO_INT(P[0].Y);
ELSIF IN>P[N-1].X THEN
ERR:=2;
OUT:=DINT_TO_INT(P[N-1].Y);
ELSE
FOR I:=1 TO N-1 DO
IF P[I-1].X>=P[I].X THEN
ERR:=1;
EXIT;
END_IF;
IF IN<=P[I].X THEN
EXIT;
END_IF
END_FOR;
IF ERR=0 THEN
OUT:=DINT_TO_INT(P[I].Y-(P[I].X-IN)*(P[I].Y-P[I-
1].Y)/(P[I].X-P[I-1].X));
ELSE
OUT:=0;
END_IF;
END_IF
ELSE
ERR:=4;
END_IF;
Do:
The changed function block with one (private) help method CalculateOut is far less complex:
Number of Statements 12
McCabe complexity of 8
Prater complexity of 2,25
Halstead complexity of 19,9
Elshof complexity of 0,32
OUT:=0;
ERR:=0;
iIndexFound := -1;
FOR I := 1 TO N-1 DO
IF iIndexFound < 0 AND ERR = 0 THEN
IF P[I-1].X >= P[I].X THEN
PLCopen PC2 Training Software Construction Guidelines © PLCopen (2016)
Coding Guidelines V.1.0 April 20, 2016 page 61/127
®
PLCopen
for efficiency in automation
ERR := 1;
ELSIF IN <= P[I].X THEN
iIndexFound := i;
END_IF
END_IF
END_FOR;
IF ERR = 0 THEN
OUT := CalculateOut (P[iIndexFound], P[iIndexFound -1]);
ELSE
OUT := 0;
END_IF;
Comments:
Literature references:
Thomas J. McCabe: "A Complexity Measure" in: IEEE Transactions on Software
Engineering, Vol 2, 1976.
Prater, R. E.: "An axiomatic theory of software complexity metrics", in Computer Journal,
Vol. 27, 1984
Halstead, M.: "Elements of Software Science", Elsevier North-Holland, Amsterdam, 1977
Elshof, J.: "An Analysis of Commercial PL/I Programs", IEEE Transactions on Software
Engineering, Vol. 2, 1976
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Example:
Don't:
Imagine any simple case where a programmer has created a 'LoopCounter' Global Variable for
general use throughout their Main program. Now imagine a second developer has copied and
pasted a block to a priority program, that happens to run in a different task:
VAR_GLOBAL
LoopCounter;
END_VAR
Priority Program:
Main Program:
...
...
MaxReading := Reading[0];
FOR LoopCounter := 0 TO 10 DO
FOR LoopCounter := 1 TO 100 DO
IF ValveWarning[LoopCounter] == TRUE THEN
IF Reading[LoopCounter] > MaxReading THEN
ProcessWarning := TRUE;
MaxReading := Reading[LoopCounter];
END_IF;
END_IF;
END FOR;
END FOR;
During execution of the main program, while inside the FOR loop the Priority Program may start to
execute at any time (while the LoopCounter may be any value from 0 to 10). At the end of the
Priority Program the global variable "LoopCounter" is left with the value of 100 when execution
returns to the Main Program but the FOR loop now ends at the next iteration without completing
the rest of the iterations. There is also potential for the code to execute now on the wrong element
or even worse attempt access data beyond the bounds of the array.
Do:
In the above example, we can solve the problem by avoiding the multiple writes to LoopCounter by
creating 2 program variables with local scope. For clarity these should be defined with different
names.
Comments: For more information about synchronizing the execution of tasks see Manage
synchronization among tasks (Rule CP11), page 64.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PROGRAM Fast_Acquisition
VAR_EXTERNAL
ClearSubTotalCount : BOOL; // This is actually used as input
SubTotalCount : INT; // This is actually used as output
END_VAR
VAR_INPUT
SignalInput : BOOL; // input signal to count rising-edge
END_VAR
VAR
Old_ClearSubTotalCount : BOOL := FALSE;
END_VAR
PLCopen
for efficiency in automation
CONFIGURATION CELL_1
VAR_GLOBAL
SubTotalCount : INT;
ClearSubTotalCount: BOOL;
END_VAR
RESOURCE STATION_1 ON PROCESSOR_TYPE_1
TASK SLOW_1(INTERVAL := t#200ms, PRIORITY := 2) ;
TASK FAST_1(INTERVAL := t#10ms, PRIORITY := 1) ;
PROGRAM MainAquisitionInst WITH SLOW_1 : Main_Acquisition();
PROGRAM FastAcquisitionInst WITH FAST_1 : Fast_Acquisition(SignalInput
:= %I1.1);
END_RESOURCE
END_CONFIGURATION
Comments:
This rule is only for PLC system of "Preemptive scheduling" implementation (See IEC 61131-3,
Table 63, No.5b).
Some vendor provides similar system-defined functions.
It may be possible to avoid the need for synchronization. In the case that multiple PROGRAM
instances all need to exchange data synchronously from the logic point of view, such PROGRAMs
should be changed into FUNCTION_BLOCK and one PROGRAM should be added instead to call
the FUNCTION_BLOCK instances synchronously.
As using vendor-specific "lock" feature temporarily blocks switching execution to the task with
higher priority. It can make periodic task not to be in time for the specified period.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Do:
In this implementation, the recursion was removed and replaced by an iteration using FOR
FUNCTION Factorial : INT
VAR_INPUT
X : INT;
END_VAR
VAR_LOCAL
Acc : INT;
END_VAR
FOR I IN 1..X DO
Acc := Acc * X;
END_FOR;
Factorial := Acc;
END_FUNCTION;
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
5.16. Read a variable written by another task only once per cycle
Identifier: Rule CP15
Importance: High
Targeted languages: All
References: None
Description: In one task, multiple reading of a variable written by another task shall be avoided.
The other task is able to be executed at any time between the two readings and so the two read
values may be different. The program may behave in a non-deterministic way.
Guideline: To avoid this situation, in a task that reads a variable written to in another task, that
variable should be copied into a local variable which is then exclusively used. This will ensure that
the value won't unexpectedly change and so make program execution more predictable.
This copy could be done automatically by a programming support environment supporting the
following features from IEC 61131-3,
Table 47, No.2a "Declaration of inputs of a program"
Table 47, No.2b "Declaration of outputs of a program "
Table 62, No.8b "Connection of GLOBAL variables to PROGRAM inputs"
Table 62, No.9b "Connection of PROGRAM outputs to GLOBAL variables"
When the declaration of program POU input/output variables, the global variables are copied to the
input variables of the program before execution, and output variables are copied to the global
variables after the execution. The value of input variables is never overwritten during the execution
of the program in that cycle. Also output variables are never reflected to the global variables until
the cycle execution of the program finishes.
Reasoning: In a program successive reading of a variable declared externally should be consistent.
However, in the case of a variable written to by another task, this other task can be executed
between two reads due to task switching.
Before running the process, the PLC is sampling the process inputs by copying the input values at a
given time into an image memory. This is for the same reason: having constant input during a
process execution.
Exceptions: None
Example:
Don't:
In this example every time an error flag is raised, an error code is also raised to identify which part
of the process is in error. The MachineError flag is generated from a high priority task that can
preempt the main program at every time.
PLCopen
for efficiency in automation
Main Program:
….
Priority Program:
If execution of the main program is interrupted after rung 27, but before rung 30, the Priority
Program may start to execute overwriting global variable "ErrorID". When execution returns to
the Main Program the remaining rungs are evaluated, with the possibility that none of the
"ProcessnError" bits are set.
This is a situation the developer of Main Program will not have realistically catered for.
Do:
The solution consists in reading MachineError and ErrorId only once and copying their value in a
variable image. Then it ensures that ProcessnError will be consistent. The case where no
ProcessnError is flagged when MachineError is flagged is not possible anymore.
If the Programming Support Environment allows it, the input/output of the POU program should be
explicitly declared. Then the system takes care of this copy automatically.
Comments: None
PLCopen PC2 Training Software Construction Guidelines © PLCopen (2016)
Coding Guidelines V.1.0 April 20, 2016 page 73/127
®
PLCopen
for efficiency in automation
5.17. Tasks shall only call program POUs and not Function Blocks
Identifier: Rule CP16
Importance: High
Targeted languages: Ladder, Structured Text, Sequential Function Chart, Function Block Diagram
References:
IEC 61131-8 Sections 3.5.4 and 3.12.6
IEC 61131-3 Section 2.7.2
Description: IEC Tasks shall not be configured to call Functions or Function Blocks directly. They
shall only be configured to call program POUs.
Guideline: Tasks shall call program POUs only. Direct association of tasks to such function blocks
should be avoided.
Reasoning: This is recommended to avoid ambiguity in determining the execution control of
indirectly referenced function block instances. The association of tasks with function block
instances and its effects on data concurrency are described in 2.7.2 of IEC 61131-3. The
programmer should be aware of the fact that use of this feature may produce data consistency errors
during program run time. The guidelines provided by the IEC 61131-3 implementer should be
consulted to determine the mechanisms provided to assure data consistency. Since these
mechanisms are implementation dependent, programs using this feature may not be portable
between different IEC 61131-3 compliant systems
Exceptions: None
Example:
Don't: (example from Figure 20 of IEC61131-3. FB1 and FB2 should not be assigned directly to
TASKs)
Comments: None
PLCopen
for efficiency in automation
Exceptions: None
Example, use case:
Comments:
It is illegal to attempt to pass an output from a Function to an In-Out parameter of a Function
Block:
ACC1
+---+ +-------+
X1---| * | | ACCUM | ILLEGAL USAGE:
X2---| |---|A-----A|---ACC In-out A is not a variable
+---+ | | or function block name
X3-----------|X |
+-------+
PLCopen
for efficiency in automation
ACC1
+-------+
| ACCUM | ILLEGAL USAGE:
2.0---|A-----A|---2.0 In-out A is not a variable
| | or function block name
---|X |
+-------+
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Note:
In this "Don't" example, each PROGRAM does not declare input/output variables and accesses
global variables via external variables. To know the data flow among PROGRAM instances, the
logic of each PROGRAM body need to be examined.
Do:
RESOURCE Station1 ON ProcessorTypeA
VAR_GLOBAL
//-- 1) Variables for inter-PROGRAM communication
MainProgDone: BOOL := TRUE;
InitDone: BOOL := FALSE;
InitError: BOOL := FALSE;
//-- 2) System-defined variables to be accessed via VAR_EXTERNAL
CurrentTime : TIME;
CPUErrorStatus : ErrorStats;
//-- 3) Variables exchanged between tasks
HighSpeedCounter : DINT;
//-- 4) I/O and communication variables
HSPulse : BOOL AS %I4.5;
END_VAR
TASK FastTask(INTERVAL := t#1ms, PRIORITY := 1);
TASK SlowTask(INTERVAL := t#10ms, PRIORITY := 15);
PROGRAM ProgInst1 WITH FastTask
: Program1(Execute := MainProgDone,
HighSpeedCounter := HighSpeedCounter,
Done => InitDone,
PLCopen
for efficiency in automation
Note:
Program instance declaration above explicitly represents data flow among PROGRAM instances
shown below. (This diagram is NOT a formal graphical representation of IEC 61131-3)
PLCopen
for efficiency in automation
Comments:
The rules below also relate to the usage of global variables:
1. Rule 5.27 A global variable may be written only by one PROGRAM
2. Rule 5.11 Avoid multiple writes from multiple tasks.
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
+---| |---->>J26 || |
| w x || flg y z |
+---| |---------+---------(S)---+ +---| |---| |-------------(S)---+
| || |
J26:
Conditional code can be controlled with Boolean
| flg logic
+---|/|---->>J27 | IF NOT flg AND w THEN
| y z | z := TRUE;
+---| |---------+---------(S)---+ ELSIF flg AND y THEN
| | x := TRUE;
J27: END_IF;
| | Conditional code can better be expressed in ST,
especially more complex and nested structures
PLCopen
for efficiency in automation
Comments: none
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Motion Function Blocks instances are sometimes called multiple times per PLC scan, for
example when Blending between steps or using "BufferMode" to stack up consecutive
commands.
Example:
Don't: calling twice a raising edge function block: the second call doesn't see any more the rising
edge it-self.
FUNCTION_BLOCK Rising_Edge
VAR_INPUT
S : BOOL;
END_VAR;
VAR
Old_State : BOOL;
END_VAR;
VAR
InputDetectionForDashboardButtonA: Rising_Edge;
InputDetectionForDashboardButtonB: Rising_Edge;
END VAR;
InputDetectionForDashboardButtonA(InputFilterA);
...
InputDetectionForDashboardButtonA(InputFilterB);
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
VAR_INPUT
newValue: REAL;
END_VAR
VAR
values: ARRAY[1..10] OF REAL;
END_VAR
VAR_TEMP
index: INT;
END_VAR
currentValue := values[ 1 ];
FOR index := 1 TO 10 DO
values[ i ] := values[ i + 1 ];
END_FOR
values[ 10 ] := newValue;
END_FUNCTION_BLOCK
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
If a programmable controller program has to count something and the counts are expected to
be in the range from 0 to 1000, a variable of type SINT or USINT cannot be used, since
their value ranges only extend from -128 to +127 for SINT and from 0 to 255 for USINT. A
reasonable data type for this purpose would be UINT. This has a sufficient value range and
the usage of an unsigned integer type also makes it clear that negative values are not
expected
Any code that uses a CASE statement should strongly consider if the expression variable
should be an enumerated type, testing against the semantic value rather than numeric value
An enumerated data type restricts the values of variables of the type to a user-defined set of
identifiers. As an example consider
TYPE Color : ( Red, Yellow, Green );
END_TYPE
...
VAR_GLOBAL brickColor : Color; END_VAR
Here a new type Color is defined. It may only have three values - Red, Green, or Yellow.
IEC 61131-3 does not define numerical values to which these enumerated values may
correspond. There also is no conversion function to and from enumerated types to integral
types. The values only have to be distinct and reproducible. An assignment of a value to the
variable brickColor is possible only if one of the defined color values is used. All other
values are flagged as errors
Another enumerated data types example:
TYPE ANALOG_SIGNAL_TYPE : (SINGLE_ENDED, DIFFERENTIAL) ;
END_TYPE
Even though there are only 2 values, using enumeration make the code easier to read and
also extend.
Subrange data types can limit the range of permissible values, e.g.:
TYPE ANALOG_DATA : INT (-4095..4095) ; END_TYPE
Array data types group data of the same data type, e.g.:
TYPE ANALOG_16_INPUT_DATA : ARRAY [1..16] OF ANALOG_DATA ;
END_TYPE
Structured data types group data of the different data types e.g.:
TYPE
ANALOG_CHANNEL_CONFIGURATION :
STRUCT
RANGE : ANALOG_SIGNAL_RANGE ;
MIN_SCALE : ANALOG_DATA ;
MAX_SCALE : ANALOG_DATA ;
END_STRUCT ;
ANALOG_16_INPUT_CONFIGURATION :
STRUCT
SIGNAL_TYPE : ANALOG_SIGNAL_TYPE ;
FILTER_PARAMETER : SINT (0..99) ;
CHANNEL : ARRAY [1..16] OF
ANALOG_CHANNEL_CONFIGURATION ;
END_STRUCT ;
END_TYPE
PLCopen
for efficiency in automation
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Do:
(* Graphical representation of FB declaration *)
+-------------------------+
| MyFunctionBlock |
BOOL--|Enable CylinderOut1|--DT_CylinderOut
INT--|Input2 CylinderOut2|--DT_CylinderOut
INT--|Input3 CylinderOut3|--DT_CylinderOut
ARRAY[1..5] OF DT_EncoderInput--|EncoderInputs Error|--BOOL
| ErrorID|--DWORD
+-------------------------+
(* Textual declaration of FB *)
FUNCTION_BLOCK MyFunctionBlock
VAR_INPUT
Enable : BOOL;
PLCopen
for efficiency in automation
Input2 : INT;
Input3 : INT;
EncoderInputs : ARRAY[1..5] OF DT_EncoderInput
END_VAR
VAR_OUTPUT
CylinderOut1 : DT_CylinderOut;
CylinderOut2 : DT_CylinderOut;
CylinderOut3 : DT_CylinderOut;
Error : BOOL;
ErrorID : DWORD;
VAR PUBLIC
ConfigParams : DT_MyFBConfiguration //Static configuration
parameter.
// This variable is not shown as pin but can be written
// separately before calling the FB instance.
END_VAR
END_FUNCTION_BLOCK
TYPE
DT_MyFBConfiguration : STRUCT
Param1 : DINT;
Param2 : DWORD ;
Param3 : BOOL;
Param4 : INT;
Param5 : STRING[32];
Param6 : BOOL;
Param7 : DINT;
Param8 : BOOL;
Param9 : BOOL;
END_STRUCT
DT_EncoderInput : STRUCT
IsReverse : BOOL := FALSE;
Reset : BOOL := FALSE;
Count : INT := 0;
END_STRUCT
DT_CylinderOut : STRUCT
Solenoid1 : BOOL;
Solenoid2 : BOOL;
Solenoid3 : BOOL;
Solenoid4 : BOOL;
PilotLamp : BOOL;
DumpParam : DINT;
END_STRUCT
END_TYPE
Comments: none
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
I := I * J;
// If it compiles (compiler not compliant to IEC61131 Ed.3rd)
// Result can be either 0 or 5 depending on the way the compiler
// is interfering types
Do either:
I := I * REAL_TO_INT(J);
PLCopen
for efficiency in automation
or:
I := REAL_TO_INT(INT_TO_REAL(I) * J);
Note that the result can differ between the 2 cases. Also if there is no explicit typecast the user does
not know which solution is chosen by the compiler.
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
6. Languages
6.1. Define indentation
Identifier: Rule L1
Importance: Low
Targeted languages: Structured Text, Instruction List, textual variable declaration
References:
JSF++ 44
Description: You may define your use of indentation, and use consistently throughout the project.
Guideline: Use 4 spaces for indentation level.
Reasoning: Indenting code aids readability, particularly for conditional and loop statements. Small
indents (e.g. 1-2 spaces) are not always clear. Large indents (e.g. 8 spaces) can mean that nested
statements create code too wide for the screen.
Exceptions: none
Example, use case:
Don't: the nested IF instruction should be at the same indentation than Sort call:
IF sizeListToSort < 0 THEN
Sort (numberElements := sizeListToSort,
direction := 2,
idEse := idEse,
Ese := Ese,
status => statusTemp);
Do:
// Initialisation
IF Dem_froid OR Rep_chaud OR Prem_cycle THEN
Cmd_vanne_remplissage.Temps_ma := 15;
Cmd_vanne_vidange.Temps_ma := 15;
Local := true;
ELSE
// Grafcet
init_graph := false;
END_IF;
Comments: See also 6.6.7 Define use of tabs, page 120.
PLCopen
for efficiency in automation
Do:
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
| a b c d |
+--( )--| |--+--( )---( )--+
| | e |
| +-----( )-----+
| |
| TRUE a |
+--| |---( )--+
| |
| a b c |
|--| |--| |--+--( )--+
| | d |
| +--( )--+
| | e |
| +--( )--+
| |
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
+---------+
| |
| +=====+
| || A ||
| +=====+
| |
| + t1
| |
| ===+====+====+===
| | |
| +-----+ +-----+
| | B | | C |
| +-----+ +-----+
| | |
| | *--------+
| | | |
| | + t2 + t3
| | | |
| | +---+ +---+
| | | D | | E |
| | +---+ +---+
| | | |
| ===+====+====+=== |
PLCopen PC2 Training Software Construction Guidelines © PLCopen (2016)
Coding Guidelines V.1.0 April 20, 2016 page 104/127
®
PLCopen
for efficiency in automation
| | |
| + t4 + t5
| | |
| +---+ +---+
| | F | | G |
| +---+ +---+
| | |
| + t6 + t7
| | |
+----------+-------------+
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
end_if ;
Do:
IF (Pump.Temperature >= 90) AND Pump.Running THEN
Pump.SpeedMode := SLOW;
END_IF;
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Don't: Do:
// Count number of elements in error // Count number of elements in error
Count:= 0; Count:= 0;
FOR index:= 1 TO 20 DO FOR index:= 1 TO 20 DO
IF NOT bError[index] THEN IF bError[index] THEN
// Not in error so skip to next element // Another element in error
CONTINUE; Count:= Count + 1;
END_IF; END_IF;
Count:= Count + 1; END_FOR;
END_FOR;
FOR loops using EXIT can iterate less times than expected. Rewrite the loop to expect an early
exit:
Don't: Do:
J:= 101;
index:= 1;
FOR index := 1 TO 100 DO
WHILE index <= 100 AND WORDS[index] <>
IF WORDS[index] = 'KEY' THEN
'KEY' DO
J:= index;
index:= index+1;
EXIT;
END_WHILE;
END_IF;
J:=index;
END_FOR;
PLCopen
for efficiency in automation
Do:
PLCopen
for efficiency in automation
Do:
// This loop is fine
i:= 0;
WHILE i <= 10 AND WORDS[i] <> 'KEY' DO
i := i + 2;
END_WHILE;
j := i;
PLCopen
for efficiency in automation
Comments: After the execution of the loop the value of the control variable is implementation
specific.
PLCopen
for efficiency in automation
6.5.5. FOR loop variable usage should not be used outside the FOR loop
Identifier: Rule L13
Importance: Medium
Targeted languages: ST
References:
IEC61131-3 (ed3) 7.3.3.4.2
JSF++ Av Rule 136
Description: The IEC 61131-3 standard states: "The value of the control variable after completion
of the FOR loop is Implementer specific."
Guideline: Don't use the control variable outside the FOR loop, otherwise, the WHILE or REPEAT
constructs can be used.
Reasoning: Since the value of the control variable outside the loop is implementation depended
using it would make the code non portable.
Exceptions: None
Example:
Don't:
FOR i := 0 TO 100 BY 2 DO
IF Words[ i] = 'Key' THEN
EXIT;
END_IF;
END_FOR;
Do:
// This loop is fine
KeyAtIndex := 101;
FOR i := 0 TO 100 BY 2 DO
IF Words[i] = 'Key' THEN
KeyAtIndex := i;
END_IF;
END_FOR;
PLCopen
for efficiency in automation
END_IF;
Comments: None
PLCopen
for efficiency in automation
Do:
// Use formal argument list: MyFunction will not modify Bee
A := MyFunction(In:=Bee, Max:=5);
PLCopen
for efficiency in automation
Comments: None
PLCopen
for efficiency in automation
Misra C 12.1
JSF++ Rule 213
Description: When using operators with a similar precedence, use parenthesis to disambiguate.
Guideline: In a structured text expression using operators AND/OR/= or +/-, use parenthesis to
specify explicitly the order of evaluation.
Reasoning: The precedence of operators may change between implementations. When a developer
looks at an ambiguous expression, time may be lost due to assumptions about precedence.
Exceptions: None
Example:
Don't:
IF A AND B OR C AND D THEN
...
END_IF;
Do:
IF (A AND B) OR (C AND D) THEN
...
END_IF;
or
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
IF some_condition THEN
// some code
...
END_IF;
Do:
IF some_condition THEN
// some code
...
ELSE
// Nothing needs to happen in this case ! (Deliberate choice)
;
END_IF;
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation
Description: The only allowed operators for manipulating pointers are equality and inequality.
Developer shall not use pointer arithmetic to calculate a position in a memory to access further
data.
Guideline: Should be limited and used only for array access
Reasoning: Pointer arithmetic is implementation dependent and understanding such code requires a
thorough understanding of PLC’s internals. This practice was only acceptable due to the lack of
high level abstractions like structure, function blocks and arrays, but now these are available, they
should be used instead of pointer arithmetic. Moreover, as mentioned in rule N1, developers should
not use physical addresses for manipulating data.
Exceptions: None
Example: None
Comments: None
PLCopen
for efficiency in automation
Codesys SA0061
Misra-C 17.3
Description: <=, >=, < and > operators shall not be used on pointers or references. Only equality
and differences operators are allowed. If the order is required, then developer shall use an explicit
array so that the relative positioning of variables is known.
Guideline: Pointer equality and inequality are allowed - all other comparison operators are
forbidden
Reasoning: This rule is related to others rules relative to variable mapping in memory. The test
relies on knowledge of memory organization of the PLC. It is either undocumented or susceptible
to change and it is difficult to maintain.
Exceptions: None
Example:
Don't:
// Wrong example
VAR
x: POINTER;
y: POINTER;
END_VAR
...
IF X^ < Y^ AND X < Y THEN -- the comparison X and Y is not allowed
TEMP := X^:
X^ := Y^;
Y^ := TEMP;
END_IF;
Do:
// Good example - the usage of array is more explicit and relies
// on wide used arrays
VAR
Values : ARRAY [1..50] OF INT;
PLCopen
for efficiency in automation
IndexX : INT;
IndexY : INT;
END_VAR
IF Values[IndexX] < Values[IndexY] AND IndexX < IndexY THEN
TEMP := Values[IndexX];
Values[IndexX] := Values[IndexY];
Values[IndexY] := Temp;
END_IF;
Comments: None
PLCopen
for efficiency in automation
PLCopen
for efficiency in automation