Home > IEC 61131-3 > IEC 61131-3: Der generische Datentyp T_Arg

IEC 61131-3: Der generische Datentyp T_Arg

In dem Artikel The wonders of ANY zeigt Jakob Sagatowski wie der Datentyp ANY sinnvoll eingesetzt werden kann. Im beschriebenen Beispiel vergleicht eine Funktion zwei Variablen, ob der Datentyp, die Datenlänge und der Inhalt exakt gleich sind. Statt für jeden Datentyp eine eigene Funktion zu implementieren, kann mit dem Datentyp ANY die gleichen Anforderungen mit nur einer Funktion deutlich eleganter umgesetzt werden.

Vor einiger Zeit hatte ich eine ähnliche Aufgabenstellung. Es sollte eine Methode entwickelt werden, die eine beliebige Anzahl von Parametern entgegennimmt. Sowohl der Datentyp, als auch die Anzahl der Parameter waren beliebig.

Bei meinem ersten Lösungsansatz versuchte ich ein Array mit variabler Länge vom Typ ARRAY [*] OF ANY einzusetzen. Allerdings können Arrays mit variabler Länge nur als VAR_IN_OUT und der Datentyp ANY nur als VAR_INPUT eingesetzt werden (siehe auch IEC 61131-3: Arrays mit variabler Länge). Somit schied dieser Ansatz aus.

Alternativ zu dem Datentyp ANY steht noch die Struktur T_Arg zur Verfügung. T_Arg ist in der TwinCAT-Bibliothek Tc2_Utilities deklariert und steht, im Gegensatz zu ANY, auch unter TwinCAT 2 zur Verfügung. Der Aufbau von T_Arg ist vergleichbar mit der Struktur, die für den Datentyp ANY eingesetzt wird (siehe auch The wonders of ANY).

TYPE T_Arg :
STRUCT
  eType   : E_ArgType    := ARGTYPE_UNKNOWN;     (* Argument data type *)
  cbLen   : UDINT        := 0;                   (* Argument data byte length *)
  pData   : UDINT        := 0;                   (* Pointer to argument data *)
END_STRUCT
END_TYPE

T_Arg kann an beliebigen Stellen eingesetzt werden, somit auch im Bereich VAR_IN_OUT.

Die folgende Funktion addiert eine beliebige Anzahl von Zahlen, deren Datentyp ebenfalls beliebig sein kann. Das Ergebnis wird als LREAL zurückgegeben.

FUNCTION F_AddMulti : LREAL
VAR_IN_OUT
  aArgs        : ARRAY [*] OF T_Arg;
END_VAR
VAR
  nIndex	: DINT;
  aUSINT	: USINT;
  aUINT		: UINT;
  aINT		: INT;
  aDINT		: DINT;
  aREAL		: REAL;   
  aLREAL	: LREAL;
END_VAR

F_AddMulti := 0.0;
FOR nIndex := LOWER_BOUND(aArgs, 1) TO UPPER_BOUND(aArgs, 1) DO
  CASE (aArgs[nIndex].eType) OF
    E_ArgType.ARGTYPE_USINT:
      MEMCPY(ADR(aUSINT), aArgs[nIndex].pData, aArgs[nIndex].cbLen);
      F_AddMulti := F_AddMulti + aUSINT;
    E_ArgType.ARGTYPE_UINT:
      MEMCPY(ADR(aUINT), aArgs[nIndex].pData, aArgs[nIndex].cbLen);
      F_AddMulti := F_AddMulti + aUINT;
    E_ArgType.ARGTYPE_INT:
      MEMCPY(ADR(aINT), aArgs[nIndex].pData, aArgs[nIndex].cbLen);
      F_AddMulti := F_AddMulti + aINT;
    E_ArgType.ARGTYPE_DINT:
      MEMCPY(ADR(aDINT), aArgs[nIndex].pData, aArgs[nIndex].cbLen);
      F_AddMulti := F_AddMulti + aDINT;
    E_ArgType.ARGTYPE_REAL:
      MEMCPY(ADR(aREAL), aArgs[nIndex].pData, aArgs[nIndex].cbLen);
      F_AddMulti := F_AddMulti + aREAL;
    E_ArgType.ARGTYPE_LREAL:
      MEMCPY(ADR(aLREAL), aArgs[nIndex].pData, aArgs[nIndex].cbLen);
      F_AddMulti := F_AddMulti + aLREAL;
  END_CASE
END_FOR

Der Aufruf der Funktion gestaltet sich hierbei allerdings etwas umständlicher, als bei dem Datentyp ANY.

PROGRAM MAIN
VAR
  sum          : LREAL;
  args         : ARRAY [1..4] OF T_Arg;
  a            : INT := 4567;
  b            : REAL := 3.1415;
  c            : DINT := 7032345;
  d            : USINT := 13;
END_VAR

args[1] := F_INT(a);
args[2] := F_REAL(b);
args[3] := F_DINT(c);
args[4] := F_USINT(d);
sum := F_AddMulti(args);

Das Array, das an die Funktion übergeben wird, muss zuvor initialisiert werden. In der Bibliothek Tc2_Utilities stehen Hilfsfunktionen zur Verfügung, die eine Variable in eine Struktur vom Typ T_Arg umwandeln (F_INT(), F_REAL(), F_DINT(), …). Die Funktion zum Addieren der Werte besitzt nur noch eine Eingangsvariable vom Typ ARRAY [*] OF T_Arg.

Anwendung findet der Datentyp T_Arg z.B. im Funktionsblock FB_FormatString() oder in der Funktion F_FormatArgToStr() von TwinCAT. Mit dem Funktionsblock FB_FormatString() können in einem String bis zu 10 Platzhalter durch Werte von SPS-Variablen vom Typ T_Arg ersetzt werden (ähnlich wie bei fprintf in C).

Ein Vorteil von ANY ist die Tatsache, dass der Datentyp durch die Norm IEC 61131-3 definiert wird.

Auch wenn die generische Datentypen ANY und T_Arg vom Leistungsumfang nicht den Generics in C# oder den Templates in C++ entsprechen, so unterstützen diese dennoch die Entwicklung generischer Funktionen in der IEC 61131-3. Diese können jetzt so entworfen werden, dass die gleiche Funktion für unterschiedliche Datentypen und Datenstrukturen verwendet werden kann.

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 )

Google+ photo

You are commenting using your Google+ 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 )

w

Connecting to %s

%d bloggers like this: