Großen FB in 2 Teile splitten - knifflig.

rs-plc-aa

Level-1
Beiträge
727
Reaktionspunkte
57
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

Ich bin jetzt das erste mal über die 16kB Limitierung gestolpert die für Bausteine gilt wenn eine CPU kleiner 317 verwendet wird.

Für die die das noch nicht wissen:

Die SIMATIC (egal ob 300 oder 400) hat eine generelle begrenzung für einzelne Bausteine auf 64kB. Dies geht bei der CPU 317 los und geht bis zur größten 400er. Die CPUs 315 und kleiner sind pro Baustein auf 16kB begrenzt - und hier liegt jetzt mein Problem...

Ich habe einen FB mit ziemlich umfangreicher Schnittstelle und sehr viel Code als eine Art "Black-Box" gebaut - d.h. er hat viele Optionen die nicht immer gebraucht werden aber von aussen über die Schnittstelle aktiviert werden können.

Dieser beinhaltet auch eine Schrittkette auf Basis einer Wortvariable (Schrittnummer).

Da das gute Stück von Projekt zu Projekt stetig wächst (immer mehr Optionen kommen hinzu) und ich eigentlich schon das ganze am stück behalten will weil es einfach besser zu pflegen ist stehe ich nun vor dem Problem dass ich ihn nicht mehr in eine 315er reinkriege - diese würde aber dieses mal reichen weil es verhälnismäßig wenig optionen sind, ein großteil also nicht genutzt wird.

Ich habe schon Überlegungen angestrengt bestimmte Teilfunktionen auszulagern - aber gerade diese bringen Speicherplatztechnisch am wenigsten.

Ich müsste also die Schrittkette splitten.

Angenommen es sind 100 Schritte und 50 davon packe ich in einen neuen FB, wie wäre jetzt die optimale Vorgehensweise die beiden Schnittstellen zu gestalten daß das ganze nachher noch so läuft als wäre es im selben FB ?

Die Schlüsselvariable wäre wohl die Schrittnummer - diese könnte z.B. in ein Merkerwort verlagert werden und an beiden FBs als IN_OUT Parameter gesetzt werden.

Aber da sind noch viele Eingänge und Durgangsparameter die auch immer für beide Teile gebraucht werden.

Müsste ich da einfach die Schnittstelle komplett vom einen zum anderen übernehmen ?

Zu dem habe ich den Verdacht daß die statischen Variablen ebenfalls in "neutrales Gebiet" ausgelagert werden müssen...


Ich dachte ich frage mal ob jemand schon ein ähnliches Problem bewältigt hat denn jeder Versuch kostet sehr viel zeit (es muss ja auch getestet werden)...


Bin für alle Anregungen und Tips dankbar!
 
Was wird denn zu groß? Der FB, oder der Instanz-DB?

Ist es der FB, so würde ich den einfach teilen und die beiden neuen FB unmittelbar hintereinander mit dem selben Instanz-DB aufrufen.

Ist es der DB wirds schwieriger. Dann muß man die Teilung so vornehmen, daß die statischen Daten aufgeteilt werden und im zweiten FB die in-, out und in_out-Parameter am Anfang in den eigenen Bereich und am Ende wieder zurück geschrieben werden. Fängt der statische Bereich im Instanz-DB zum Bleistift bei dbx8.0 an, so kopiert man die ersten 8 Byte aus dem ersten INst-DB in die ersten 8 Byte des zweiten Inst-DB und am Ende des zweiten FB umgekehrt. Man kann das latürnich auf den statischen Datenbereich erweitern, so weit das not tut.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo!

Verwendest du in deiner Schrittkette sehr viele kleine (vom speicher) Schritte oder eher große Schritte.
Wenn du jetzt einen große Schritt hast dann kannst du den ja in einen FC / FB schreiben und zu gegebener Zeit dann deinen FB "Schritt x" aufrufen.

godi
 
Hi,

also spontan denke ich:

call fb1, db1

call fb2, db1

aber das macht s7 ja nich freiwillig mit.


Meine jetzt rein theoretische Idee:

FB1 und FB2 müssen im Delarationsteil identisch sein.

dann:

call fb1,db1
call fb2,db2

zu Beginn des FB2 umschalten auf die Instanz DB1 und mit dem zweiten Teil des Codes in der ersten Instanz fertigrechnen.

wie das Umschalten genau zu bewerkstelligen wäre, kein konkreter Plan. Wenn ich da aber eine ungefähr richtige Ahnung hab, wird entweder AR2 als Pointer auf die Instanz benutzt (würde bedeuten: am ende von FB1 AR2 sichern, zuBeginn von FB2 wiederherstellen) oder ein schlicher AUF DI1 zu Beginn von FB2.

keine Ahnung, aber mal so ne Idee - vielleicht in anderer Richtung ausbaufähig?

Gruß
 
Hallo,

Ich bin jetzt das erste mal über die 16kB Limitierung gestolpert die für Bausteine gilt wenn eine CPU kleiner 317 verwendet wird.

...
Ich müsste also die Schrittkette splitten.

Angenommen es sind 100 Schritte und 50 davon packe ich in einen neuen FB, wie wäre jetzt die optimale Vorgehensweise die beiden Schnittstellen zu gestalten daß das ganze nachher noch so läuft als wäre es im selben FB ?

...
Bin für alle Anregungen und Tips dankbar!

Ich beschränke mich auf 32er-Schrittketten, deren Zustand sich einfach in einem DW abbilden läßt. Fordert die Anlage mehr als eine 32er-Schrittkette, so verkette ich diese und setze z.B. mit dem "Fertig-Bit" des einen, das Startbit der nächsten.
Hab aber auch schon die Struktur "Masterschrittkette" die wieder einzelne Detailschrittkette anstößt verwendet und zu synchronisierung auf das "Fertig-Bit" der einzelnen Schrittketten wartet.

An die 16kB-Grenze bin ich bisher noch nicht gestoßen - aber gut zu wissen, wobei einige mit Graph7 programmierte SK da nicht weit davon weg waren.

hth

kiestumpe
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

wir hatten das gleiche Problem und haben es bisher wie folgt gelöst:

1. Zusammenfassen ähnlicher Schritte / Unterscheidung der auszuführenden Aktionen über Flags.

2. Auslagerung der Teile die vor/nach jedem Schritt ausgeführt werden sollen in je einen Prolog-/Epilog-FC. Hier geschieht z.B. das Multiplexen von Eingangsvariablen u.ä.

Gruß Christian
 
Hallo RS,
für mich wäre der Aufhänger bei deinem "Super"-FB auch die Schrittkette.
Wenn du mittels eines MW's als Zähler arbeitest, wie ist das konkret gelöst ? SPL-Befehl ? Oder vergleichst du bei jedem Schritt auf den korrekten Wert ?
Wie auch immer, ich könnte mir vorstellen, das du mit Schritt-Merkern (1 Merker für jeden Schritt) einiges an Platz sparen könntest. Vielleicht wäre das eine Überlegung wert. Wieviel kB's nimmt der Baustein den zuviel in Anspruch ?

Gruß
LL
 
Kannst Du nicht mal einen Auszug aus dem FB hier reinstellen. Also damit man weis Wie Du die Kette Aufgebaut hast. Das Splitten wäre für mich zweite Wahl aber mach bar. Erste Wahl wäre wie einige Kollegen hier ja schon angedeutet haben die Struktur zu verändern. Und einiges in untergestellte FC auszulagern.

Da ihr aber schon mehrere Anlagen mit den SKs drausen habt ist wahrscheinlich die Splitt Variante zwar etwas "quick and dirty" aber einfach zu Händeln. Aber selbst um da weitere Tipps geben zu können müsste man den Aufbau kennen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi,

also spontan denke ich:

call fb1, db1

call fb2, db1

aber das macht s7 ja nich freiwillig mit.


Meine jetzt rein theoretische Idee:

FB1 und FB2 müssen im Delarationsteil identisch sein.

dann:

call fb1,db1
call fb2,db2

zu Beginn des FB2 umschalten auf die Instanz DB1 und mit dem zweiten Teil des Codes in der ersten Instanz fertigrechnen.

wie das Umschalten genau zu bewerkstelligen wäre, kein konkreter Plan. Wenn ich da aber eine ungefähr richtige Ahnung hab, wird entweder AR2 als Pointer auf die Instanz benutzt (würde bedeuten: am ende von FB1 AR2 sichern, zuBeginn von FB2 wiederherstellen) oder ein schlicher AUF DI1 zu Beginn von FB2.

keine Ahnung, aber mal so ne Idee - vielleicht in anderer Richtung ausbaufähig?

Gruß

Hallo!

Ja die zwei FB's müssen in der Deklaration gleich sein und den zweiten FB rufst du dann mit CC / UC auf dann brauchst du keine Parameter mehr übergeben.
siehe dazu http://www.sps-forum.de/showthread.php?t=14604&highlight=fb+aufruf
zum Schluss von dem Thread habe ich das mal ausprobiert einen FB mit CC / UC aufrufen.

godi
 
...das finde ich dann aber mehr dirty als quick. Würde ich mir nicht antun.

ich würd es tun, wenn es fremder Code ist, den ich mal ausnahmsweise in eine Maschine reinpressen muss. Ansonsten ist es auf Dauer keine Lösung.

Aber gut, ich hatte auch schon Bausteine mit mehr als 16k, die hätt ich auch so überhaupt nicht auseinandernehmen können, weil eben die gesamte Datenbasis von ebendieser Logig bearbeitet werden musste. Da hätte ich eventuell dann so gesaut, wenn es unbedingt nicht eine 318 hätt sein dürfen.

Aber schlecht, ohne Kenntnis des Codes hier Ratschläge zu geben.

Wie gesagt, wenn Weiterentwicklung geplant, sollte es schon eine saubere Lösung sein - im Zweifel dann eben doch eine 317 statt 315.

Gruß
 
ich finds auch schöner, nicht zu murksen. Aber man darf doch mal mit dem Gedanken spielen, wenn so ne Systemgrenze erreicht ist:p

Schmiermerker zu S5-Zeiten waren ja auch Murks:ROFLMAO:
 
Wehn du plitte wolte kontte sie ein FB machen und in diese FB wieder kleinere FB's als Instans aufruffe.
So sind alle daten in eine DB und so kunte sie die daten in de verschiedene unterprogramme auf dieser daten eingreifen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

erst mal riesen Dank für die vielen Antworten !

Ich bin gestern unmittelbar nach threaderöffnung zur Baustelle gefahren und kam auch erst um 1:00 Uhr (am) wieder zurück, hatte dann zwar neugierigkeitshalber die Antworten noch überflogen aber da die Streichhölzer an meinen Augen zu knicken drohten habe ich das noch mal verschieben müssen...

Da doch ein paar verschiedene Ansätze genannt wurden möchte ich jetzt noch mal kurz versuchen die Problemstellung besser einzugrenzen - sagt Bescheid wenn ich noch was vergessen habe.

Die Schrittkette funktioniert nach dem Prinzip des Vergleichens auf gleich, vielleicht wäre eine Sprungleiste besser aber da habe ich nicht so viel Spielraum mit der Nummernvergabe (reserve, Gruppierung, etc.)

Ich habe mir natürlich auch noch jede Menge Gedanken dazu gemacht, habe jetzt gestern zwar eine 317er eingebaut weil es pressiert hat aber die ist auch nachher gleich wieder gewechselt.

Ich wollte es mal so angehen:

- Ähnliche Schrittreihen zusammenfassen und mit Bits den Grund des Schritts speichern um am Ende richtig verzweigen zu können.
z.B. ist ein Abschaltevorgang oft gleich - nur der Grund und das anschließende Ziel ein anderes - so könnte der Vorgang vereinheitlicht werden und mit hilfe des Grundes unterschieden werden wohin es anschließend geht.

Das Problem scheint auf jeden Fall die menge an Code zu sein und nicht die Schnittstelle (weswegen auch der IDB nicht zu groß ist sondern nur der FB)

- Es gibt 2 Arten von Schrittreihen -> Verschiedene Start- und Stopreihen und den Dauerbetrieb

Mein Gedanke jetzt: Start/Stop+Allgemeines vom Dauerbetrieb trennen (ob das dann ca. 50/50 ist muss ich mal noch sehen).

Dann müssten die 2 FBs in etwa so aussehen:

1.) Gemeinsame (bzw. identisch angelegte) IN, IN_OUT, Temp
2.) Alles was vorher STAT war in einen Global DB legen und beiden als IN_OUT anhängen - dies beinhaltet u.A. auch die Schrittnummer.
3.) Eingebettete Multiinstanz FBs wie z.B. der SFB4 (TON) bei beiden anlegen (separat)

Bleibt nun nur zu prüfen ob das dann auch funkt...

Wichtig ist eben nur die gemeinsame Schrittnummer da immer nur ein Schritt scharf sein darf und jederzeit durch ein Abbruchereignis o.Ä. in den Stop-Teil verzweigt werden können muss...

Ach so - zu dem Temp Bereich fällt mir gerade noch was ein:

Hier speichere ich DB Nummern zwischen um mit internen AUF DBxxx Befehlen was machen zu können.
Diese müssten auf jeden fall am Anfang von beiden FB immer neu versorgt werden!

Grund ist daß der FB mehrmals mit verscheidenen IDBs aufgerufen wird um gleichartige Maschinen getrennt von einander laufen lassen zu können - aber das ist wieder eine andere Geschichte - wobei hier mit der 315er sowieso nicht mehr als 2 Aufrufe gehen werden da sonst der OB1 an seine 16kB Grenze stößt und dieser kann wohl unmöglich gesplittet weden :ROFLMAO:
 
Zu dem Temp - Bereich:
Den kannst du ja in den Stat bereich verschieben und dann hats du da keine Probleme mehr und den Stat bereich brauchst du nicht auslagern in einen global DB. Du kannst ja dann deinen zusatz FB mit UC / CC aufrufen und dann brauchst du keine Parameter übergeben! Du musst nur immer Aufpassen das der Deklarationsteil in beiden FB's gleich ist!
 
D.h. es wird wenn ich den zweiten FB mit gleicher Schnittstelle direkt nach dem ersten mit UC/CC aufrufe die Schnittstelle exakt gleich belegt ?

Dann könnte dieser Ansatz wohl der erste Testkandidat werden!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
So habe dir das mal Ausprogrammiert:

Code:
FUNCTION_BLOCK FB 11
TITLE =
VERSION : 0.1

VAR_INPUT
  Ein : BOOL ; 
  Ein_Word : WORD ; 
END_VAR
VAR_OUTPUT
  Aus : BOOL ; 
  Aus_Word : WORD ; 
END_VAR
VAR
  STAT_WORD : WORD ; 
  HM_FP_EIN : BOOL ; 
  FP_EIN : BOOL ; 
  STAT_AUS : BOOL ; 
END_VAR
BEGIN
NETWORK
TITLE =
      U     #Ein; 
      FP    #HM_FP_EIN; 
      =     #FP_EIN; 
NETWORK
TITLE =
      U     #FP_EIN; 
      X     #STAT_AUS; 
      =     #STAT_AUS; 
NETWORK
TITLE =
      U     #STAT_AUS; 
      SPBN  next; 
      L     #Ein_Word; 
      T     #STAT_WORD; 
next: NOP   0; 
END_FUNCTION_BLOCK
FUNCTION_BLOCK FB 12
TITLE =
VERSION : 0.1

VAR_INPUT
  Ein : BOOL ; 
  Ein_Word : WORD ; 
END_VAR
VAR_OUTPUT
  Aus : BOOL ; 
  Aus_Word : WORD ; 
END_VAR
VAR
  STAT_WORD : WORD ; 
  HM_FP_EIN : BOOL ; 
  FP_EIN : BOOL ; 
  STAT_AUS : BOOL ; 
END_VAR
BEGIN
NETWORK
TITLE =
      U     #STAT_AUS; 
      =     #Aus; 

NETWORK
TITLE =
      U     #Aus; 
      SPBN  next; 
      L     #STAT_WORD; 
      T     #Aus_Word; 
next: NOP   0; 
END_FUNCTION_BLOCK
FUNCTION_BLOCK FB 10
TITLE =
//Von Aussen kann der Zusammengesetzte Baustein wie ein gnzer Betrachtet werden
VERSION : 0.1

VAR_INPUT
  Ein : BOOL ; 
  Ein_Word : WORD ; 
END_VAR
VAR_OUTPUT
  Aus : BOOL ; 
  Aus_Word : WORD ; 
END_VAR
VAR
  FB_Test : FB 11; 
END_VAR
VAR_TEMP
  Rette_AR2 : DINT ; 
END_VAR
BEGIN
NETWORK
TITLE =
      CALL #FB_Test (//Die Ausgänge von diesem Baustein nicht verwenden
           Ein                      := #Ein,
           Ein_Word                 := #Ein_Word);
//Sichere Adressregister 2
      TAR2  ; 
      T     #Rette_AR2; 
//Erzeuge Bausteinaufruf
      L     P##FB_Test; //Lade Pointer von Variable
      L     2#111111111111111111111111; 
      UD    ; //Maskiere Byte 0 von Pointer aus
      L     2#10000100; 
      SLD   24; 
      XOD   ; //Maskiere Pointer auf DB
      LAR2  ; //Pointer muss an das AR2 übergeben werden wegen Multiinstanz
      UC    FB    12; //Bausteinaufruf
//Schreibe AR2 zurück
      L     #Rette_AR2; 
      LAR2  ; 
// Hier können jetzt die Ausgänge von dem Baustein Abgefragt werden
      U     #FB_Test.Aus; 
      =     #Aus; 
      L     #FB_Test.Aus_Word; 
      T     #Aus_Word; 
 
 

END_FUNCTION_BLOCK
DATA_BLOCK DB 10
TITLE =
VERSION : 0.0
 FB 10
BEGIN
   Ein := FALSE; 
   Ein_Word := W#16#0; 
   Aus := FALSE; 
   Aus_Word := W#16#0; 
   FB_Test.Ein := FALSE; 
   FB_Test.Ein_Word := W#16#0; 
   FB_Test.Aus := FALSE; 
   FB_Test.Aus_Word := W#16#0; 
   FB_Test.STAT_WORD := W#16#0; 
   FB_Test.HM_FP_EIN := FALSE; 
   FB_Test.FP_EIN := FALSE; 
   FB_Test.STAT_AUS := FALSE; 
END_DATA_BLOCK
ORGANIZATION_BLOCK OB 1
TITLE = "Main Program Sweep (Cycle)"
VERSION : 0.1

VAR_TEMP
  OB1_EV_CLASS : BYTE ; //Bits 0-3 = 1 (Coming event), Bits 4-7 = 1 (Event class 1)
  OB1_SCAN_1 : BYTE ; //1 (Cold restart scan 1 of OB 1), 3 (Scan 2-n of OB 1)
  OB1_PRIORITY : BYTE ; //Priority of OB Execution
  OB1_OB_NUMBR : BYTE ; //1 (Organization block 1, OB1)
  OB1_RESERVED_1 : BYTE ; //Reserved for system
  OB1_RESERVED_2 : BYTE ; //Reserved for system
  OB1_PREV_CYCLE : INT ; //Cycle time of previous OB1 scan (milliseconds)
  OB1_MIN_CYCLE : INT ; //Minimum cycle time of OB1 (milliseconds)
  OB1_MAX_CYCLE : INT ; //Maximum cycle time of OB1 (milliseconds)
  OB1_DATE_TIME : DATE_AND_TIME ; //Date and time OB1 started
END_VAR
BEGIN
NETWORK
TITLE =
      CALL FB    10 , DB    10 (
           Ein                      := M      1.0,
           Ein_Word                 := MW    12,
           Aus                      := M      1.1,
           Aus_Word                 := MW    14);

END_ORGANIZATION_BLOCK

Ich finde da ist nicht recht viel kniffeliges drann.
Den FB 10 kannst du von Aussen dann behandeln wie einen normalen Baustein!
Das einzige auf das du achten musst ist das du die Ausgänge der des Aufgeteilten FB's erst nach dem zweiten FB aufruf hinausschreibst da du sonst immer eine Aktualisierung der Ausgänge nach dem ersten FB hast also mitten im Ursprünglichen Programm!

Zur Bearbeitung des ursprünglichen FB's würde ich das so machen das ich als Quelle oder sonstiges den ganzen FB abgelegt habe da drinnen die änderungen mache danach den FB 2 mal kopiere (in die Aufgerufenen Bausteinnamen) und dann brauchst du nur mehr im ersten FB die untere hälfte und im zweiten FB die obere hälfte kopieren. Und natürlich die zusätzlichen Ausgänge im Übergeordneten FB nachtragen!

godi
 
Das Problem mit den Ausgängen habe ich schon mal umgangen in dem ich einfach keine verwende - nur IN_OUT, da die meisten eh in gemeinsam benutzten (global-) DB Bereichen liegen.

Das mit den Temp in STAT verschieben wird wohl - zumindest in bezug auf die DB Nummern nicht gehen weil sonst die Meldung kommt daß hier keine statischen Variablen verwendet werden durfen, also die Anweisung:

Code:
// DB Nummern für Zugriffe zuordnen und temporär zwischenspeichern:
      L     #DB_Nr_Laufzeitinfo        // IN
      T     #DB_Nr_Laufzeitinfo_Int  // TEMP
      L     #DB_Nr_Reserve_1
      T     #DB_Nr_Reserve_1_Int
      L     #DB_Nr_Reserve_2
      T     #DB_Nr_Reserve_2_Int
      L     #DB_Nr_Reserve_3
      T     #DB_Nr_Reserve_3_Int
 
...
 
      AUF   DB [#DB_Nr_Laufzeitinfo_Int] // kann NUR im Temp liegen!
      L     DBD    0
      L     L#1
      +D    
      T     DBD    0
... nicht funktioniert

Aber das ließe sich ja elegant umschiffen wenn man immer im ersten Netzwerk den oberen Code (vor ... ) hat.

Ich bin gerade schon am testen, schaue mir das Beispiel aber auch noch an...
 
Man kann ja aber eine Variable DB_Nummer im TEMP-Bereich einrichten und jedesmal neu zuweisen, vor dem Gebrauch. Das ist vor allem sinnig, wenn die DB-Aufschläge nur ein- oder zweimal vorkommen. Wozu sollte man das ganze Programm die DB-Nummern einzeln herumschleppen?

Ich selbst gehe auch lieber den Weg:

L DB100.DBD10
T WEISSDERGEIER

Das hat meist den Vorteil, daß der Ladebefehl mit Symbolik ist (sofern vorhanden)

L DB_Kaugummi.Durchkauzaehler
T WEISSDERGEIER

Oder so:

LAR1 P##DB_Kaugummi.Durchkauzaehler
L w[AR1,P#4.0]
T DB_Nummer //temp-Variable

AUF DB[DB_Nummer]

L D[AR1,P#0.0]
T WEISSDERGEIER

dann kann man mit dem Offset (P#0.0) spielen und solcherlei Dinge.
 
Zurück
Oben