TIA FC statt FB verwenden um Ressourcen zu sparen ?

smartie

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

leidiges Thema, ja ich weiß. - Aber da ich gerade dazu "gezwungen" bin bei meinem Programm etwas Speicheroptimierung zu betreiben habe ich mir einen meiner
Funktionsbausteine mal vorgenommen und als FC erstellt. - Grundsätzlich meine ich den Unterschied zwischen FB und FC zu kennen und war deshalb auch der
Meinung ich sollte meinen Code als FB erstellen.

Folgenden Code habe ich nun als Funktion FC für eine S7-1214C erstellt und er funktioniert auch scheinbar korrekt wenn ich ihn mehrfach aufrufe:

Code:
FUNCTION "FC_1001 - Array_Char_Suche" : Void
{ S7_Optimized_Access := 'TRUE' }

VERSION : 0.1
   VAR_INPUT 
      Daten_Array : Array [1 .. 1024] of Char;
      Start : Bool;
      Versatz : Int;
      Zeichen : Byte;
   END_VAR

   VAR_OUTPUT 
      Position : Int;
      Fertig : Bool;
   END_VAR

   VAR_TEMP 
      Zaehler_Max : Int;
      Array_Max : Int;
      Daten_Array_Index : Int;
   END_VAR

BEGIN
      // ARRAY_DURCHSUCHEN
      // Die Funktion 'ARRAY_DURCHSUCHEN' durchsucht ein Array mit einer festen Länge von 1024 Byte
      // nach dem am Eingang 'Zeichen' definierten Zeichen.
      // Dabei kann über den Eingang 'Versatz' der Beginn der Suche im Array bestimmt werden.  Wird
      // als Versatz 0 eingestellt, beginnt die Suche mit dem ersten Zeichen des Array.
    
        #Array_Max := 1024;     
        IF #Start = TRUE THEN GOTO Sprungmarke_1;
           Sprungmarke_1:
             #Position := -1;
             #Fertig := FALSE;
             #Zaehler_Max := #Array_Max - #Versatz;
             GOTO Sprungmarke_2;
           Sprungmarke_2:  
              FOR #Daten_Array_Index := #Versatz + 1 TO #Zaehler_Max DO
                  IF #Daten_Array[#Daten_Array_Index] = #Zeichen THEN
                    #Position := #Daten_Array_Index;            
                     EXIT;
                  END_IF;
              END_FOR;
                #Fertig := TRUE;
        ELSE;
        #Fertig := FALSE;
        END_IF;
      
END_FUNCTION

Die Frage die ich mir nun stelle ist: Funktioniert der Code sicher immer als Funktion, oder wäre es besser weiter einen FB zu verwenden?

Prinzipiell hätte ich einen FB bevorzugt, da ich der Annahme bin das das sicherer ist, aber so langsam geht mir der Arbeitsspeicher aus,
da ich die Funktion mehrmals aufrufen muss und jede Instanz 1040 Byte Speicher belegt.

Gruß smartie
 
Grundsätzlich meine ich den Unterschied zwischen FB und FC zu kennen und war deshalb auch der
Meinung ich sollte meinen Code als FB erstellen.
Ehrlich gesagt, sehe ich hier überhaupt keinen Grund für einen FB.
Den FB benutzt man, um im Instanzdatenbaustein Daten von Zyklus zu Zyklus speichern zu können. Das muss man beim FC dann z.B. über InOuts und externe Speicherstellen lösen. Solche Daten sehe ich hier aber nicht.



In Deinem Code selbst sind aber einige überflüssige Sachen vorhanden:
Code:
        IF [COLOR=#ff8c00]#Start = TRUE[/COLOR] THEN [COLOR=#ff0000]GOTO Sprungmarke_1;
           Sprungmarke_1:[/COLOR]
             ...
             [COLOR=#FF8C00]#Fertig := FALSE;[/COLOR]
             ....
             [COLOR=#ff0000]GOTO Sprungmarke_2;
           Sprungmarke_2:[/COLOR] 
             
           ....
        [COLOR=#FF8C00]ELSE[/COLOR][COLOR=#FF0000];[/COLOR]
             [COLOR=#FF8C00]#Fertig := FALSE[/COLOR];
        END_IF;
#Start selbst hat schon den Wert TRUE oder FALSE. Man muss also keinen Vergleich auf TRUE machen, der dann als Ergebnis auch nur TRUE oder FALSE liefert.
Und wozu die GOTOs (die an sich schon in der Programmierwelt ziemlich geschasst sind), um dann nur in die nächste Zeile zu springen? Also mehr als überflüssig.
Und die FALSE-Zuweisung an #Fertig machst Du so oder so. Warum also 2x programmieren, wenn's einmal am Anfang auch genügt.
Code:
        #Array_Max := 1024;    
        #Fertig := FALSE;
       IF #Start THEN 
             #Position := -1;
             #Zaehler_Max := #Array_Max - #Versatz;
              FOR #Daten_Array_Index := #Versatz + 1 TO #Zaehler_Max DO
                  IF #Daten_Array[#Daten_Array_Index] = #Zeichen THEN
                    #Position := #Daten_Array_Index;            
                     EXIT;
                  END_IF;
              END_FOR;
               #Fertig := TRUE;
        END_IF;
 
Zuletzt bearbeitet:
@Matze
Egal wie du das Array an den FB bindest, es landet dann aber immer als Lokale Kopie in der Instanz.

@TE
Eine Sache ändert sich aber beim FB->FC:
Position ist nur noch in Verbindung mit Fertig gültig,
ansonsten steht Müll drin.

So oder so, du bist in einem Zyklus fertig, und somit musst du auch nichts speichern.

Mfg Manuel
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@MSB nein:

Es wird nur eine art Pointer auf den Speicherbereich gebildet, der via InOut an einen FB angebunden wird.
Ich mache das bei sehr vielen meiner Bausteine, wenn ich auf Global-DBs zugreife. Warum sollte ich alles doppelt in
der CPU haben...

Schau dir mal eine InOutVariable an, wenn du z.B. einen Struct anbindest der 1024Byte groß ist, hat die InOut Variable maximal die größe von einem Pointer (Glaube 4 Byte).

Grüße

Marcel
 
Das wäre dann aber ein very Special Feature ab 1200.

Gesendet von meinem GT-I9505 mit Tapatalk
 
Vielen Dank erst mal für die Antworten, daraus ergeben sich ein paar Fragen/Erkentnisse:

So oder so, du bist in einem Zyklus fertig, und somit musst du auch nichts speichern.
- Genau das ist doch die Kern-Frage. Woher weiß ich das ich in einem Zyklus fertig bin?

Man könnte auch beim FB bleiben und das Array via InOut anbinden.
- Funktioniert wirklich. Habe ich noch nicht gewusst. Aber statt 1040 Byte belegt der Instanzdatenbaustein jetzt nur noch 40 Byte.
Ich habe noch einen anderen Baustein mit ca. 12 Instanzen, der jeweils ein Array mit 1024 Byteam Input und Output hat. Die habe
ich beide an INOUT gelegt und Schwupp hab ich schon wieder viel mehr Speicher frei.

In Deinem Code selbst sind aber einige überflüssige Sachen vorhanden...
- Vielen Dank für den Hinweis. Das war mein erster Gehversuch in SCL. Ich hatte in der Richtung vorher noch nichts gemacht und
bin froh das ich es soweit hinbekommen habe.

Gruß smartie
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So oder so, du bist in einem Zyklus fertig, und somit musst du auch nichts speichern.
- Genau das ist doch die Kern-Frage. Woher weiß ich das ich in einem Zyklus fertig bin?
Weil zum Einen der Programmcode in einem einzigen Zyklus durchlaufen wird (keine Sprünge wegen Timer o.ä.) und zum Anderen vor allem auch keine Daten von Zyklus zu Zyklus gespeichert werden.


Es wird nur eine art Pointer auf den Speicherbereich gebildet, der via InOut an einen FB angebunden wird.

Schau dir mal eine InOutVariable an, wenn du z.B. einen Struct anbindest der 1024Byte groß ist, hat die InOut Variable maximal die größe von einem Pointer (Glaube 4 Byte).
Gut zu wissen.
Dann werd' ich mir sicher angewöhnen, bei größeren Datenmengen den InOut auch dann zu benutzen, wenn von Ihnen nur gelesen werden soll. So wie hier z.B. bei dem Code von smartie.
 
Weil zum Einen der Programmcode in einem einzigen Zyklus durchlaufen wird (keine Sprünge wegen Timer o.ä.) und zum Anderen vor allem auch keine Daten von Zyklus zu Zyklus gespeichert werden.

Das ich (in diesem Baustein) keine Daten habe, die von Zyklus zu Zyklus gespeichert werden müssen war ein Grund warum ich überhaupt auf die Idee gekommen bin es mit einem FC zu probieren.


Was ich aber nicht verstehe ist was du mit
... keine Sprünge wegen Timer o.ä.
meinst. :confused:


Gruß smartie
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Was ich aber nicht verstehe ist was du mit
... keine Sprünge wegen Timer o.ä.
meinst. :confused:
Du durchsuchst ein Feld mit einer Schleife nach der Position eines bestimmten Zeichen.
Das machst Du momentan komplett in einem Zyklus. Je nach Größe des Feldes kann es bei sowas zu Zykluszeitüberschreitungen kommen. Deshalb kann man die Schleife auch auf mehrere Zyklen aufteilen, z.B. in dem man den Zähler nur einmal je Zyklus erhöht. Alternativ kann man dies auch per Timer machen, um z.B. zwischenzeitlich andere umfangreiche Aufgaben erledigen zu können.
Durch diese Aufteilung ergeben sich halt wieder Daten, die von Zyklus zu Zyklus gespeichert werden müssen.
 
Jetzt noch ne dumme frage hinterher ;)

Warum wollt ihr InOut nur bei lesenden Zugriffen nutzen? Wie der name schon sagt kann man lesen und schreiben.
Oder ist euch die Querverweisliste heilig (Dort taucht es ja vermutlich nicht auf), ggf. bei Überlappende Zugriffe ... müsste man mal schauen.


Bisher hatte ich nur einmal das Thema das sich jemand darüber aufgeregt hat das eine Verwendung in der Querverweisliste nicht auftauchte, und für den gab es dann folgendes bei der Verwendungsstelle des nicht erkannten Zugriffes:

Code:
// FB mit Zugriff

// Laden eines Wertes der im oberen Baustein verwendet wird damit er in der
// Querverweisliste auftaucht.
L DB100.DBW0
L DB100.DBW2
CLR

Damit waren alle zufrieden, auch wenn es für meinen Geschmack "nicht sauber" aussieht.

Grüße

Marcel
 
Warum wollt ihr InOut nur bei lesenden Zugriffen nutzen? Wie der name schon sagt kann man lesen und schreiben.
Vlt. hab' ich mich da unklar ausgedrückt.
Wenn ich auf die Daten lesend und schreibend zugreifen will, ist INOUT ja so oder so die entsprechende Wahl.

Wenn ich aber Daten habe, auf die ich nur lesend zugreifen will, würde ich mich im Normalfall für einen IN entscheiden. Mit Deiner für mich neuen Information wird da aber sicher in Zukunft auch eine andere Auswahl stattfinden.
:)
 
Zurück
Oben