| 

.NET C# Java Javascript Exception

8
Bei der Deklaration von Arrays musste bisher immer eine konstante Größe angegeben werden. Ab der 3rd Edition der IEC 61131-3 können Arrays mit einer variablen Länge deklariert werden. Funktionen lassen sich dadurch deutlich generischer anlegen als bisher. Zwar können für die Arraygrenzen auch Variablen benutzt werden, diese Variablen müssen aber als Konstanten deklariert werden. Eine […]

Bei der Deklaration von Arrays musste bisher immer eine konstante Größe angegeben werden. Ab der 3rd Edition der IEC 61131-3 können Arrays mit einer variablen Länge deklariert werden. Funktionen lassen sich dadurch deutlich generischer anlegen als bisher.

Zwar können für die Arraygrenzen auch Variablen benutzt werden, diese Variablen müssen aber als Konstanten deklariert werden. Eine Anpassung der Arraygrenzen zur Laufzeit ist somit nicht möglich.

PROGRAM MAIN
VAR
 arrData : ARRAY[1..ARRAY_UPPER_BOUND] OF INT;
END_VAR
VAR CONSTANT
 ARRAY_UPPER_BOUND : INT := 10;	
END_VAR

Gerade wenn Arrays als Parameter an Funktionen oder Funktionsblöcken übergeben werden, stellen feste Arraygrenzen eine unangenehme Limitierung dar. Ist diese nicht hinnehmbar, musste bisher auf Pointerarithmetik gewechselt werden, mit allem Nachteilen. Hier ein einfaches Beispiel, welches die Summe eines eindimensionalen Arrays von LREAL-Variablen berechnet.

FUNCTION F_CalcSum1DimArrayOldSchool : LREAL
VAR_INPUT
 pData : POINTER TO LREAL;
 nSize : UDINT;
END_VAR
VAR
 pDataIndex : POINTER TO LREAL;
 nUpperIndex : UDINT;
 nIndex : UDINT;
END_VAR

F_CalcSum1DimArrayOldSchool := 0;
nUpperIndex := nSize / SIZEOF(pDataIndex^);
IF (nUpperIndex > 0) THEN
 FOR nIndex := 0 TO (nUpperIndex - 1) DO
 pDataIndex := pData + (nIndex * SIZEOF(pDataIndex^));
 F_CalcSum1DimArrayOldSchool := F_CalcSum1DimArrayOldSchool + pDataIndex^;	
 END_FOR
END_IF

Die Funktion kann für die Addition beliebiger LREAL-Arrays genutzt werden. Sie ist unabhängig von der Anzahl der Elemente und von der oberen und unteren Arraygrenze.

PROGRAM MAIN
VAR
 array01 : ARRAY[2..8] OF LREAL := [16.1, 34.1, 4.1, 43.1, 35.1, 2.1, 65.1];
 lrSum01 : LREAL;
	
 array02 : ARRAY[-1..2] OF LREAL := [16.1, 34.1, 9.1, 13.1];
 lrSum02 : LREAL;
	
 array03 : ARRAY[-3..-1] OF LREAL := [16.1, 34.1, 8.1];
 lrSum03 : LREAL;
END_VAR
lrSum01 := F_CalcSum1DimArrayOldSchool(ADR(array01), SIZEOF(array01));
lrSum02 := F_CalcSum1DimArrayOldSchool(ADR(array02), SIZEOF(array02));
lrSum03 := F_CalcSum1DimArrayOldSchool(ADR(array03), SIZEOF(array03));

Beispiel 1 (TwinCAT 3.1.4020)

Allerdings hat diese Lösung einige Nachteile. Zum einen eben die Tatsache das Pointerarithmetik benutzt werden muss. Der Quellcode der Funktion wird schon bei relativ einfachen Aufgaben recht komplex. Zum anderen muss an die Funktion auch eine Größen- bzw. Längenangabe übergeben werden. Bei dem Aufruf muss also sichergestellt werden, das der Pointer auf das Array und die Längenangabe übereinstimmen.

Seit der 3rd Edition der IEC 61131-3 können Arrays auch mit variabler Arraygrenze definiert werden. Statt der Arraygrenze, wird ein ’*’ angegeben:

arrData : ARRAY[*] OF LREAL;

Wird die Funktion aufgerufen, so muss das übergebene Array konstante Arraygrenzen besitzen. In der Funktion kann über die Funktionen LOWER_BOUND und UPPER_BOUND die jeweilige obere- und untere Arraygrenze abgefragt werden.

Derzeit können Arrays mit variabler Länge nur an VAR_IN_OUT Variablen von Funktionen, Funktionsblöcken und Methoden übergeben werden (bleibt zu hoffen, dass in Zukunft auch VAR_INPUT und VAR_OUTPUT Variablen unterstützt werden).

Hier das angepasste Beispiele:

FUNCTION F_CalcSum1DimArray : LREAL
VAR_IN_OUT
 arrData : ARRAY[*] OF LREAL;
END_VAR
VAR
 nIndex : DINT;
END_VAR
F_CalcSum1DimArray := 0;
FOR nIndex := LOWER_BOUND(arrData, 1) TO UPPER_BOUND(arrData, 1) DO
 F_CalcSum1DimArray := F_CalcSum1DimArray + arrData[nIndex];
END_FOR

Die Funktion erwartet als Eingangsparameter nur noch ein Array von LREAL-Werten. Die Anzahl der Array-Elemente ist variabel. Mit LOWER_BOUND und UPPER_BOUND kann eine Iteration über das gesamte Array durchgeführt werden. Der Quellcode ist deutlich lesbarer als im ersten Beispiel.

PROGRAM MAIN
VAR
 array01 : ARRAY[2..8] OF LREAL := [16.1, 34.1, 4.1, 43.1, 35.1, 2.1, 65.1];
 lrSum01 : LREAL;
	
 array02 : ARRAY[-1..2] OF LREAL := [16.1, 34.1, 9.1, 13.1];
 lrSum02 : LREAL;
	
 array03 : ARRAY[-3..-1] OF LREAL := [16.1, 34.1, 8.1];
 lrSum03 : LREAL;
END_VAR
lrSum01 := F_CalcSum1DimArray(array01);
lrSum02 := F_CalcSum1DimArray(array02);
lrSum03 := F_CalcSum1DimArray(array03);

Beispiel 2 (TwinCAT 3.1.4020)

Auch werden mehrdimensionale Arrays unterstützt. Bei der Deklaration müssen alle Dimensionen als variabel angelegt werden:

arrData : ARRAY[*, *, *] OF LREAL;

Der zweite Parameter von UPPER_BOUND und LOWER_BOUND gibt die Dimension an, von der die jeweilige Arraygrenze ermittelt werden soll.

FUNCTION F_CalcSum3DimArray : LREAL
VAR_IN_OUT
 arrData : ARRAY[*, *, *] OF LREAL;
END_VAR
VAR
 nIndex1, nIndex2, nIndex3 : DINT;
END_VAR
F_CalcSum3DimArray := 0;
FOR nIndex1 := LOWER_BOUND(arrData, 1) TO UPPER_BOUND(arrData, 1) DO
 FOR nIndex2 := LOWER_BOUND(arrData, 2) TO UPPER_BOUND(arrData, 2) DO
 FOR nIndex3 := LOWER_BOUND(arrData, 3) TO UPPER_BOUND(arrData, 3) DO
 F_CalcSum3DimArray := F_CalcSum3DimArray + arrData[nIndex1, nIndex2, nIndex3];
 END_FOR
 END_FOR
END_FOR

Bei dem Aufruf kann ein beliebiges dreidimensionales Array von LREAL-Werten an die Funktion übergeben werden.

PROGRAM MAIN
VAR
 array01 : ARRAY[1..2, 3..4, 5..6] OF LREAL := [16.1, 34.1, 4.1, 43.1, 35.1, 2.1, 65.1, 16.1];
 lrSum01 : LREAL;
END_VAR
lrSum01 := F_CalcSum3DimArray(array01);

Beispiel 3 (TwinCAT 3.1.4020)

Somit lassen sich auch komplexere Aufgaben flexibel umsetzen ohne das auf Pointerarithmetik zurückgegriffen werden muss.

Dieses soll zum Schluss an einem Funktionsblock gezeigt werden, der zwei Matrizen miteinander multipliziert. Die Größen der Matrizen sind variabel:

METHOD PUBLIC Multiplication : BOOL
VAR_IN_OUT
 arrayA : ARRAY[*, *] OF DINT;
 arrayB : ARRAY[*, *] OF DINT;
 arrayX : ARRAY[*, *] OF DINT;	
END_VAR
VAR
 nIndex1, nIndex2, nIndex3, nIndex4 : DINT;
END_VAR;
FOR nIndex1 := LOWER_BOUND(arrayA, 1) TO UPPER_BOUND(arrayA, 1) DO
 FOR nIndex2 := LOWER_BOUND(arrayB, 2) TO UPPER_BOUND(arrayB, 2) DO
 nIndex4 := 0;
 FOR nIndex3 := LOWER_BOUND(arrayA, 2) TO UPPER_BOUND(arrayA, 2) DO
 nIndex4 := nIndex4 + arrayA[nIndex1, nIndex3] * arrayB[nIndex3, nIndex2];
 END_FOR;
 arrayX[nIndex1, nIndex2] := nIndex4;
 END_FOR;
END_FOR;

Die Methode kann mit unterschiedlich großen Arrays aufgerufen werden.

PROGRAM MAIN
VAR
 fbMatrix : FB_Matrix;
 arrayA1 : ARRAY[1..2, 1..2] OF DINT := [1, 2, 3, 4];
 arrayB1 : ARRAY[1..2, 1..2] OF DINT := [5, 6, 7, 8];
 arrayX1 : ARRAY[1..2, 1..2] OF DINT;
	
 arrayA2 : ARRAY[1..3, 1..3] OF DINT := [1, 2, 3, 4, 5, 6, 7, 8, 9];
 arrayB2 : ARRAY[1..3, 1..3] OF DINT := [5, 6, 7, 8, 10, 11, 12, 13, 14];
 arrayX2 : ARRAY[1..3, 1..3] OF DINT;				
END_VAR
fbMatrix.Multiplication(arrayA1, arrayB1, arrayX1);
fbMatrix.Multiplication(arrayA2, arrayB2, arrayX2);

Beispiel 4 (TwinCAT 3.1.4020)


iec-61131-3 oop codesys-v3 twincat plc
Weitere News:
Schreibe einen Kommentar:
Themen:
plc twincat codesys-v3 oop iec-61131-3
Entweder einloggen... ...oder ohne Wartezeit registrieren
Benutzername
Passwort
Passwort wiederholen
E-Mail