Home > IEC 61131-3 > IEC 61131-3: Namensräume

IEC 61131-3: Namensräume

Mit der 3rd Edition der IEC 61131-3 wurde das Prinzip der Namespaces (Namensräume) eingeführt. Namespaces gruppieren Elemente wie Variablen, Bausteine, Datentypen und Bibliotheken in zusammengehörige Einheiten. Ein Element wird dadurch nicht mehr nur durch seinen Namen, sondern auch durch seinen zugehörigen Namespace benannt.

Mit diesem Thema hatte ich mich bereits Ende 2010 beschäftigt. Damals noch unter CoDeSys V3. Die folgenden Beispiele wurden mit TwinCAT 3 erstellt und stellen die verschiedenen Bereiche vor, in denen Namespaces zum Tragen kommen.

Bibliotheken

Bezeichner von Funktionsblöcken, Funktionen und Datentypen müssen eindeutig sein. Das betrifft auch die Elemente, die aus Bibliotheken in ein Projekt eingebunden werden. Sollen mehrere SPS-Bibliotheken von unterschiedlichen Quellen zum Einsatz kommen, können aber genau hier Namenskonflikte auftreten. Um dieses zu vermeiden, wurde meistens vom Entwickler der Bibliothek vor jedem POU- oder Datentypbezeichner ein Prefix gestellt (z.B. MC_MoveAbsolute). Hiermit wird versucht, die Wahrscheinlichkeit eines Namenkonflikts möglichst gering zu halten.

Bei TwinCAT 3 wird dieses Problem mit Namespaces gelöst. Bei jedem SPS-Projekt, und somit auch bei SPS-Bibliotheken, kann ein Namespace bei den Projektinformationen definiert werden. Groß- und Kleinschreibung wird nicht berücksichtigt.

Sehr häufig entspricht der Namespace einer Bibliothek auch dem Namen der Bibliothek (in diesem Beispiel ist dieses nicht der Fall). Bleibt das Feld für den Namespace leer, so wird als Namespace der Name der Bibliothek (das Feld Title) benutzt.

Pic01
Werden zu einem SPS-Projekt Bibliotheken hinzugefügt, in denen Elemente gleich benannt worden sind, so kann mit Hilfe der Namespaces dieser Namenskonflikt aufgelöst werden.

Beispiel:

Zwei SPS-Bibliotheken enthalten jeweils den Baustein FB_Foo. Diese beiden Bibliotheken werden einem Projekt hinzugefügt. Der Versuch, eine Instanz eines dieser Bausteine anzulegen führt zwangsläufig zu einer Fehlermeldung. Für den Compiler ist es nicht eindeutig, aus welcher Bibliothek er den Baustein nehmen soll.

Pic02
Wird der Namespace der jeweiligen Bibliothek zusätzlich angegeben, so wird dieser Namenskonflikt aufgelöst.

Ohne die Angabe eines Namespace wird erst im lokalen SPS-Projekt nach dem jeweiligen Element gesucht. Somit lässt sich ein POU FB_Foo instanziieren, welcher im aktuellen SPS-Projekt enthalten ist. Ein in den Projektinformationen angegebener Namespace, ist hierbei ohne Bedeutung.

PROGRAM MAIN
VAR
  fbFoo1  :  MyNamespace01.FB_Foo;
  fbFoo2  :  MyNamespace02.FB_Foo;
  fbFoo3  :  FB_Foo;
END_VAR

Attribut init_namespace

Hilfreich ist das Attribut init_namespace. Wird eine Variable vom Typ STRING oder WSTRING mit diesem Attribut dekoriert, so wird diese Variable mit dem Namen des aktuellen Namespace initialisiert.

FUNCTION_BLOCK PUBLIC FB_Foo
VAR_INPUT
END_VAR
VAR_OUTPUT
  {attribute 'init_namespace'}
  sNamespace  :  STRING;	
END_VAR
VAR
END_VAR

Somit kann zur Laufzeit der jeweilige Namespace ermittelt werden:

Pic03

Beispiel 1 (TwinCAT 3.1) auf GitHub

Namespace anpassen

Der Namespace einer Bibliothek wird auch bei den Eigenschaften der Referenz angezeigt:

Pic04

Sollte der Fall eintreten, dass auch der Namespace nicht eindeutig ist, so kann dieser in den Eigenschaften der Referenz angepasst werden.

Dadurch ergibt sich auch die Möglichkeit, verschiedene Versionen der gleichen Bibliothek in ein Projekt einzubinden.

Pic05

Sofern der Namespace angepasst wurde, so kann gezielt auf die gewünschten Elemente der Bibliothek zugegriffen werden.

PROGRAM MAIN
VAR
  eAdsErr01  :  Tc2_System_A.E_AdsErr;
  eAdsErr02  :  Tc2_System_B.E_AdsErr;
END_VAR

Obwohl in beiden SPS-Bibliotheken der Enumerator E_AdsErr gleich aufgebaut ist, handelt es sich um zwei verschiedene Datentypen. Das bedeutet, dass in dem oberen Beispiel die Variablen eAdsErr01 und eAdsErr02 nicht miteinander kompatibel sind.

eAdsErr01 := eAdsErr02;

Diese Zuweisung wird vom Compiler mit der folgenden Fehlermeldung ablehnt:

Implicit conversion from one enumeration type (E_ADSERR (tc2_system, 3.4.14.0 (beckhoff automation gmbh))) to another (E_ADSERR (tc2_system, 3.4.13.0 (beckhoff automation gmbh)))

Global Variable List

Eine Globale Variable List (GVL) dient zum Deklarieren von globalen Variablen. Der Name der GVL muss in einem Projekt eindeutig sein, wobei Groß- und Kleinschreibung nicht von Bedeutung ist. Jede GVL ist ein in sich abgeschlossener Bereich (Namespace), in dem, unabhängig von anderen GVLs, globale Variablen deklariert werden.

Im folgenden Beispiel sind drei Variablen deklariert. Alle drei Variablen haben den Namen var01, wovon zwei in getrennten GVLs (GVL01 und GVL02) deklariert werden und eine lokal in MAIN.

Pic06

Um den Zugriff auf die Variablen wieder eindeutig zu machen, muss zusätzlich der Name der GVL vor den Variablennamen, getrennt durch einen Punkt, gestellt werden.

GVL01.var01 := 1;    // global variable in GVL01
GVL02.var01 := 2;    // global variable in GVL02
var01 := 3;          // local variable in MAIN

Existiert die Variable var01 nur in einer GVL, so kann die Angabe der GVL auch entfallen. Gibt es allerdings eine lokale Variable mit dem gleichen Namen, so muss der Name der GVL wieder angegeben werden. Alternativ kann vor dem Variablennamen auch nur ein Punkt gestellt werden, welches den global Namespace kennzeichnet.

.var01 := 1;     // global variable
var01 := 3;      // local variable

Der Punkt vor dem Variablennamen gibt an, dass auf die globale Variable mit dem Namen var01 zugegriffen werden soll. In diesem Fall darf die Variable aber auch nur in einer GVL existieren.

Attribut qualified_only

Der Name der GVL sollte immer mit angegeben werden, auch dann, wenn es nicht unbedingt notwendig ist. Befindet sich in der GVL das Attribut qualified_only, so wird eine Fehlermeldung ausgegeben, wenn bei einem Zugriff auf eine der Variablen die Angabe der GVL fehlt.

{attribute 'qualified_only'}
VAR_GLOBAL
  var01  :  INT;
  var02  :  INT;
END_VAR

Wird auf eine der globalen Variablen zugegriffen, so muss der Name der GVL mit angegeben werden. Das Programm wird dadurch lesbarer und Seiteneffekte zwischen lokalen und globalen Variablen können besser vermieden werden.

Beispiel 2 (TwinCAT 3.1) auf GitHub

GVLs in Bibliotheken

Befindet sich eine GVL in einer Bibliothek, so kann neben den Namen der GVL auch noch der Namespace der Bibliothek genutzt werden.

In dem folgenden Beispiel wurden drei Variablen mit den Namen var01 an verschiedenen Stellen deklariert:

– In der GVL01 einer Bibliothek mit dem Namespace MyNamespace01
– In der GVL01 des lokalen SPS-Projektes
– Im lokalen POU

Für den Zugriff auf die jeweilige Variable kann, neben den Namen der GVL, noch zusätzlich der Namespace der Bibliothek benutzt werden:

MyNamespace01.GVL01.var01 := 1;  // global variable of the GVL inside the library
GVL01.var01 := 2;                // global variable of the local GVL
var01 := 3;                      // local variable

Wird in der lokalen GVL das Attribut qualified_only nicht verwendet, so kann auf die Angabe der GVL verzichtet werden:

MyNamespace01.GVL01.var01 := 1;  // global variable of the GVL inside the library
.var01 := 2;                     // global variable of the local GVL
var01 := 3;                      // local variable

Auch kann auf die Angabe der GVL der Bibliothek verzichtet werden, wenn dort das Attribut qualified_only nicht zum Einsatz kommt.

MyNamespace01.var01 := 1;  // global variable of the GVL inside the library
.var01 := 2;               // global variable of the local GVL
var01 := 3;                // local variable

Wären die Namen der GVLs eindeutig, so könnte auch der Namespace entfallen:

GVL01.var01 := 1;   // global variable of the GVL of the library
.var01 := 2;        // global variable of the local GVL
var01 := 3;         // local variable

Die letzten Beispiele verdeutlichen, das durch den Wegfall der Namespaces die Lesbarkeit des Programms abnimmt. Es ist schwerer zu erkennen, wo die referenzierten Variablen deklariert wurden. Daher sollte in jeder GVL das Attribut qualified_only enthalten sein und bei der Verwendung von Elementen aus Bibliotheken der Namespace benutzt werden.

Auch bei der Definition von FBs die von einem FBs aus einer Bibliothek erben, als auch bei der Verwendung von Interfaces aus Bibliotheken sollte der Namespace angegeben werden:

FUNCTION_BLOCK FB_MyFoo EXTENDS MyNamespace01.FB_Foo IMPLEMENTS MyNamespace01.I_Foo
VAR_INPUT
END_VAR
VAR_OUTPUT
END_VAR
VAR
END_VAR

Der Dialog zum Anlegen von neuen FBs bietet hierzu entsprechende Unterstützung an:

Pic07

Beispiel 3 (TwinCAT 3.1) auf GitHub

Enumerationen

Sofern auf die Werte einer Enumeration zugegriffen wird, kann der entsprechende Wert direkt benutzt werden. Um einen eindeutigen Zugriff auf eine Enumerations-Konstante zu gewährleisten, kann zusätzlich noch der Typ-Name hinzugefügt werden.

TYPE E_Foo01 :
(
  eNoError := 0,
  eErrorA := 1,
  eErrorB := 2
);
END_TYPE

PROGRAM MAIN
VAR
  eFoo01  :  E_Foo01;
END_VAR
eFoo01 := eErrorA;
eFoo01 := E_Foo01.eErrorA;

Ist ein Bezeichner für eine Enumerations-Konstante in verschiedenen Typ-Definitionen enthalten, so ist der Typ-Name beim Zugriff notwendig. Dadurch können Konstanten gleichen Namens in mehreren Enumerationen verwendet werden. Somit ist es nicht mehr notwendigen jede Enumerations-Konstante mit einem Prefix zu erweitern, um Namenskonflikte zu vermeiden.

TYPE E_Foo01 :
(
  eNoError := 0,
  eErrorA := 1,
  eErrorB := 2
);
END_TYPE

TYPE E_Foo02 :
(
  eNoError := 0,
  eError1 := 1,
  eError2 := 2
);
END_TYPE

PROGRAM MAIN
VAR
  eFoo01	  :  E_Foo01;
  eFoo02	  :  E_Foo02;
END_VAR
eFoo01 := E_Foo01.eNoError;
eFoo02 := E_Foo02.eNoError;

Befindet sich die Typ-Definition in einer Bibliothek, ist die Angabe des Namespace zusätzlich noch möglich:

eFoo01 := MyNamespace01.E_Foo01.eNoError;

Attribut qualified_only

Ähnlich wie bei den GVLs, kann durch das Attribut qualified_only die Angabe des Typ-Namens erzwungen werden:

{attribute 'qualified_only'}
TYPE E_Foo01 :
(
  eNoError := 0,
  eErrorA := 1,
  eErrorB := 2
);
END_TYPE

Beispiel 4 (TwinCAT 3.1) auf GitHub

Attribut strict

Das Attribut strict hat keinen direkten Bezug zu Namespaces. Es kann aber ebenfalls dazu dienen ein Programm lesbarer zu machen. Deshalb soll es hier kurz vorgestellt werden.

Eine Variable vom Typ einer Enumeration wird intern wie ein INT behandelt. Somit sind mit Enumerationen arithmetische Operationen möglich oder es können Werte zugewiesen werden, die nicht durch die Enumerationen definiert wurden. Das folgende Beispiel weist der Variablen eFoo01 den Wert 3 zu. Die Enumeration E_Foo01 enthält jedoch keinen entsprechenden Wert.

eFoo01 := E_Foo01.eErrorA + 2;

Wird das Attribut strict bei der Definition einer Enumeration angegeben, so wird sichergestellt, dass Variablen von diesem Typ nur Werte annehmen können, die durch die Enumeration auch definiert worden sind.

{attribute 'strict'}
TYPE E_Foo01 :
(
  eNoError := 0,
  eErrorA := 1,
  eErrorB := 2
);
END_TYPE

Durch das Attribut strict sind keine Operationen mehr erlaubt, die Werte zur Folge haben, die nicht durch die Enumeration definiert worden sind. Dieses betrifft folgende Operationen:

Zuweisung von Konstanten die nicht durch die Enumeration definiert wurden
eFoo01 := 5;
Arithmetische Operationen mit Werten der Enumeration
eFoo01 := E_Foo01.eNoError + E_Foo01.eErrorA;
Zuweisen von Variablen die nicht vom Typ der Enumeration sind
nVar := 1;        // variable nVar is a INT
eFoo01 := nVar;

Zusammenfassung

Namespaces bieten einen guten Mechanismus um Namenskonflikte zu vermeiden. Entsprechende Prefixe in den Bezeichnern von Funktionen und Datentypen sind somit nicht mehr notwendig. Die Elementnamen werden dadurch kompakter, der Quelltext besser lesbar.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: