IEC 61131-3: Vergleich Edition 3 und Edition 4

Seit Mai 2025 ist die Edition 4 der IEC 61131-3 online verfügbar. Im folgenden Post gehe ich kurz auf die wichtigsten Unterschiede zwischen der Edition 3 und der Edition 4 ein.

Die Neuerungen der Edition 4 habe ich nicht testen können, da zum Zeitpunkt des Vergleichs mir keine Entwicklungsumgebung zur Verfügung stand, die die neuen Funktionen der Edition 4 unterstützt. Somit kann ich nur einen allgemeinen Überblick über die Unterschiede bieten. Für den Vergleich habe ich die IEC 61131-3 (Edition 3.0) 2013-02 und die IEC 61131-3 (Edition 4.0) 2025-05 verwendet. Wer sich intensiver mit der IEC 61131-3 auseinandersetzen will oder muss, kommt um die Norm allerdings nicht herum.

Der erste Eindruck

Bei dem Vergleich der Inhaltsverzeichnisse fällt auf, dass bei der Edition 3 der Anhang ab Seite 221 beginnt, während die Edition 4 ab Seite 241 den Anhang enthält.

Neu hinzugekommen ist das 6 Seiten umfassende Kapitel 6.9 Synchronization of concurrent execution. Die entsprechenden Unterkapitel verraten, dass es hier um Mutexe und Semaphoren geht.

Das Kapitel 7.2 Instruction List (IL) ist in der Edition 4 nicht mehr enthalten. Somit ist IL (zu Deutsch: AWL) nicht mehr Bestandteil der IEC 61131-3. Das muss aber nicht heißen, dass IL von den Herstellern nicht mehr angeboten wird. Jeder Hersteller kann weiterhin selbst entscheiden, ob er IL in seiner Entwicklungsumgebung anbieten möchte oder nicht.

Oktal-Literale

Neben den Ganzzahl-Literalen (z.B. -43), den Fließkomma-Literalen (z.B. -43.8), den Binar-Literalen (z.B. 2#1101_0110) und den Hexadezimal-Literalen (z.B. 16#E26B) gibt es in der Edition 3 auch die Oktal-Literal (z.B. 8#267). Die Oktal-Literale werden von Edition 4 nicht mehr unterstützt. In der Edition 3 waren die Oktal-Literale schon als deprecated gekennzeichnet.

Datentypen USTRING und UCHAR

Mit den beiden neuen Datentypen USTRING und UCHAR werden nun auch Zeichenketten unterstützt, bei denen jedes Zeichen nach UTF-8 kodiert ist.

Während ein WSTRING / WCHAR als UTF-16 kodiert wird und immer 2 Byte pro Zeichen benötigt, codiert UTF-8 jedes Zeichen mit einer Folge von 1 bis 4 Bytes.

UTF-8, oder Unicode Transformation Format – 8 Bit, ist abwärtskompatibel zu 7-Bit-ASCII, da die ersten 128 Zeichen in UTF-8 und ASCII im englischen Zeichensatz identisch sind. Somit ist jede gültige ASCII-Zeichenkette auch eine gültige UTF-8-Zeichenkette, sodass die meisten für ASCII geschriebenen Programme leicht an UTF-8 angepasst werden können.

UTF-8 ist besonders bei Internetanwendungen stark verbreiten. Sowohl das Internet-Mail Consortium (IMC) als auch das Word Wide Web Consortium (W3C) empfehlen die Verwendung von UTF-8 als einheitliche Codierung.

USTRING– und UCHAR-Literale werden wie folgt angegeben:

x    : USTRING := USTRING#'ABC';
x    : USTRING := U#'ABC';
y    : UCHAR := UCHAR#'A';
y    : UCHAR := U#'A';

LEN_MAX und LEN_CODE_UNIT

In Kapitel 6.6.2.5.12 werden die Character string functions beschrieben. Neu hinzugekommen sind die Funktionen LEN_MAX und LEN_CODE_UNIT.

LEN_MAX gibt die maximale Länge des Strings zurück:

VAR
   x   : STRING[100] := 'Hello';
   y   : WSTRING[100] := WSTRING#'Hello';
   z   : USTRING[100] := USTRING#'Hello';
END_VAR
a := LEN_MAX(x);  // a = 100
b := LEN_MAX(y);  // b = 100
c := LEN_MAX(z);  // c = 100

LEN_CODE_UNIT gibt die Anzahl der von dem String belegten Code-Einheiten zurück. Bei den Datentypen STRING und WSTRING gibt LEN_CODE_UNIT den gleichen Wert zurück wie bei LEN. Bei USTRING kann der Wert von LEN_CODE_UNIT allerdings größer sein als von LEN.

a := LEN_CODE_UNIT(x);  // a = 5
b := LEN_CODE_UNIT(y);  // b = 5
c := LEN_CODE_UNIT(z);  // c = 5

Da die Strings in diesem Beispiel nur ASCII-Zeichen enthalten, liefert LEN_CODE_UNIT für alle drei Datentypen denselben Wert zurück.

Angabe von Zeichen durch Zeichencodes

In einem String- oder Zeichen-Literal können beliebige Zeichen durch den Zeichencode angegeben werden. Dieser wird in Hexadezimaldarstellung nach einem $ in geschweifte Klammern angegeben:

VAR
   x   : STRING := '${9}'; // Steuerzeichen für Tabulator
   y   : WSTRING := WSTRING#'${2211}';  // Zeichen ∑
   z   : USTRING := USTRING#'${1F579}'; // Emoji 'Joystick'
END_VAR

Die bisherige Unterstützung von Zeichencodes mit festen Längen (z.B. ‘$0A’ bzw. “$00C4”) wird weiterhin unterstützt.

Anmerkung: Für die Darstellung des Zeichencodes hätte ich mir gewünscht, dass die übliche Codierung für das jeweilige Zahlensystem verwendet wird; also 16#1F579 statt nur 1F579. Auch wenn es üblich ist, Zeichencodes in hexadezimal anzugeben, so ist doch eindeutiger zu erkennen in welchem Zahlensystem der Zeichencode angegeben wurde.

Die Char Map (Zeichentabelle) unter Windows erlaubt leider nur die Eingabe von Zeichencodes mit max. 4 Ziffern. Die Funktion Einfügen -> Symbol in Word ist deutlich hilfreicher, den passenden Zeichencode zu finden:

Beschrieben werden die String- und Zeichen-Literale im Kapitel 6.3.3 Character string literals.

Datentypkonvertierung

In Bild 11 des Kapitels 6.6.1.6 Data type conversion ist eine Übersicht über die impliziten und expliziten Datentypkonvertierungen zu sehen. Gegenüber der Edition 3 gibt es hier einige Anpassungen und Erweiterungen.

Die Edition 4 definiert einige explizite Datentypkonvertierungen, die in der Edition 3 nicht enthalten sind:

  • LWORD_TO_BOOL, DWORD_TO_BOOL, WORD_TO_BOOL und BYTE_TO_BOOL
  • UINT_TO_WCHAR und USINT_TO_CHAR
  • WSTRING_TO_WCHAR
  • WCHAR_TO_UINT

Einige explizite Datentypkonvertierungen wurden in implizite Datentypkonvertierungen geändert:

  • STRING_TO_WSTRING
  • CHAR_TO_WCHAR

Für die Datentypen USTRING und UCHAR sind einige implizite und explizite Datentypkonvertierungen hinzugekommen:

  • UDINT_TO_UCHAR und DWORD_TO_UCHAR
  • USTRING_TO_WSTRING, USTRING_TO_STRING und USTRING_TO_UCHAR
  • UCHAR_TO_UDINT, UCHAR_TO_LWORD, UCHAR_TO_DWORD, UCHAR_TO_USTRING, UCHAR_TO_WCHAR und UCHAR_TO_CHAR
  • WSTRING_TO_USTRING und STRING_TO_USTRING
  • CHAR_TO_UCHAR

Datentypkonvertierung zwischen Strings und ARRAY OF BYTE

Neu hinzugekommen sind Funktionen für die Datentypkonvertierung zwischen Zeichenketten und ARRAY OF BYTE. Beschrieben werden diese im Kapitel 6.6.2.5.8 Data type conversion between string types and array of bytes:

  • STRING_TO_ARRAY_OF_BYTE, WSTRING_TO_ARRAY_OF_BYTE und USTRING_TO_ARRAY_OF_BYTE
  • ARRAY_OF_BYTE_TO_STRING, ARRAY_OF_BYTE_TO_WSTRING und ARRAY_OF_BYTE_TO_USTRING

TRUNC entfällt

Die Funktion TRUNC wird als typisierte und überladene Funktion definiert. In der typisierten Schreibweise wird der Quelldatentyp und der Zieldatentyp im Funktionsnamen angegeben, z.B. LREAL_TRUNC_DINT(x), während bei der überladenen Schreibweise nur der Zieldatentyp angegeben wird, z.B. TRUNC_DINT(x). Der Quelldatentyp wird aus dem übergebenen Parameter ermittelt.

Die Edition 3 hatte noch die Schreibweise ohne die Angabe eines Datentyps definiert, also TRUNC(x). Hierbei musste der Quelldatentyp immer ANY_REAL und der Zieldatentyp immer ANY_INT sein. Diese Schreibeweise war in der Edition 3 schon als Deprecated gekennzeichnet und ist jetzt aus der Edition 4 entfernt worden.

Eigenschaften

Mit der Edition 4 werden (endlich) Eigenschaften definiert. Eigenschaften sind Teil einer CLASS, FUNCTION_BLOCK oder INTERFACE. Damit der Wert einer Eigenschaft gesetzt oder gelesen werden kann, werden Setter- und Getter-Methoden deklariert. Die Deklaration ähnelnd der einer Methode. Allerdings wird statt dem Schlüsselwort METHOD die Schlüsselwörter PROPERTY_GET und PROPERTY_SET verwendet.

PROPERTY_GET PUBLIC nFoo : INT
	;
END_PROPERTY
PROPERTY_SET PUBLIC nFoo : INT
	;
END_PROPERTY

Sind Setter- als auch Getter-Methode definiert, so muss der Datentyp bei beiden Methoden gleich sein.

Für Eigenschaften können die gleichen Zugriffsbezeichner (Access Specifier) wie für Methoden verwendet werden, also INTERNAL, PRIVATE, PROTECTED und PUBLIC. Zusätzlich sind noch die Schlüsselwörter ABSTRACT und FINAL möglich. Wird kein Zugriffsbezeichner angegeben, so ist die Eigenschaft PROTECTED.

Soll eine Eigenschaft nur lesbar sein, so kann auf die Setter-Methode verzichtet werden oder diese wird auf PRIVATE gesetzt.

Eine Eigenschaft kann, wie eine Instanzvariable verwendet werden:

VAR
   fbFoo   : FB_Foo;
   x       : INT := 10;
END_VAR
fbFoo.nFoo := x;  // Schreiben der Eigenschaft
x := fbFoo.nFoo;  // Lesen der Eigenschaft 

In der Setter- und Getter-Methode wird der Programmcode hinterlegt, um den Wert der Eigenschaft intern zu verwalten.

FUNCTION_BLOCK FB_Foo
   VAR PRIVATE
      _nFoo : INT;   // Backing variable
   END_VAR
   PROPERTY_GET PUBLIC nFoo : INT
      nFoo := _nFoo;
   END_PROPERTY
   PROPERTY_SET PUBLIC nFoo : INT
      _nFoo := nFoo;
   END_PROPERTY
END_FUNCTION_BLOCK

Beschrieben werden die Eigenschaften im Kapitel 6.6.5.11 Properties.

Assertions

Die Edition 4 definiert im Kapitel 6.6.2.5.17 Assertions die Funktion ASSERT, die den Eingangsparameter IN vom Typ BOOL und keinen Rückgabewert besitzt. ASSERT soll dazu dienen die Gültigkeit von Ausdrücken oder Variablen während der Entwicklung zu überprüfen.

Ist IN bei dem Aufruf TRUE, so hat die Funktion keine Auswirkungen. Ist IN aber FALSE, so soll ASSERT dem Entwickler dieses ‚mitteilen‘. Wie die Mitteilung aussieht, kann jeder Hersteller (der Entwicklungsumgebung) individuell definieren.

Ist die Entwicklung abgeschlossen hat der Aufruf von ASSERT keine Auswirkungen mehr, unabhängig welchen Wert der Eingangsparameter IN besitzt. Wie der Entwicklungsumgebung dieses mitgeteilt wird, kann vom Hersteller festgelegt werden.

Synchronisierung paralleler Programmausführung

Das Kapitel 6.9 Synchronization of concurrent execution ist in der Edition 4 neu hinzugekommen und definiert Objekte und Funktionen um Programmcode, der auf mehrere Tasks aufgeteilt wurde, zu synchronisieren. Eine Synchronisation ist beispielsweise dann erforderlich, wenn z.B. zwei parallele Programme auf eine gemeinsame Variable zugreifen, wobei ein Programm diese Variable auch verändert.

Damit parallellaufende Programme einfacher synchronisierbar sind, werden in der Edition 4 Mutexe und Semaphoren definiert.

Ich werde nur kurz die Funktionen vorstellen, die die Edition 4 definiert. Eine genaue Beschreibung dieser Konzepte wäre an dieser Stelle zu umfangreich, könnte aber Thema eines eigenen Post werden.

Mutex

Mutexe werden üblicherweise zur Modellierung kritischer Abschnitte verwendet. Ein Mutex kann gesperrt und entsperrt werden.

Es wird sowohl ein objektorientierter Ansatz definiert als auch ein Ansatz, der auf Funktionen basiert. Bei dem objektorientierter Ansatz ist die Basis der Funktionsblock MUTEX. Dieser besitzt die folgenden Methoden:

  • UNLOCK
  • LOCK
  • TRYLOCK

Zusätzlich besitzt MUTEX noch die Eigenschaften LOCK_COUNT und OWNER. OWNER dient dazu einen Wert zu speichern, der die Task identifiziert.

Bei dem Ansatz auf Basis von Funktionen stehen die entsprechenden Funktionen bereit:

  • MUTEX_UNLOCK
  • MUTEX_LOCK
  • MUTEX_TRYLOCK

Semaphore

Auch hier wird sowohl ein objektorientierter Ansatz als auch ein Ansatz, der auf Funktionen basiert definiert. Für den objektorientierten Ansatz wurde der Funktionsblock SEMA definiert. Dieser besitzt die Methoden:

  • RELEASE
  • ACQUIRE
  • TRY_ACQUIRE

Entsprechend wurden auch die folgenden Funktionen festgelegt:

  • SEMA_RELEASE
  • SEMA_ACQUIRE
  • SEMA_TRY_ACQUIRE

Unterstützung BCD-Zahlen ist abgekündigt

In Zukunft werden BCD-Zahlen nicht weiter unterstützt. In der Edition 4 sind die folgenden Funktionen als Deprecated gekennzeichnet:

  • IS_VALID_BCD
  • BCD_TO_out und in_BCD_TO_out
  • TO_BCD_out und in_TO_BCD_out

Fazit

Mein persönliches Highlight ist die Unterstützung von Mutexe und Semaphoren. In Zeiten, wo die CPUs immer mehr Kerne besitzen, müssen auch entsprechende Hilfsmittel bereitgestellt werden, um ein Programm auf mehrere Tasks zu verteilen.

Die restlichen Änderungen würde ich als allgemeine Pflege und Wartung bezeichnen. Gut, das hierbei auch Sachen aus der Norm entfernt werden, wenn diese keine Bedeutung mehr haben. Dazu gehört z.B. das Entfernen von IL als auch der Wegfall der Oktal-Literale.

Es wurden auch einige Punkte genauer definiert, beispielsweise die Frage, ob ARRAY[1..1] und ARRAY[1..0] erlaubt sind und wie sie sich verhalten (Kapitel 6.4.4.5.1).

Ansonsten sehe ich die Unterschiede nicht so umfangreich, wie zwischen Edition 2 (erschienen 2003) und Edition 3 (erschienen 2013).

Allerdings vermisse ich auch einige Punkte. Dazu gehören die lokalen Enums (implicit enumeration), optionale Parameter bei Methoden und Funktionen, als auch die Möglichkeit Methoden zu Überladen.

Unknown's avatar

Author: Stefan Henneken

I’m Stefan Henneken, a software developer based in Germany. This blog is just a collection of various articles I want to share, mostly related to Software Development.

2 thoughts on “IEC 61131-3: Vergleich Edition 3 und Edition 4”

  1. Hola Stefan,

    Optional parameters for methods and functions, as well as the possibility of overloading methods, do you know when they are planned and when they will be able to include it?

    Thanks for the article so I can keep up with the latest developments…but I feel like they’re falling way behind… For me, the pace isn’t fast enough; it’s very slow compared to how the industry is progressing…

Leave a reply to Stefan Henneken Cancel reply