Step 7 Schleife über FB

chomp

Level-1
Beiträge
10
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich rufe innerhalb eines Multiinstanz FB mehrfach den selben FB, allerdings mit verschiedenen instanzen auf.
Ist es Möglich diese in einem Array unterzubringen und dann über eine Schleife aufzurufen?

Ich versuche das mal in einem ganz einfachen Bsp darzustellen:

Aktuell:

Code:
CALL #meinFB_1
  In := M0.0
  Out := M0.1

CALL #meinFB_2
  In := M1.0
  Out := M1.1

CALL #meinFB_3
  In := M2.0
  Out := M2.1

U #meinFB_1.Wert
U #meinFB_2.Wert
U #meinFB_3.Wert
= m5.0

Das würde ich gerne so zusammenfassen:
(Ich schreibe bas mal in Pseudocode: )

Code:
L 0
T "index"

L  3
NEXT: T

  CALL #meinFB_Array["index"]
    In := InArray["index"]
    Out := OutArray["index"]

L "index"
LOOP NEXT

U #meinFB_Array[0].Wert
U #meinFB_Array[1].Wert
U #meinFB_Array[2].Wert
= m5.0

Das mit den Arrays für ein und Ausgansdaten ist noch recht einfach aber wie macht man das für die DBs?
Falls das geht kann man die Schleife dann auch dynamisch erweitern oder muss diese von anfang an festgeletg werden?
Ich hoffe ich konnte verständlich ausdrücken worum es mir geht!

Schöne Grüße
chomp
 
Zuviel Werbung?
-> Hier kostenlos registrieren
.
@chomp

Du rufst in deiner AWL-Schleife den FB OHNE
Instanz-DB und OHNE Bausteinparameter mit
Hilfe deiner Indexvariablen auf:

Code:
...

UC FB  [#index]
...

Der FB wird hier ohne Instanz-DB aufgerufen und
darf damit auch keine Bausteinparameter und keine
statischen Lokaldaten haben.

Du musst also dafür sorgen (wie im Beispiel von
Thomas V2.1 ), das der FB bei jedem Aufruf mit dem
gleichen festen/seperatem Datenbereich arbeitet,
den du vor seinem Aufruf füllen und nachher wieder
in dein ARRAY zurückkopieren musst.

Zum Füllen und Kopieren in den richtigen Array-Bereich
benutzt du auch deinen #index.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Eine saublöde Idee

Im übrigen halte ich nichts von solchen Schweinereien, die aus einer einmaligen Schreibfaulheit des Programmierers resultieren aber für immer das Programm total undurchsichtig machen.
Außerdem ist gar nicht sicher, ob dabei überhaupt irgendwas "gespart" wird, wenn die FB-Aufrufe mit verschiedenen Übergabeparametern versorgt werden müssen.

Harald
 
.
Damit rufst Du allerdings NICHT verschiedene Instanzen eines FB auf sondern verschiedene FB<nr>, deren nr in #index steht.
Harald

Hallo Harald,

ja, genau das habe ich beschrieben.

Der FB hat dann keine Instanz und keine
Bausteinparameter mehr, die müssen wie
bei Larry´s Beispiel von Thomas V2.1 auf
anderen Weg bereitgestellt werden.

Gern kann der TE auch einen FB mit fester
Nummer
in ähnlicher Weise programmieren,
der #index wird dann nur für die Adressierung
der Array-Bereiche benutzt.

Das geht auch.



Im übrigen halte ich nichts von solchen Schweinereien, die aus einer einmaligen Schreibfaulheit des Programmierers resultieren aber für immer das Programm total undurchsichtig machen.
Außerdem ist gar nicht sicher, ob dabei überhaupt irgendwas "gespart" wird, wenn die FB-Aufrufe mit verschiedenen Übergabeparametern versorgt werden müssen.

Harald


Darüber hinaus ist das lediglich eine mögliche
Lösung auf die Frage des TE, ob nun
"Schweinerei" oder "Entenei".

Und der Speicher für die Übergabeparameter
wird doch so oder so schon in seinem Array
vorgehalten.

Gruss
 
Code:
...

UC FB  [#index]
...
Damit rufst Du allerdings NICHT verschiedene Instanzen eines FB auf sondern verschiedene FB<nr>, deren nr in #index steht.
Harald
ja, genau das habe ich beschrieben.
Warum? Das hat der TE doch gar nicht gefragt, siehe
ich rufe innerhalb eines Multiinstanz FB mehrfach den selben FB, allerdings mit verschiedenen instanzen auf.
Ist es Möglich diese in einem Array unterzubringen und dann über eine Schleife aufzurufen?


Gern kann der TE auch einen FB mit fester
Nummer
in ähnlicher Weise programmieren,
der #index wird dann nur für die Adressierung
der Array-Bereiche benutzt.

Das geht auch.
Das geht eben nicht mit Deinem "UC FB [#index]". Deshalb ja auch das aufwändige Kopieren der kompletten Instanzdaten (Übergabeparameter + STAT!) zwischen dem Instanzen-Array und der Ausführ-Instanz im Codebeispiel von Thomas_V2.1


Und der Speicher für die Übergabeparameter
wird doch so oder so schon in seinem Array
vorgehalten.
Es geht nicht um den Speicherplatz sondern: Der Wert der unterschiedlichen Aktualparameter muß in die Array-Instanzen kopiert werden und dann nochmal vom Array in die für den Aufruf genutzte Instanz. Was daran wohl vorteilhaft sein soll??? Da kann man doch auch ganz klassisch mit weniger Aufwand und schön übersichtlich jeden Instanz-Aufruf einzeln ausprogrammieren.

Harald
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Lassen wir das doch mal außen vor ...
Es ging hier um eine Möglichkeit und das wäre eine - wenn auch unschön, das gebe ich zu. Ich hatte aber auch schon ein paar mal den Wunsch nach einem "Array of FB". Es ist eigentlich idiotisch, dass Siemens dies nicht ermöglicht.
Ich habe das dann anders gelösst (trotzdem wäre es schön gewesen ...)

Gruß
Larry
 
.

Hallo Harald !

Die eigentliche Antwort für den TE ist der
UC-Aufruf in seiner AWL-Programmierung,
der ihn seiner Instanz-DB-Übergabe entledigt.

Und beim UC-Aufruf gibt es keine Instanzen
mehr.

Alles weitere ist bereits genannt worden.

Gruss
 
Zuviel Werbung?
-> Hier kostenlos registrieren
.

@ Harald

Bevor ich es jetzt noch vergesse:

Solche Betitelungen wie "eine saublöde Idee"
oder "Schweinerei" haben mich jetzt schon
überrascht, da sie ja vom gerade frisch gekürten
"User des Jahres 2013" hier geäussert werden. :rolleyes:

Gruss



P.S. Gern kannst du (statt bisher lediglich Kritik) deine eigene konstruktive Lösung präsentieren !
 
@SoftMachine
Solche deutlichen "Betitelungen" gehörten schon immer zu meinem Fach-Wortschatz. Vielleicht wurde ich gerade deshalb zum dritten mal in Folge zum "User des Jahres" gewählt?
Tip: versuche doch mal mehr fundierte Fachbeiträge zu schreiben statt Deinem sonst üblichen HIER- und DA-Blabla und halte Dich zurück bei Sachen wo Du keine Ahnung hast, dann wirst Du vielleicht auch mal nominiert ...

Irgendwie scheinst Du das Thema dieses Threads absolut nicht zu verstehen. Anders kann ich mir Dein Beharren an Deinem unsinnigen "UC ..." nicht erklären. Auch wenn Du es vielleicht nicht begreifst, so habe ich doch in diesem Thread hier schon mehr konstruktiven Fachbeitrag geliefert als Du. Dir fallen allerdings nur meine "Betitelungen" auf - für eine Art zu programmieren, die ich ablehne, weil sie in Step7 nicht vorgesehen ist und daher nicht unterstützt wird.

Wenn ich eine Lösung präsentieren wollte, dann würde sie wohl ähnlich wie die schon gleich am Anfang verlinkte Lösung von Thomas_V2.1 aussehen. Hast Du denn schon versucht diese Lösung zu verstehen?

Naja, mal sehen wie weit der TE mit Deinem "UC ..." kommt ...

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

es ist ja eine etwas hitzige Diskussion entfacht.
Leider bin ich am WE nicht dazugekommen das zu testen, werde das aber baldmöglichst tun und dann auch Rückmeldung geben!
Zum Thema:

Der Lösungsvorschlag von SoftMachine scheint auch nicht das zu sein was ich brauche eher das verlinkte von Thomas_V2.1.

Zum Sinn:
Ich finde die Kritik von PN/DP ist durchaus gerechtfertigt, allerdings wenn es sich nicht nur um eine einmalige Tipparbeit handelt sondern um mehrfache und es sich nochdazu nicht nur um 5 - 10 Aufrufe der selben Instanz handelt, sondern das ganze sich im hohen zweistelligen Bereich bewegt, bin ich gerene Bereit über so eine "Schweinerei" nachzudenken!

Schöne Grüße
chomp
 
.. allerdings wenn es sich nicht nur um eine einmalige Tipparbeit handelt sondern um mehrfache und es sich nochdazu nicht nur um 5 - 10 Aufrufe der selben Instanz handelt, sondern das ganze sich im hohen zweistelligen Bereich bewegt, bin ich gerene Bereit über so eine "Schweinerei" nachzudenken! ..
Wenn du schon einmal dabei bist, beim Nachdenken meine ich, dann käme vielleicht auch "meine" Lösung in Betracht. Ich hatte vor Jahren die selben Gedankengänge. Bei ähnlichen und wohl bemerkt über Jahre gut durchdachten Dingen lege ich einmalig einen UDT mit dem Inhalt der "Instanzdaten" an. Diesen UDT vereinbare ich x-fach in einem Global-DB und übergebe den DB an eine FC zur Bearbeitung. Ein zweiter Baustein-Parameter zeigt aus einem bestimmten Grund (bei mir HMI-Anbindung) auf eine weitere (einzelne) Variable von diesem Typ. Aus der DB-Größe und aus der UDT-Größe erkennt die FC die Anzahl der "Instanzen" und bearbeitet eine nach der anderen. In meinem Fall wird pro Zyklus immer nur eine Instanz bearbeitet. Grundlegend wichtig ist dass der UDT wirklich gut durchdacht ist. Nachträgliche Änderungen führen quasi zu einer neuen Generation der gesamten Bibliothek. Diese Schweinerei nenne ich "System" ;) . Wenn man das System kennt, ist es selbst bei komplexen Sachen sehr effektiv und übersichtlich, resourcenschonend und auch leicht zu warten. Bausteinparameter wie Merker, Eingänge, Ausgänge usw. werden einfach durch die Variablen des DB ersetzt, bzw. direkt in den DB geschrieben bzw. gelesen. Vielleicht ist das noch mal ein weiterer Denkanstoß.
 
Ich will mal meine Kritik etwas untermauern - die soll nicht wie unkonstruktives Meckern wirken ;)

Das größte Problem bei dem Wunsch zur Einsparung von Tipparbeit ist, daß auch noch verschiedene Aktualparameter an die Instanzaufrufe übergeben werden sollen. Ob diese Übergaben direkt am Bausteinaufruf gemacht werden oder vorher und nachher in/aus den Array-Instanzen, spart praktisch nichts. Das kann man imho doch schon so grob überschlagen. Oder man schaut es sich mal an:

Das "klassisch" ausprogrammierte Beispiel vom TE (AWL/Pseudocode)
(in Blau die Zeilen, die je Instanz unvermeidbar nötig sind)
Code:
VAR
[COLOR="#0000FF"]    meinFB_1 : meinFB; //Ventil 12Y1 Presszylinder
    meinFB_2 : meinFB; //Ventil 12Y4 Schubzylinder horizontal
    meinFB_3 : meinFB; //Ventil 14Y3 Hubzylinder vorne[/COLOR]
END_VAR

[COLOR="#0000FF"]CALL #meinFB_1
  In := M0.0
  Out := M0.1

CALL #meinFB_2
  In := M1.0
  Out := M1.1

CALL #meinFB_3
  In := M2.0
  Out := M2.1[/COLOR]

U #meinFB_1.Wert
U #meinFB_2.Wert
U #meinFB_3.Wert
= m5.0

Nun die Tipparbeit "sparende" Variante mit Instanz-Array (SCL).
(in Blau die Zeilen, die je Instanz unvermeidbar nötig sind)
(Die Deklaration des TYPE meinFB_t laß ich hier mal weg, weil die mehr oder weniger eine nicht sehr aufwendige Kopie der Variablendeklaration des FB meinFB ist)
Code:
VAR
    FB_ARRAY : ARRAY[0..2] OF meinFB_t; //einzelnen Instanzen kann kein Kommentar und kein eigenes Symbol gegeben werden
    doInst : meinFB;
END_VAR
VAR_TEMP
    i : INT;
END_VAR

BEGIN        
//Eingänge aller Instanzen mit ihren Aktualwerten versorgen:
[COLOR="#0000FF"]    FB_ARRAY[0].In := M0.0;
    FB_ARRAY[1].In := M1.0;
    FB_ARRAY[2].In := M2.0;[/COLOR]

//alle Instanzen aufrufen
    FOR i := 0 TO 2 DO
        // Array-Instanz in Ausführ-Instanz kopieren
        doInst.In    := FB_ARRAY[i].In;
        doInst.Out   := FB_ARRAY[i].Out;
        doInst.Wert  := FB_ARRAY[i].Wert;
        doInst.Stat1 := FB_ARRAY[i].Stat1;
        doInst.Stat2 := FB_ARRAY[i].Stat2;
        doInst.Stat3 := FB_ARRAY[i].Stat3;

        // die Ausführ-Instanz aufrufen
        doInst();

        // Daten von Ausführ-Instanz in Array zurückkopieren
        FB_ARRAY[i].In    := doInst.In;
        FB_ARRAY[i].Out   := doInst.Out;
        FB_ARRAY[i].Wert  := doInst.Wert;
        FB_ARRAY[i].Stat1 := doInst.Stat1;
        FB_ARRAY[i].Stat2 := doInst.Stat2;
        FB_ARRAY[i].Stat3 := doInst.Stat3;
    END_FOR;

//alle Instanz-Ausgänge auf die Ausgangsvariablen schreiben:
[COLOR="#0000FF"]    M0.1 := FB_ARRAY[0].Out;
    M1.1 := FB_ARRAY[1].Out;
    M2.1 := FB_ARRAY[2].Out;[/COLOR]

//Beispiel-Verknüpfung
    M5.0 := FB_ARRAY[0].Wert AND FB_ARRAY[1].Wert AND FB_ARRAY[2].Wert;
END_FUNCTION_BLOCK
Also ich sehe hier kein nennenswertes Einsparpotenzial. Nur eine absolute Verschlechterung der Übersichtlichkeit.

Man spart gerade mal die Zeile mit der Instanz-Deklaration und die Zeile mit dem "CALL Instanz..", hat dafür aber einmalig einen Schreib-Mehraufwand von hier > 15 Programmzeilen (was im realen Programm je nach Anzahl der Instanz-Variablen leicht mehr werden können).
Nochmal: man spart je Instanz gerade mal 2 Programmzeilen, muß dafür aber Nachteile in Kauf nehmen, z.B. verliert man die Möglichkeit, jeder einzelnen Instanz ein eigenes Symbol und einen eigenen Kommentar zu geben.

Falls man das in AWL schreiben will, dann benötigt diese Schreib-"Einsparung" sogar noch mehr Schreibaufwand.
Dann benötigt jede Kopieraktion 2 Programmzeilen (L + T bzw. U + =). In AWL spart man also überhaupt keine Programmzeilen sondern muß sogar mehr schreiben!

Da der meiste unvermeidliche Schreibaufwand in der Versorgung der Eingangs- und Ausgangs-Parameter liegt, ist es praktisch sogar unerheblich, wie aufwändig oder clever der CALL-Code innerhalb der FOR-Schleife gelöst wird, dieser Code fällt ja nur einmal an.

Durch das mehrfache Kopieren der Instanzdaten hat diese Array-Variante eine deutlich schlechtere Performance als die klassisch übersichtlich ausprogrammierte Variante. Der Programmspeicherbedarf wird zudem erheblich größer.

Übrigens kann man auf diese Art keine Variable im selben OB-Zyklus (bzw. beim selben Aufruf des Mutter-FB) von einer Instanz zur nächsten weitergeben, sondern immer erst im nächsten Zyklus, weil die Ausgangsvariablen erst beschrieben werden, nachdem alle Instanzen ausgeführt wurden.

Selbst wenn man alle Übergabeparameter als Pointer deklarieren würde, um das Kopieren der Aktualwerte einzusparen, dann müßte man trotzdem einmal die Pointeradressen in das Instanz-Array schreiben - es spart also auch wieder keine Schreibarbeit.

Es gibt bestimmt noch mehr Probleme, wenn man erstmal richtig drüber nachdenkt...

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich möchte den vielen konstruktiven Beiträgen und Anregungen einmal Rechnung tragen und das ganze etwas näher beleuchten. Danke auch an Mr. Scrooge den Vorschlag finde ich auch sehr interessant!

Konkret geht es darum. Ich habe meien Hütte automatisiert (Ja ich kenne Oscat) und das sieht im Moment so aus:
Code:
// Das findets jeweils in einem Multiinstanz FB statt den ich Pro Raum habe!
//Für jeden Lichtschalter im Haus
      CALL  #Switch
       I_Enabled:=TRUE
       Input    :="E_Switch_Guest"
       Q_SC     :=
       Q_DC     :=
       Q_LC     :=
       Q_Sig    :=

// -----------------------------------------
// Lamp 1
// -----------------------------------------

// Toggle
      O     #Switch.Q_SC
      O     "GivenValueInterface".Lamps.Guest.Toggle
      =     #Toggle

// TurnOn
      O     "GivenValueInterface".Lamps.Guest.TurnOn
      =     #TurnOn

// TurnOff
      O     "StairsBasement".Switch_2.Q_SC
      O     "StairsFirstFloor".Switch_1.Q_DC
      O     "GivenValueInterface".Lamps.Guest.TurnOff
      =     #TurnOff

// TimedOn
      O     #Switch.Q_DC
      O     "GivenValueInterface".Lamps.Guest.TimedOn
      =     #TimedOn


      CALL  #Light
       I_TimedOn:=#TimedOn
       I_Toggle :=#Toggle
       I_TurnOn :=#TurnOn
       I_TurnOff:=#TurnOff
       I_Enabled:="GlobalConfig".Lamps.Guest.Enabled
       I_Time   :="GlobalConfig".Lamps.Guest.TimeOnValue
       Q_On     :=

      U     #Light.Q_On
      =     "A_Li_Guest"
      =     "SystemState".Lamps.Guest

Ich scheue also nicht die Tipparbeit, den es ist alles Fertig und funktioniert! :)
Es ist nur so das ich mit dieser Lösung, wenn ich was am Verhalten ändern will, anfangen muss zu Programmieren. Ok, das geht schnell und einfach, aber noch schneller und einfacher ginge es über ein HMI über Parametrierung statt Programierung.
Dazu hatte ich die Idee alle FB (hier #Switch) über ein Array zu durchlaufen. Dann prüfen welche Signale anliegen. Pro Consumer (hier #Light) gibt es eine Array mit allen Eingangssignalen (DC, SC, LC) und dann wird verglichen ob hierfür eine Aktion (und welche) ausgeführt werden soll. Konkret muss man jedes Eingangssignal (3 pro Taster) mit jedem Ausgangstreiber (4 pro Consumer) prüfen. Also: 3 * [AnzahlTaster] * 4 * [AnzahlConsumer] = (Bei mir >30k). Das das ganze nicht Performanter wird ist mir durchaus klar, mir geht es hier auch mehr am Spaß an der Freude :).

Das Problem mit den benamten Instanzen ist mir durchaus bewusst. Ist mir dann aber auch egal weil ich sowieso jedes Eingangssignal mit jeder Senke teste. Um das in der HMI übersichtlich zu halten Dachte ich an ein Weiteres Array aus UDTs, das die Bezeichnungen der Lichter, Schalter und Steckdosen hält!

schöne Grüße
chomp
 
Zuletzt bearbeitet:
Hallo chomp,

vielleicht ist nicht die Idee falsch sondern der Ansatz ...

Es ist doch nur eine Frage, wen du nach vorne stellst. Du könntest z.B. einen Master-Baustein machen, der dein Array_of_UDT verwaltet. In dem läuft die Schleife, in der die Struktur-Ergebnisse[index] verknüpft werden. Das kann/könnte dann sogar (sofern es nicht eine Timer-Funktion ist) über einen eingelagerten FB abgewickelt werden.
Falls du noch zusätzlich Zeiten brauchst so liesse sich das ja auch ganz gut "zu Fuß" lösen (Systemzeit mit verarbeiten).

Gruß
Larry
 
Hallo Larry,

ich bin mir nicht sicher ob ich deinen Vorschlag richtig verstanden habe.
Du schlägst vor das was ich jetzt als FB gelöst habe (Switch und Light) anstatt als FB als FC löse.

Wie gesagt bin ich mir nicht sicher ob du das so gemeint hast aber ich habe mal darüber nachgedacht und das sollte sich zu einer recht schmucken Lösung ausbauen lassen.

Ich "füttere" den FC dann mit drei UDTs, einen für In, Out, und die Stat. Diese wiederum kann ich in einem Array UDT zusammenfassen welches mehrfach über ein Array instanziert wird.
Das ganze sollte nicht allzu unleserlich werden.

gruß chomp
 
Zurück
Oben