Die Struktur der benötigten H-Datei

logi.CAD 3 erstellt die Implementierungs-Stubs in der H-Datei automatisch, wenn Sie die Anleitung aus dem Artikel "Details: Vendor-Baustein erstellen" befolgen. Dennoch ist es nützlich, wenn Sie die Grundstruktur einer H-Datei kennen.
Die Grundstruktur der H-Datei muss wie folgt sein:

  • include der benötigten Typen
    Wenn der Vendor-Baustein allgemeine Datentypen unterstützen soll, müssen alle relevanten elementaren Datentypen in diesem Abschnitt deklariert werden – falls nicht anderweitig definiert.

  • Typdefinition für den Datentyp des neuen Vendor-Bausteins

  • Initialisierungsmakro für die Typdefinition (= INIT-Makro)

  • nur für Funktionsbausteine erforderlich:

    • Initialisierungsmakro für den Warmstart (= WINIT-Makro)

    • Nameserver-Datenstruktur

  • Implementierung der Funktionalität

Der Inhalt der Typdefinition inkl. der Makros sowie der Implementierung wird beeinflusst durch:

  • die Anweisung { ImplementationProperties ( ) } und einigen ihrer Definitionen (siehe der Artikel "Eigenschaften für das Implementieren von Vendor-Bausteinen" für Details) – zum Beispiel die Definition useUntypedTypeStructure.

  • die Tatsache, ob der Vendor-Baustein allgemeine Datentypen verwendet oder nicht

Die folgenden Beispiele veranschaulichen den erforderlichen Inhalt der H-Datei für einen Vendor-Baustein mit ausschließlich elementaren Datentypen:

images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/warning.svg Falls Ihr Vendor-Baustein komplexere Datentypen (z.B. Strukturen, Arrays, Referenzen, Strings) unterstützen soll, kontaktieren Sie bitte logi.cals.

Beispiel 1: Funktion MUL_01 mit konkretem Datentyp

Die folgende Schnittstelle deklariert eine Funktion mit 2 Eingängen mit dem Datentyp INT.

Beispiel 1 für Schnittstelle
{CustomImplementation}
FUNCTION MUL_01 : INT
VAR_INPUT
IN1 : INT;
IN2 : INT;
END_VAR
END_FUNCTION

Die Anwendung Test_01 ruft den angegebenen Vendor-Baustein MUL_01 auf und weist dessen Ergebniswert der Variablen Var2 zu.

Beispiel 1 für Anwendung mit dem Vendor-Baustein
PROGRAM Test_01
VAR
Var1 : INT := 5;
Var2 : INT;
END_VAR
Var2:=MUL_01(IN1:=2, IN2:=Var1);
END_PROGRAM

Die folgenden Zeilen werden in der H-Datei lcfu___MUL_01.h benötigt, damit logi.CAD 3 in der Lage ist, die Anwendung für Test_01 zu erstellen. Die Zeilen /* ... */ sind lediglich Kommentare, die zur Erläuterung der Struktur hinzugefügt wurden.

Beispiel 1 für H-Datei
/* IEC 61131-3 standard types */
#include <LC3CGBase.h>
 
/* type definition */
typedef struct _LC_TD_Function_MUL_01
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_INT LC_VD_MUL_01;
} LCCG_StructAttrib LC_TD_Function_MUL_01;
 
/* Initialization macro */
#define LC_INIT_Function_MUL_01(p) \
{ \
(p)->LC_VD_MUL_01 = 0;\
}
 
/* implementation */
#define lcfu___MUL_01(LC_this, IN1, IN2, pEPDB) ((LC_this)->LC_VD_MUL_01 = 2*(IN1)*(IN2));

Hier einige grundlegende Erklärungen zu diesem Inhalt:

  • Die Standard-Header-Datei muss enthalten sein, weil der Standard-Datentyp INT verwendet wird.

  • Die Typdefinition muss die folgenden Elemente der POE und deren Datentyp deklarieren:


    Funktionsbausteine

    Funktionen

    →Eingangsvariablen der POE

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    →Ein-/Ausgangsvariablen der POE

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    Ausgang ENO (dessen Datentyp ist immer BOOL)

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    →Ausgangsvariablen der POE

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    lokale →Variablen der POE

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    Ergebniswert der Funktion

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    Hilfsvariablen, die für den Benutzer nicht sichtbar sind
    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/information.svg Diese Hilfsvariablen sind notwendig, um ihre Werte von einer Ausführung der Anwendung bis zur nächsten behalten wird.

    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/check.svg

    Der Datentyp der Variablen und des Ergebniswerts hängt von der angegebenen Schnittstelle ab. Für das obige Beispiel muss für den Ergebniswert LC_VD_MUL_01 der Datentyp INT angegeben werden.
    Deklarieren Sie die Variablen in der Reihenfolge wie in der Tabelle angegeben. Die Reihenfolge kann relevant werden, wenn eine Anwendung mit Hilfe des Ressourcenmanagers aktualisiert (= neu geladen) wird.
    Dies bedeutet:

    • Die erforderliche Reihenfolge für Variablen in einer Herstellerfunktion ist: VAR_IN_OUTENOVAR_OUTPUT – Ergebniswert

    • Die erforderliche Reihenfolge für Variablen in einem Vendor-Funktionsbausteins ist: VAR_INPUTVAR_IN_OUTENOVAR_OUTPUTVAR – Hilfsvariablen, die für den Benutzer nicht sichtbar sind

  • Das Initialisierungsmakro ist für jedes Element erforderlich, das innerhalb der Typdefinition deklariert ist, nicht aber für den Ausgang ENO. Das Initialisierungsmakro ist eine typspezifische Initialisierung.

  • Die Implementierung spezifiziert eine "C-Funktion", die angibt, was die POE tun soll, wenn sie aufgerufen wird. Im obigen Beispiel führt MUL_01 die Berechnung 2*IN1*IN2 durch und weist das Ergebnis dem Ergebniswert LC_VD_MUL_01 zu.
    Alternativ kann die Implementierung auch mit Hilfe einer C-Datei erfolgen. In diesem Fall ist im Vendor-Baustein die Definition functionHasCFile innerhalb der Anweisung { ImplementationProperties ( ) } erforderlich. Informationen über die Struktur einer C-Datei erhalten Sie bei logi.cals .

Wenn Sie die Anwendung für Test_01 erstellen, erzeugt logi.CAD 3 automatisch die folgenden Zeilen in der Datei lcpu___test_01.c für die Zeile Var2:=MUL_01(IN1:=2, IN2:=Var1);:

(Diese Datei befindet sich im Unterordner src-gen des Projekts. Dieser Unterordner ist standardmäßig nicht sichtbar.)

Beispiel 1 für erzeugten C-Code
{
LC_TD_Function_MUL_01 lFunction_MUL_01;
LC_INIT_Function_MUL_01(&lFunction_MUL_01);
lFunction_MUL_01.LC_VD_ENO = LC_EL_true;
lcfu___MUL_01(&lFunction_MUL_01, (LC_TD_INT)2, LC_this->LC_VD_VAR1, pEPDB);
LC_this->LC_VD_VAR2 = lFunction_MUL_01.LC_VD_MUL_01;
}

Hier sind einige grundlegende Erklärungen zu diesem Code (wenn Sie an Details interessiert sind, wenden Sie sich bitte an logi.cals):

  • Zeile LC_TD_Function_MUL_01 lFunction_MUL_01; = Verwendung der Typdefinition (in der H-Datei angegeben); Außerdem wird die Variable lFunction_MUL_01 erstellt.

  • Zeile LC_INIT_Function_MUL_01(&lFunction_MUL_01); = Initialisierung der erzeugten Variablen mit dem Initialisierungsmakro (in der H-Datei angegeben)

  • Zeile lcfu___MUL_01(&lFunction_MUL_01, (LC_TD_INT)2, LC_this->LC_VD_VAR1, pEPDB); = Aufruf der Funktion MUL_01 mit zugewiesenen Parametern; Zunächst wird dem Ergebniswert eine Variable zugewiesen, dann werden die Werte bzw. Variablen den Eingangsvariablen zugewiesen (hier: Literal 2 und Variable VAR1. Zuletzt ird immer der interne Parameter pEPDB aufgeführt.
    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/information.svg Wären Eingangsvariablen der Funktion beim Aufruf der Funktion weggelassen worden, so würde der Initialisierungswert des Datentyps diesen Eingangsvariablen zugewiesen werden.
    images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/information.svg Normalerweise wird der Parameter pEPDB (pointer Entry Point Description Block) nicht benötigt, um einen C-Baustein zu implementieren. Daher können Sie diesen internen Parameter ignorieren. Wenn Sie jedoch bestimmte RTS-APIs verwenden, muss der Parameter pEPDB übergeben werden.

  • Zeile LC_this->LC_VD_VAR2 = lFunction_MUL_01.LC_VD_MUL_01; = Zuweisung der Ergebnisse an die Variable VAR2.

Ergebnis der obigen Implementierung: Wenn Sie die Anwendung auf die integrierte SPS laden, wird die Sicht Variablenwerte den Wert 20 für die Variable Var2 anzeigen.

Beispiel 2: Funktion MUL_02 mit allgemeinem Datentyp

Die folgende Schnittstelle deklariert eine Funktion mit 2 Eingängen, nun mit dem allgemeinen Datentyp ANY.

Beispiel 2 für Schnittstelle
{CustomImplementation}
FUNCTION MUL_02 : ANY
VAR_INPUT
IN1 : ANY;
IN2 : ANY;
END_VAR
END_FUNCTION

Die Anwendung Test_02 ruft den angegebenen Vendor-Baustein MUL_02 auf (ein mit INT typisierter Aufruf und ein anderer mit SINT typisierter Aufruf) und weist dessen Ergebniswert der jeweiligen Variablen zu.

Beispiel 2 für Anwendung mit dem Vendor-Baustein
PROGRAM Test_02
VAR
Var1 : INT := 5;
Var3 : INT;
Var4 : SINT := 5;
Var5 : SINT;
END_VAR
Var3:=MUL_02(IN1:=INT#4, IN2:=Var1);
Var5:=MUL_02(IN1:=SINT#4, IN2:=Var4);
END_PROGRAM

Als Folge davon werden die folgenden Zeilen in der H-Datei lcfu___MUL_02.h benötigt.
images/s/b2ic8e/9012/1ca6q62/_/images/icons/emoticons/warning.svg Wenn Sie den Aufruf mit mehr Datentypen als INT und SINT verwenden würden, würde die H-Datei auch die entsprechenden Zeilen für diese Datentypen erfordern.

Beispiel 2 für H-Datei
#include <LC3CGBase.h>
 
/* type definition for INT */
typedef struct _LC_TD_Function_MUL_02__INT
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_INT LC_VD_MUL_02;
} LCCG_StructAttrib LC_TD_Function_MUL_02__INT;
 
 
/* type definition for SINT */
typedef struct _LC_TD_Function_MUL_02__SINT
{
LC_TD_BOOL LC_VD_ENO;
LC_TD_SINT LC_VD_MUL_02;
} LCCG_StructAttrib LC_TD_Function_MUL_02__SINT;
 
/* initialization macro */
#define LC_INIT_Function_MUL_02__INT(p) \
{ \
(p)->LC_VD_MUL_02 = 0;\
}
#define LC_INIT_Function_MUL_02__SINT(p) \
{ \
(p)->LC_VD_MUL_02 = 0;\
}
 
/* implementation - observe that different implementations are specified for INT and SINT */
#define lcfu___MUL_02__INT(LC_this, IN1, IN2, pEPDB) ((LC_this)->LC_VD_MUL_02 = 3*(IN1)*(IN2));
#define lcfu___MUL_02__SINT(LC_this, IN1, IN2, pEPDB) ((LC_this)->LC_VD_MUL_02 = 3+(IN1)+(IN2));

Ergebnis der obigen Implementierung: Wenn Sie die Anwendung auf die integrierte SPS laden, wird die Sicht Variablenwerte den Wert 60 für die Variable Var3 und den Wert 12 für die Variable Var5 anzeigen.

Beispiel 3: Funktionsbaustein FB_MUL_01 mit konkretem Datentyp

Die folgende Schnittstelle deklariert einen Funktionsbaustein mit 2 Eingängen mit dem Datentyp ANY. und 1 Ausgang mit dem Datentyp INT.

Beispiel 3 für Schnittstelle
{CustomImplementation}
FUNCTION_BLOCK FB_MUL_01
VAR_INPUT
IN1 : INT;
IN2 : INT;
END_VAR
VAR_OUTPUT
OUT : INT;
END_VAR
END_FUNCTION_BLOCK

Die Anwendung Test_01 ruft den angegebenen Vendor-Baustein FB_MUL_01 auf und weist dessen Ausgang der Variablen Var2 zu.

Beispiel 3 für Anwendung mit dem Vendor-Baustein
PROGRAM Test_01
VAR
Var1 : INT := 5;
Var2 : INT;
Inst01 : FB_MUL_01;
END_VAR
Inst01(IN1:=2, IN2:=Var1, OUT=>Var2);
END_PROGRAM

Die folgenden Zeilen werden in der H-Datei lcfu___fb_mul_01.h benötigt, damit logi.CAD 3 in der Lage ist, die Anwendung für Test_01 zu erstellen. Die Zeilen /* ... */ sind lediglich Kommentare, die zur Erläuterung der Struktur hinzugefügt wurden.

Beispiel 3 für H-Datei
/* IEC 61131-3 standard types */
#include <LC3CGBase.h>
 
/* type definition */
typedef struct _LC_TD_FunctionBlock_FB_MUL_01
{
LC_TD_INT LC_VD_IN1;
LC_TD_INT LC_VD_IN2;
LC_TD_BOOL LC_VD_ENO;
LC_TD_INT LC_VD_OUT;
} LCCG_StructAttrib LC_TD_FunctionBlock_FB_MUL_01;
 
/* initialization macro */
#define LC_INIT_FunctionBlock_FB_MUL_01(p) \
{ \
LC_INIT_INT(&((p)->LC_VD_IN1)); \
LC_INIT_INT(&((p)->LC_VD_IN2)); \
LC_INIT_INT(&((p)->LC_VD_OUT)); \
}
 
/* initialization macro for warm boot */
#define LC_WINIT_FunctionBlock_FB_MUL_01(p,RF) { if (RF==0) LC_INIT_FunctionBlock_FB_MUL_01(p) }
 
/* name server data structures - The contents of this section looks different, if it is auto-generated. Keep the auto-generated contents. */
#define LCNS_EL_CNT___FB_MUL_01 0
/* implementation */
#define lcfu___FB_MUL_01(LC_this, pEPDB) ((LC_this)->LC_VD_OUT = 3 * (LC_this)->LC_VD_IN1 * (LC_this)->LC_VD_IN2);

Hier die grundlegenden Unterschiede zum Beispiel für Funktionen:

  • In der Typdefinition müssen die Eingänge des Funktionsbausteins und deren Datentyp deklariert werden.
    Lokale Variablen müssten ebenfalls in der Typdefinition deklariert werden. Dieser Funktionsbaustein hat aber keine lokalen Variablen.

  • Daher werden die Eingänge des Funktionsbausteins auch innerhalb des Initialisierungsmakros benötigt.

  • Das Initialisierungsmakro für den Warmstart (= WINIT-Makro) wird benötigt. Das WINIT-Makro definiert das Verhalten des Funktionsbausteins bei einem Warmstart, während das INIT-Makro das Verhalten bei einem Kaltstart definiert.
    Das WINIT-Makro ist dem INIT-Makro ähnlich, hat aber zusätzlich das Retain-Flag RF.
    Die Zeile #define LC_WINIT_FunctionBlock_FB_MUL_01(p,RF) { if (RF==0) LC_INIT_FunctionBlock_FB_MUL_01(p) } reicht aus, um eine korrekte Codegenerierung zu gewährleisten, wenn eine Instanz des Funktionsbausteins in einem Abschnitt VAR ... END_VAR mit dem Schlüsselwort RETAIN deklariert werden würde.
    Obwohl in diesem Beispiel der Funktionsbaustein in einem Abschnitt VAR ... END_VAR ohne das Schlüsselwort RETAIN deklariert wird, ist es sinnvoll, diese Zeile für das WINIT-Makro zu integrieren. Sie – als Hersteller des Funktionsbausteins – können nicht sicher sein, ob der Funktionsbaustein mit oder ohne das Schlüsselwort RETAIN verwendet werden wird.
    Wenn der Funktionsbaustein selbst einen Abschnitt mit dem Schlüsselwort RETAIN enthält, muss der Inhalt des WINIT-Makros anders aussehen. Bitte kontaktieren Sie logi.cals für Details zu diesem Inhalt.

  • Die Nameserver-Datenstruktur wird ebenfalls benötigt.
    Die Zeile #define LCNS_EL_CNT___FB_MUL_01 0 ist ausreichend, um eine korrekte Codegenerierung zu gewährleisten. Wenn die H-Datei jedoch automatisch generiert wird, sieht der Inhalt anders aus. In diesem Fall müssen Sie den automatisch generierten Inhalt nicht ändern.

  • Die Implementierung gibt die "C-Funktion" für den Funktionsbaustein an, ohne die Eingänge zu spezifizieren. Grund dafür: Die Eingänge werden bereits von der Datenstruktur (LC_this) bereitgestellt.

Ergebnis der obigen Implementierung: Wenn Sie die Anwendung auf die integrierte SPS laden, wird die Sicht Variablenwerte den Wert 30 für die Variable Var2 anzeigen.