Zusätzlich zu einer Instanz noch Struktur anlegen?

Bensen83

Level-1
Beiträge
777
Reaktionspunkte
3
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo. Habe mal ne Grundsatzfrage. :)
Ich habe einen Funktionsbaustein zur Ansteuerung von einem Ventil.
Nun habe ich in dem Programm "Ventil_A" eine Instanz dieses Bausteins deklariert.
Sollte ich nun noch eine Struktur anlegen, welche ich auf die verschiedenen Eingänge, bzw. Ausgänge des Bausteins lege??? Oder würdet ihr eher den Baustein ohne Zuweisungen aufrufen und dann in den weiteren Programmen so: Ventil_A.Indtanz.Eingang drauf zugreifen?

Der Nachteil ohne Struktur wäre, dass ich auf die Ausgänge des Basteins außerhalb des selbigen nicht schreibend zugreifen kann.

Nachteil mit Struktur: ich verbrauche fast den doppelten Speicher. Nämlich einmal
Für die Struktur und einmal für die Instanz.

Was meint ihr?
 
Hallo Bensen,

aus meinem Verständnis ist eine Struktur nicht unbedingt etwas, dass man auf eine Schnittstelle legt wenn es einem doch eigentlich um die Einzel-Elemente in der Struktur geht.

Da es dabei aber keine wirklichen Beschränkungen gibt würde ich es (persönlich) immer so machen, wie ich es für meine Anwendung am besten gebrauchen kann.

Im Falle deines Ventil-Bausteins würde ich sagen, dass du ganz gut damit bedient bist, alle Einzelemente auf die Schnittstelle zu legen ...

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Missverständnis

Sorry war ein Missverständnis.
Meinte auch die einzelnen Elemente des Basteins in eine Struktur zu legen
Nicht eine Struktur auf den Baustein.

Meine frage war jetzt eigentlich ob man besser die ein und Ausgänge des
Basteins direkt anspricht, oder dort die Elemente einer bspw. Globalen Variable vom Typ Ventil drauf legt.

Also vereinfacht Eingänge: Freigabe, vor, zurück
Ausgänge: out_vor, out_zurück

Jetzt eine Struktur vom Typ Ventil anlegen, welche diese Variablen enthält und diese auf die bausteinelemente legen. --> dann im Programm bspw. So die Freigabe. Setzen: global.variable_ventil. Freigabe := True;

Oder direkt drauf zugreifen? Also so:

Programm.bausteininstanz.freigabe := True;

Was ist besser???
 
Welchen Sinn hat denn in diesem Fall noch die Struktur ? Oder was hilft sie dir hier ?

Der Sinn einer Struktur (mal so ins unreine geschrieben) ist es, Elemente (ggf. unterschiedlichen Typs), die zusammen gehören aber nicht unbedingt als zusammengehörig erkannt werden, zusammen zu fassen - also eine Art Gliederung um eine bessere Übersichtlichkeit zu erzeugen. Diese Aufgabe erfüllt in deinem Fall die Instanz schon.

Gruß
Larry
 
Ich bin auch für den direkten Zugriff auf die FB-VAR_INPUT/OUTPUT, dazu sind sie doch da. Eine externe Sruktur macht die Sache nicht übersichtlicher, sondern nur langsamer. Und dass man auf FB-Outputs ausserhalb des FB's nicht schreiben kann, macht doch gerade den Sinn der Output-Variablen aus. Wenn Du das Bedürfnis verspürst, auch im aufrufenden Programm darauf zu schreiben, ist das ein Zeichen dafür, dass Du einen Teil der Funktionalität, die eigentlich in den FB gehört, nicht dort untergebracht hast.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Stimmt

Stimmt, genau der Meinung bin ich auch. Ich hatte nur ein Programm, wo ein Baustein aufgerufen wurde und beim Aufruf die Eingänge und Ausgänge nicht zugewiesen wurden. Das fanden andere irritierend.
Deswegen hatte ich diese frage gestellt.
 
:confused: Wenn du die Eingänge des Bausteins nicht zuweisst ... wozu hast du sie dann und was soll der Baustein dann (ohne sie) tun ?
 
Werden sie ja

Sie werden ja zugewiesen, allerdings vorher im Strukturierten Text.
Und dann eben beim Bausteinsufrug nicht mehr.

Deswegen ja die frage ob erst den Daten einer Struktur zuweisen und dann diese den Eingängen des Bausteins?

Oder eben direkt den Eingängen und dann eben ohne eingangszuweisung aufrufen.

Also zugewiesen werden sie ja schon.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Etwas genauer

... Eine externe Sruktur macht die Sache nicht übersichtlicher, sondern nur langsamer. ...

Stimmt absolut nicht, Die Übergabe einer Struktur mit VAR_INOUT ist so ziemlich das effektiveste, was es beim Aufruf gibt. Es wird lediglich die Adresse der Structur übergeben. Beim Ende des FUB ist sogar gar nix zu tun, da der aufrufende Part weiss, wo die Structur liegt.

Die Rückgabe von mehr als 1 Variablen dagegen ist extrem (intern) Programm aufwändig, der Compiler muss sie auf den Stack packen und die aufrufenden Programmteile wieder runternehmen.

Meine Strategie, wo immer es geht: Struktur anlegen, sie dem FUB Aufruf übergeben, und nachher auswerten.
 
Zuletzt bearbeitet:
Stimmt absolut nicht, Die Übergabe einer Struktur mit VAR_INOUT ist so ziemlich das effektiveste, was es beim Aufruf gibt. Es wird lediglich die Adresse der Structur übergeben. Beim Ende des FUB ist sogar gar nix zu tun, da der aufrufende Part weiss, wo die Structur liegt.

Die Rückgabe von mehr als 1 Variablen dagegen ist extrem (intern) Programm aufwändig, der Compiler muss sie auf den Stack packen und die aufrufenden Programmteile wieder runternehmen.

Bei einem FB (Function-Block)? Glaube ich niemals dass es so läuft.
Wenn Codesys das Rad nicht neu erfinden wollten haben sie auf eine gängige Vorgehensweise für sowas zurückgegriffen. Bei C++ wird bei Methodenaufrufen immer der this-Zeiger übergeben, je nach Aufrufkonvention entweder auf dem Stack oder in einem Register. Dieser Zeiger zeigt auf den Speicherbereich der aktuellen Instanz. Auf die Instanzvariablen wird dann nur noch mit Zeiger+Offset zugegriffen.
Warum sollte da sonst noch groß was auf den Stack gepackt werden? Bei Funktionen ja, denn da bleibt ja keine andere Möglichkeit, aber sicher nicht bei Funktionsbausteinen.
 
Warten wir mal, ob Werner29 sich zum Thema meldet, der muss es schliesslich wissen. An eine VAR_INPUT/OUTPUT-Übergabe per Stack mag ich aber bei FB's auch nicht glauben. Schliesslich kann man im aufrufenden Programm an beliebigen Stellen auf diese Daten zugreifen und nicht nur beim FB-Aufruf. Da wird wohl schon direkt auf die FB-Instanz zugegriffen.
Eine Übergabe per VAR_IN_OUT lohnt sich deshalb nur dann, wenn die Daten nicht nur an einen einzigen FB übergeben werden müssen. Dann macht es auch logisch Sinn, die Daten im Programm zu deklarieren, weil sie eben keinem FB eindeutig zuzuordnen sind.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Struktur sollte nicht als Übergabe gedacht sein

Also ich meinte nicht eine Struktur zu übergeben.
Mir ging es nur darum, wenn jetzt bspw. 7 integer Eingänge auf der bausteinseite sind. Und ich nun Variablen auf diese lege dann benötige ich ja schon Speicherplatz für 14 Integer.
Wenn ich im Programm direkt auf die Instanz zugreifen würde und auf die Variablen verzichte, so würde ich nur Speicherplatz für die 7 Eingangsinteger belegen. Wenn man es so weiterspinnt, benötigt man mit zusätzlichen Variablen, welche auf die Bausteine gelegt werden den doppelten Speicherplatz. Deswegen war die frage von mit ob man nicht besser direkt auf die Instanzen zugreift.
 
@ST:
Ich bin da ganz deiner Meinung ... ist aber auch eher "gefühlt" so ...

@Benson:
Was du vorhast ist klar - es geht hier jetzt schon eher um ein Grundsatz-Thema ...
So, wie du es machst bzw. vorhast, ist es aus meiner Sicht (aus der ferne gesehen) gut und richtig ...

Gruß
Larry
 
Ich habe mal irgendwo eine Anleitung gesehen in der steht wie man C++ Funktionen in Codesys einbinden kann. Das funktioniert ja nur wenn die Aufrufkonventionen gleich sind.

Bevor man aber dieses Dokument finden kann man auch mal für ein ganz einfaches Programmbeispiel den generierten Assemblercode ansehen.
Beispiel mit TwinCAT v2.10:

Quellcode:
Code:
PROGRAM MAIN
VAR
	i : INT;
	mainvar : DWORD;
	outVar : DWORD;
	TESTFBinstance : TESTFB;
END_VAR

mainvar := 16#CAFEBABE;
i := i + 1;
TESTFBinstance(in1 := 16#ABAD1DEA, in2 := 16#BAADF00D, out1 => outVar );
END_PROGRAM

FUNCTION_BLOCK TESTFB
VAR_INPUT
	in1 : DWORD;
	in2 : DWORD;
END_VAR
VAR_OUTPUT
	out1 : DWORD;
	out2 : DWORD;
END_VAR
VAR
	stat1 : DWORD;
END_VAR

stat1 := 16#DEADC0DE;
out1 := in1;
out2 := 16#1234ABCD;

END_FUNCTION_BLOCK

Das erzeugt folgenden x86-Assemblercode:

Für Main:
Code:
mov     eax, 0CAFEBABEh
add     al, 0           ; Add
mov     ds:1E492h, eax
add     al, 0           ; Add
movsx   eax, word ptr ds:1E490h ; Move with Sign-Extend
mov     edx, eax
mov     eax, 1
add     eax, edx        ; Add
add     al, 0           ; Add
mov     ds:1E490h, ax
add     al, 0           ; Add
mov     eax, 0ABAD1DEAh
mov     ds:1E49Eh, eax
mov     eax, 0BAADF00Dh
mov     ds:1E4A2h, eax
add     al, 0           ; Add
lea     eax, ds:1E49Ah  ; Load Effective Address
push    eax
call    ds:dword_50     ; Indirect Call Near Procedure
add     esp, 4          ; Add
mov     eax, ds:1E4A6h
mov     ds:1E496h, eax
add     al, 0           ; Add
pop     esi
pop     edi
pop     edx
pop     ebx
leave                   ; High Level Procedure Exit
retn                    ; Return Near from Procedure

und für TESTFB:
Code:
push    ebp
mov     ebp, esp
push    ebx
push    edx
push    edi
push    esi
mov     ebx, [ebp+8]
push    large dword ptr ds:4018h
mov     large ds:4018h, ebx
add     al, 0           ; Add
mov     eax, 0DEADC0DEh
add     al, 0           ; Add
mov     [ebx+0], eax
add     al, 0           ; Add
mov     eax, [ebx+4]
add     al, 0           ; Add
mov     [ebx+0Ch], eax
add     al, 0           ; Add
mov     eax, 1234ABCDh
add     al, 0           ; Add
mov     [ebx+10h], eax
add     al, 0           ; Add
pop     large dword ptr ds:4018h
pop     esi
pop     edi
pop     edx
pop     ebx
leave                   ; High Level Procedure Exit
retn                    ; Return Near from Procedure

Ohne jetzt der große x86 Assemblerguru zu sein sehe ich folgendes.
Vor Funktionsaufruf wird die Adresse der Instanz als ersten Parameter auf den Stack abgelegt:
Code:
lea     eax, ds:1E49Ah  ; Load Effective Address
push    eax
Im FB wird mit
Code:
mov     ebx, [ebp+8]
der erste Funktionsparameter wieder in Register ebx geladen. Der Offset von 8 Bytes kommt daher, weil davor auf dem Stack noch die Rücksprungadresse und der alte Basepointer ebp liegen.

Im Speicher eines FB werden die Daten in der Reihenfolge VAR, VAR_INPUT, VAR_OUTPUT abgelegt.

DEADC0DE wird auf eine statische Variable geschrieben. Da es nur eine statische Variable gibt müsste das an Offset 0 sein. Wenn man nachguckt stimmt das auch:
Code:
mov     eax, 0DEADC0DEh
add     al, 0           ; Add
mov     [ebx+0], eax
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Thomas_v2.1: Danke für Deine Mühe.

Man sieht ausserdem, dass die INPUT-Variablen direkt in den FB geschrieben und die OUTPUT-Variable ebenso aus ihm gelesen werden. Warum auch nicht, die Adressen sind dem Programm ja genauso bekannt wie die der anderen Variablen. Alles andere wäre auch nicht sinnvoll.
 
Deswegen war die frage von mit ob man nicht besser direkt auf die Instanzen zugreift.
Ja, das ist besser. Sieh es doch mal so: Eine FB-Instanz ist eine Strukturvariable, die zusätzlich noch eine feste Verbindung zu dem zu ihrer Bearbeitung dienenden Code besitzt. Du hast also mit der FB-Instanz bereits eine Variable im Programm deklariert, wenn auch mit teilweise (aber durchaus sinnvoll) eingeschränktem Zugriffsrecht.
 
Struktur vielleicht doch besser

Habe es gerade mal versucht. Denke wenn ich eine Struktur anlegen ist es wohl dich übersichtlicher, weil dann kann ich es so aufbauen dass Ventile, Achsen usw. Immer die gleiche Struktur haben. Bei verschiedenen Bausteinen ist das nicht der fall.

Auch wenn ich den Baustein in der Visu verwenden und es kommt mal was anderes .... Ich weis das ist weit hergeholt, aber so kann ich die Visu lassen wie se ist und dann nur im Programm Anpassungen vornehmen.
So kann ich bspw. Dann auch Programmteile kopieren und in Anlagen benutzen wo bspw. Andere Regler drin sind.
 
Zurück
Oben