__NEW

Der Operator ist eine Erweiterung der Norm IEC 61131-3.

Der __NEW-Operator reserviert dynamisch Speicher für Funktionsbausteine, um benutzerdefinierte Datentypen oder Arrays von Standarddatentypen zu instanziieren. Der Operator gibt einen passend getypten Pointer zurück.

Syntax:

<pointer name> := __NEW( <type> ( , <size> )? );
__DELETE( <pointer name> );
<type> : <function block> | <data unit type> | <standard data type>
// (...)? : Optional

Beispiel:

pScalarType := __NEW(ScalarType, length);

Der Operator __NEW erzeugt eine Instanz des Typs <type> und gibt einen Pointer auf diese Instanz zurück. Anschließend wird die Initialisierung der Instanz aufgerufen. Wenn es sich bei <type> um einen skalaren Standarddatentyp handelt, wird zusätzlich der optionale Operand <size> ausgewertet. Der Operator erzeugt dann ein Array des Typs <standard data type> der Länge <size> (Elementanzahl). Wenn der Versuch Speicher zu allozieren scheitert, gibt __NEW den Wert 0 zurück.

Verwenden Sie den __NEW-Operator innerhalb einer Zuweisung („:=“), ansonsten wird eine Fehlermeldung ausgegeben.

Voraussetzung/Folgen:

Ein Funktionsbaustein (FB) oder ein benutzerdefinierter Datentyp (DUT), dessen Instanz mit __NEW dynamisch erzeugt wird, belegt einen fixen Speicherbereich. Dafür ist es erforderlich, dass Sie die Objekte mit dem Pragma {attribute 'enable_dynamic_creation'} kennzeichnen. Bei FBs/DUTs, die Teil einer Bibliothek sind, ist dies nicht erforderlich.

__NEW 1:

Keine Typänderung per Online-Change möglich

Wenn Sie im Onlinebetrieb das Datenlayout eines FBs/DUTs ändern, welcher mit dem Attribut 'enable_dynamic_creation' gekennzeichnet ist, können Sie anschließend kein Einloggen mit Online-Change ausführen. Der Grund hierfür ist, dass der Speicherbereich der Objekt-Instanz ungültig geworden ist.

Eine Änderung des Datenlayouts liegt vor, wenn bei dem FB/DUT neue Variablen hinzugefügt, bestehende Variablen gelöscht oder Datentypen von Variablen geändert werden. In diesem Fall können Sie ein Einloggen mit Download ausführen.

Routerspeicher:

Dynamischer Speicher wird aus dem Routerspeicherpool alloziert.

__NEW 2:

Statusinformationen des TwinCAT-Routers

Mithilfe des Funktionsbausteins FB_GetRouterStatusInfo aus der Tc2_Utilities-Bibliothek können Sie Statusinformationen des TwinCAT-Routers, wie z. B. den verfügbaren Router-Speicher, aus der SPS auslesen.

Freigabe des Speichers:

Ein mit __NEW reservierter dynamischer Speicher muss mittels __DELETE explizit freigegeben werden. Dies muss entweder bereits im gleichen Taskzyklus oder spätestens vor dem Herunterfahren der SPS geschehen. Andernfalls kann es zu einem sogenannten Speicherleck (memory leak) kommen. Infolgedessen können andere Programmteile keinen Speicher mehr reservieren, wodurch ein instabiles System entstehen kann. Es wird die Verwendung der SPS-Bibliothek Tc3_DynamicMemory empfohlen, um die Handhabung mit dynamischem Speicher zu vereinfachen.

Allozieren einer STRING-Variablen:

Wenn Sie einen STRING der Länge cLength allozieren möchten, verwenden Sie BYTE anstelle von STRING als Datentyp.

VAR CONSTANT
    cLength : UINT := 150;
END_VAR
VAR
    bNew    : BOOL := TRUE;
    pString : POINTER TO STRING(cLength);
    bDelete : BOOL;
END_VAR
IF bNew AND (pSTRING = 0) THEN
    pString := __NEW(BYTE, cLength);
    bNew    := FALSE;
END_IF

IF bDelete THEN
    __DELETE(pSTRING);
    bDelete := FALSE;
END_IF

Beispiel mit Struktur:

Struktur ST_Sample:

{attribute 'enable_dynamic_creation'}
TYPE ST_Sample :
STRUCT
    a,b,c,d,e,f : INT;
END_STRUCT
END_TYPE

Programm MAIN:

PROGRAM MAIN
VAR
    pDut    : POINTER TO ST_Sample;
    bNew    : BOOL := TRUE;
    bDelete : BOOL;
END_VAR
IF bNew AND (pDut = 0) THEN
    pDut := __NEW(ST_Sample);
    bNew := FALSE;
END_IF

IF bDelete THEN
    __DELETE(pDut);
    bDelete := FALSE;
END_IF

Beispiel mit Funktionsbaustein:

Funktionsbaustein FB_Dynamic:

{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK FB_Dynamic
VAR
    nCounts : INT;
END_VAR

Methode Increase:

METHOD Increase : INT
VAR_INPUT
    nCountStep : INT;
END_VAR
nCounts := nCounts + nCountStep;
Increase := nCounts;

Programm MAIN:

PROGRAM MAIN
VAR
    pFB       : POINTER TO FB_Dynamic;
    nResult   : INT;
    nIncrease : INT := 5;
    bNew      : BOOL := TRUE;
    bDelete   : BOOL;
END_VAR
IF bNew AND (pFB = 0) THEN
    pFB := __NEW(FB_Dynamic);
    bNew := FALSE;
END_IF

IF (pFB <> 0) THEN
    nResult := pFB^.Increase(nCountStep := nIncrease);
END_IF

IF bDelete THEN
    __DELETE(pFB);
    bDelete := FALSE;
END_IF

Beispiel mit Array:

Programm MAIN:

PROGRAM MAIN
VAR
    bNew        : BOOL := TRUE;
    bDelete     : BOOL;
    pArrayBytes : POINTER TO BYTE;
    nTest       : INT;
END_VAR
IF bNew AND (pArrayBytes = 0) THEN
    pArrayBytes := __NEW(BYTE, 25);
    bNew := FALSE;
END_IF

IF (pArrayBytes <> 0)THEN
    pArrayBytes[24] := 125;  // writing a value to the last array element
    nTest := pArrayBytes[24];
END_IF

IF bDelete THEN
    __DELETE(pArrayBytes);
    bDelete := FALSE;
END_IF