Bedingte Pragmas

Bedingte Pragmas dienen dazu, die Codegenerierung im Vorübersetzungsprozess oder Übersetzungsprozess zu beeinflussen. Die Programmiersprache ST unterstützt diese Pragmas.

Bedingte Pragmas 1:

Ab TC 3.1 Build 4024 können Sie die bedingten Pragmas sowohl im Deklarations- als auch im Implementierungsteil verwenden. Dabei werden im Deklarationsteil ausschließlich die Operatoren „defined (<identifier>)“ und „hasvalue (<identifier>, ‘<value>‘)“ für einfache Compilerdefinitionen unterstützt. Die unten genannten Sonderverwendungen der beiden Operatoren sind davon ausgeschlossen. Zudem ist es nicht möglich, die Komponenten einer Enumeration oder den Datentyp eines Alias mit Hilfe von bedingten Pragmas zu definieren.

Bedingte Pragamas werden im SPS Projekt nicht aber in Bibliotheken unterstützt. Bei vorherigen TC 3.1-Versionen werden die Pragmas, die im Deklarationsteil verwendet werden, nicht ausgewertet.

Mit bedingten Pragmas beeinflussen Sie, ob Deklarations- oder Implementierungscode für die Übersetzung berücksichtigt wird. Dies können Sie beispielsweise davon abhängig machen, ob eine bestimmte Compilerdefinition definiert ist oder einen bestimmten Wert hat, ob eine bestimmte Variable deklariert ist, oder ob ein bestimmter Baustein vorhanden ist etc..

Pragma

Beschreibung

Definition im Code:

  • {define <identifier>}
  • {define <identifier> '<value>'}

Beispiele:

  • {define variantA}
  • {define variantA '123'}
  • {define variantA 'true'}

 

Definition in den SPS-Projekteigenschaften:

  • <identifier>
  • <identifier> := '<value>'

Beispiele:

  • variantA
  • variantA := '123'
  • variantA := 'true'
  • variantA := '123', variantB := '456'

Die Definition kann später mit dem defined-Operator abgefragt werden.

Außerdem kann der optional angegebene Wert später mit dem hasvalue-Operator abgefragt und verglichen werden.

{undefine <identifier>}

Die {define}- Anweisung des Bezeichners <identifier> wird aufgehoben, der Bezeichner ist ab jetzt wieder „undefiniert“. Wenn der angegebene Bezeichner gerade gar nicht definiert ist, wird das Pragma ignoriert.

{IF <expr>}...

{ELSIF <expr>}...

{ELSE}...

END_IF}

Dies sind Pragmas für die bedingte Kompilierung.

Die angegebenen Ausdrücke <expr> müssen zur Kompilierungszeit konstant sein; sie werden in der Reihenfolge ausgewertet, in der sie hier erscheinen, bis einer der Ausdrücke einen nicht-Null-Wert zeigt. Der mit der Anweisung verknüpfte Text wird übersetzt; die anderen Zeilen werden ignoriert. Die Reihenfolge der Abschnitte ist festgelegt. Die ELSIF und ELSE Abschnitte sind optional. Die ELSIF-Abschnitte dürfen beliebig oft vorkommen. Innerhalb der Konstanten <expr> können Sie mehrere bedingte Übersetzungsoperatoren verwenden.

<expr>}

Innerhalb des konstanten Ausdrucks <expr> innerhalb eines bedingten Übersetzungspragmas {IF} oder {ELSIF} können Sie einen oder mehrere Operatoren verwenden.

Unterschiedliche Gültigkeitsbereiche

Globale define-Definitionen können Sie als Compilerdefinitionen in den SPS-Projekteigenschaften (Kategorie Übersetzen) oder auf System Manager-Level einen Kontenpunkt darüber (Gruppierung Compiler Defines, siehe Dokumentation Variantenmanagement) eintragen. Die hier definierten Compilerdefinitionen sind im gesamten SPS-Projekt gültig. Außerdem können Sie in den SPS-Projekteigenschaften mehrere define-Definitionen durch Kommas getrennt angeben.

Des Weiteren können Sie im Deklarations- und Implementierungsteil der SPS-Elemente lokale Compilerdefinitionen definieren. Diese sind dann im jeweiligen Deklarations- oder Implementierungseditor gültig.

Siehe auch:

Operator defined (<identifier>)

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält. Voraussetzung ist, dass der Bezeichner <identifier> mithilfe einer {define}-Anweisung definiert wurde und danach nicht mit einer {undefine}-Anweisung wieder undefiniert wurde; ansonsten wird FALSE geliefert.

Beispiel 1:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Variable pdef1 ist durch eine {define}-Anweisung in Plc1 definiert, aber nicht in Plc2.

{IF defined (pdef1)}
    (* This code is processed in Plc1 *)
    {info 'pdef1 defined'}
    hugo := hugo + SINT#1;
{ELSE}
    (* the following code is only processed in Plc2 *)
    {info 'pdef1 not defined'}
    hugo := hugo - SINT#1;
{END_IF}

Hier ist zusätzlich ein Beispiel eines Meldungspragmas enthalten: Nur die Information pdef1 defined wird im Meldungsfenster angezeigt, wenn das SPS-Projekt kompiliert wird, weil pdef1 tatsächlich definiert ist. Die Meldung 'pdef1 not defined' wird ausgegeben, wenn pdef1 nicht definiert ist.

Beispiel 2:

Im folgenden Beispiel wird die Variable sVariantUsed je nach geltendem Compiler-define mit unterschiedlichen Werten initialisiert. Außerdem wird entweder eine allokierte Eingangs- oder eine Ausgangsvariable deklariert. Die Variable nCounter wird in jedem Fall deklariert, d.h. unabhängig von den geltenden Compilerdefinitionen.

{IF defined (Variant1)}
    sVariantUsed         : STRING := 'Variant1';
    bOutput        AT%Q* : BOOL;
{ELSE}
    sVariantUsed         : STRING := 'NotVariant1';
    bInput         AT%I* : BOOL;
{END_IF}
 
nCounter                 : INT;

Operatoren für den Implementierungsteil

Die im folgenden vorgestellten Operatoren können ausschließlich im Implementierungsteil verwendet werden und werden im Deklarationsteil nicht ausgewertet.

Operator defined (variable: <variable>)

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält, wenn die Variable <variable> innerhalb des aktuellen Gültigkeitsbereichs deklariert ist; ansonsten wird FALSE geliefert.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Variable g_bTest ist in Plc1 deklariert, nicht aber in Plc2.

{IF defined (variable: g_bTest)}
    (* the following code is only processed in Plc2*)
    g_bTest := x > 300;
{END_IF}

Operator defined (type: <identifier>)

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält, wenn ein Datentyp mit Bezeichner <identifier> deklariert ist; ansonsten wird FALSE geliefert.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Datentyp DUT ist in Plc1 deklariert, nicht aber Plc2.

{IF defined (type: DUT)}
    (* the following code is only processed in Plc1*)
    bDutDefined := TRUE;
{END_IF}

Operator defined (pou: <pou name>)

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält, wenn ein Baustein mit dem Namen <pou name> vorhanden ist, ansonsten wird FALSE geliefert.

Mit Hilfe der Syntax "pou: <pou name>.<method name>" können Sie außerdem überprüfen, ob der genannte Baustein über Methoden oder Aktionen mit dem genannten Namen verfügt.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Baustein CheckBounds ist in Plc1 vorhanden, nicht aber in Plc2.

{IF defined (pou: CheckBounds)}
    (* the following code is only processed in Plc1 *)
    arrTest[CheckBounds(0,i,10)] := arrTest[CheckBounds(0,i,10)] + 1;
{ELSE}
    (* the following code is only processed in Plc2 *)
    arrTest[i] := arrTest[i]+1;
{END_IF}

Operator defined (IsLittleEndian)

Der Operator bewirkt, dass der Ausdruck den Wert FALSE erhält, wenn die CPU „BigEndian (Motorola Byte Order)“ ist.

Operator defined (IsFPUSupported)

Wenn der Ausdruck den Wert TRUE liefert, erzeugt der Codegenerator FPU (Floating point unit) Code für die Berechnungen mit REAL-Werten. Ansonsten emuliert TwinCAT FPU-Operationen, was jedoch bedeutend langsamer ist.

Operator hasvalue (RegisterSize, '<register size>')

<register size>: Größe eines CPU-Registers in Bit

Der Operator bewirkt, dass der Ausdruck den Wert TRUE liefert, wenn die Größe eines CPU-Registers gleich <register size> ist.

Mögliche Werte für <register size>

Operator hasvalue (PackMode, '<pack mode value>')

Der abgeprüfte PackMode hängt von der Gerätebeschreibung ab, nicht vom Pragma, das für einzelne DUTs angegeben werden kann.

Operator hasattribute (pou: <pou name>, '<attribute>')

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält, wenn das Attribut <attribute> in der ersten Zeile des Deklarationsteils des Bausteins pou-name angegeben ist; ansonsten wird FALSE geliefert.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Eine Funktion fun1 ist in Plc1 und Plc2 definiert, aber in Plc1 ist ihr außerdem das Attribut vision zugewiesen.

In Plc1:

{attribute 'vision'}
FUNCTION fun1 : INT
VAR_INPUT
  i : INT;
END_VAR
VAR
END_VAR

In Plc2:

FUNCTION fun1 : INT
VAR_INPUT
  i : INT;
END_VAR
VAR
END_VAR

Pragma-Anweisung:

{IF hasattribute (pou: fun1, 'vision')}
(* the following code is only processed in Plc1 *)
ergvar := fun1(ivar);
{END_IF}

Siehe auch:

Operator hasattribute (variable: <variable>, '<attribute>')

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält, wenn der Variablen das Attribut '<attribute>' mithilfe der Anweisung {attribute '<attribute>'} in der Zeile vor der Variablendeklaration zugewiesen ist; ansonsten wird FALSE geliefert

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Variable g_globalInt wird in Plc1 und Plc2 verwendet, aber in Plc1 ist ihr zusätzlich das Attribut 'DoCount' zugewiesen.

Deklaration g_GlobalInt in Plc1

VAR_GLOBAL
   {attribute 'DoCount'}
  g_globalInt : INT;
  g_multiType : STRING;
END_VAR

Deklaration g_GlobalInt in Plc2

VAR_GLOBAL
  g_globalInt : INT;
  g_multiType : STRING;
END_VAR

Pragmaanweisung:

{IF hasattribute (variable: g_globalInt, 'DoCount')}
    (* the following code is only processed in Plc1 *)
    g_globalInt := g_globalInt + 1;
{END_IF}

Siehe auch:

Operator hastype (variable: <variable>, <type-spec>)

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält, wenn die Variable <variable> vom Datentyp <type-spec> ist; ansonsten wird FALSE geliefert.

Mögliche Datentypen für <type-spec>:

BOOL | BYTE | DATE | DATE_AND_TIME | DINT | DWORD | INT | LDATE | LDATE_AND_TIME | LINT | LREAL | LTIME | LTIME_OF_DAY | LWORD | REAL | SINT | STRING | TIME | TIME_OF_DAY | ULINT | UDINT | UINT | USINT | WORD | WSTRING

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Variable g_multitype ist in Plc1 mit Datentyp LREAL deklariert, in Plc2 mit Datentyp STRING.

{IF (hastype (variable: g_multitype, LREAL))}
    (*  the following code is only processed in Plc1 *)
    g_multitype := (0.9 + g_multitype) * 1.1;
{ELSIF (hastype (variable: g_multitype, STRING))}
    (* the following code is only processed in Plc2 *)
    g_multitype := 'this is a multitalent';
{END_IF}

Operator hasvalue (<define-ident>, '<char-string>')

Der Operator bewirkt, dass der Ausdruck den Wert TRUE erhält, wenn eine Variable mit Bezeichner <define-ident> definiert ist und den Wert <char-string> hat; ansonsten wird FALSE geliefert.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. Die Variable test wird in den SPS-Projekten Plc1 und Plc2 verwendet; in Plc1 erhält sie den Wert 1, in Plc2 den Wert 2.

Die Compiler-Definition kann entweder in den SPS-Projekteigenschaften über test := '1' oder im Implementierungsteil der POU über {define test '1'} gesetzt werden.

{IF hasvalue(test,'1')}
    (* the following code is only processed in Plc1 *)
    x := x + 1;
{ELSIF hasvalue(test,'2')}
    (* the following code is only processed in Plc2 *)
    x := x + 2;
{END_IF}

Operator NOT <operator>

Der Ausdruck erhält den Wert TRUE, wenn der Umkehrwert von <operator> den Wert TRUE liefert. <operator> kann einer der in diesem Kapitel beschriebenen Operatoren sein.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. PLC_PRG1 ist in Plc1 und Plc2 vorhanden, POU CheckBounds gibt es nur in Plc1.

{IF defined (pou: PLC_PRG1) AND NOT (defined (pou: CheckBounds))}
    (* the following code is only processed in Plc2 *)
    bANDNotTest := TRUE;
{END_IF}

Operator <operator> AND <operator>

Der Ausdruck erhält den Wert TRUE, wenn die beiden angegebenen Operatoren TRUE liefern. <operator> kann einer der in diesem Kapitel beschriebenen Operatoren sein.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. PLC_PRG1 ist in Plc1 und Plc2 vorhanden, die POU CheckBounds nur in Plc1.

{IF defined (pou: PLC_PRG1) AND (defined (pou: CheckBounds))}
    (* the following code is only processed in Plc1,  *)
    bANDTest := TRUE;
{END_IF}

Operator <operator> OR <operator>

Der Ausdruck liefert TRUE, wenn einer der beiden angegebenen Operatoren TRUE liefert. <operator> kann einer der hier beschriebenen Operatoren sein.

Beispiel:

Voraussetzung: Es gibt zwei SPS-Projekte Plc1 und Plc2. PLC_PRG1 ist in Plc1 und Plc2 vorhanden, POU CheckBounds nur in Plc1.

{IF defined (pou: PLC_PRG1) OR (defined (pou: CheckBounds))}
    (* the following code is only processed in Plc1 and in Plc2 *)
    bORTest := TRUE;
{END_IF}

Operator (<operator>)

() klammert die Operatoren.

Siehe auch: