# Verbesserungen SCL-Schrittkette



## Bobbybau91 (12 April 2016)

Hallo zusammen,

ich setze meine Schrittketten für die S7-1200 immer folgendermaßen um. Allerdings finde ich hier immer eine Erweitererung problematisch. Ich kann zwar eine begrenzte Anzahl an Schritten noch zwischen meinen Schritten einführen, aber wenn ich größere Änderungen machen muss ist das immer Problematisch. Hat jemand eine Idee wie man das besser bei der S7-1200 lösen kann? SCL oder FUP ist mir hierbei egal.


Grüße
Bob


```
//Schrittbits löschen
FOR #i := 0 TO 220 BY 1 DO
    "DB_Programm".Programmsteuerung.Schrittnummer_Bool[#i] := 0;
END_FOR;

//Schrittkette
CASE "DB_Programm".Programmsteuerung.Schrittnummer OF
    0: //Initialschritt
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[0] := 1;
        "DB_Programm".Programmsteuerung.Schrittnummer := 5;
        
    5: //Flasche zu Verschließposition befördern
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[5] := 1;
        IF "DB_Antriebe".Flaschenband."Lenze->SPS"."Zielposition erreicht" 
        THEN
            "DB_Programm".Programmsteuerung.Schrittnummer := 10;
        END_IF;
        
    10: //Flasche zentrieren und Sensorbacke zu Flasche
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[10] := 1;
        IF "DB_Akt".Zentrierbacke.AS AND "DB_Akt".Ausrichtriemen.AS AND "DB_Akt".Sensorbacke.AS
            
        THEN
            "DB_Programm".Programmsteuerung.Schrittnummer := 15;
        END_IF;
```


----------



## MSB (12 April 2016)

Die einzige Lösung die es für dein Problem gäbe, wäre Graph, welches aber gegenwärtig leider nicht für die 1200er existiert.
Ansonsten hast du deine Grundproblematik bei allen konventionellen Arten eine SK zu programmieren, von Merker SR bis Case, gleichermaßen.


----------



## hucki (12 April 2016)

Zunächst würde ich statt echten Zahlen Konstanten für die Schrittnummern verwenden. Dann spielt die echte Zahl schon mal nur noch 'ne untergeordnete Rolle und ist nur an einer Stelle zu definieren:

```
CONST
    [B]SK_Ini[/B]:= 0;
    [B]SK_Transport[/B]:= 5;
    [B]SK_Zentrieren[/B]:= 10;
    [B]SK_Next[/B]:= 15;
    ...
END_CONST


//Schrittbits löschen
FOR #i := 0 TO 220 BY 1 DO
    "DB_Programm".Programmsteuerung.Schrittnummer_Bool[#i] := 0;
END_FOR;

//Schrittkette
CASE "DB_Programm".Programmsteuerung.Schrittnummer OF
    [B]SK_Ini[/B]: //Initialschritt
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[[B]SK_Ini[/B]] := 1;
        "DB_Programm".Programmsteuerung.Schrittnummer := [B]SK_Transport[/B];
        
    [B]SK_Transport[/B]: //Flasche zu Verschließposition befördern
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[[B]SK_Transport[/B]] := 1;
        IF "DB_Antriebe".Flaschenband."Lenze->SPS"."Zielposition erreicht" 
        THEN
            "DB_Programm".Programmsteuerung.Schrittnummer := [B]SK_Zentrieren[/B];
        END_IF;
        
    [B]SK_Zentrieren[/B]: //Flasche zentrieren und Sensorbacke zu Flasche
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[[B]SK_Zentrieren[/B]] := 1;
        IF "DB_Akt".Zentrierbacke.AS AND "DB_Akt".Ausrichtriemen.AS AND "DB_Akt".Sensorbacke.AS
            
        THEN
            "DB_Programm".Programmsteuerung.Schrittnummer := [B]SK_Next[/B];
        END_IF;
```


Die Schrittweiterschaltung könnte man dann auch noch alternativ berechnen:

```
...
    SK_Zentrieren: //Flasche zentrieren und Sensorbacke zu Flasche
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[SK_Zentrieren] := 1;
        IF "DB_Akt".Zentrierbacke.AS AND "DB_Akt".Ausrichtriemen.AS AND "DB_Akt".Sensorbacke.AS
            
        THEN
            "DB_Programm".Programmsteuerung.Schrittnummer := [B]"DB_Programm".Programmsteuerung.Schrittnummer + 5[/B];
        END_IF;
```
Bei Berechnung muss man seine CONST-Liste bei neuen Einfügungen einmal neu durch nummerieren.
Bei Festangaben der Schrittnummer muss man sich dann entsprechend die Schritte raussuchen, wo was zwischen gekommen ist.
Das erste ist also etwas mehr Tipparbeit ohne Suchen, das zweite weniger Tippen mit mehr Suchen (Verweisfunktion). Muss jeder für sich entscheiden.



PS: Ach ja, man muss sich noch entscheiden, ob man die Konstanten lokal oder global deklariert. Kommt halt drauf an, ob man das in mehr als einem Baustein verwenden möchte.


----------



## RobiHerb (12 April 2016)

*Dann aber konsequent*

Dann sollte man aber auch konsequent sein. Man weiss doch was der nächste Schritt ist und wie man ihn nennen muss, hier habe ich ihm mal den Namen FlascheIstAngeschlossen gegeben:


```
...
    SK_Zentrieren: //Flasche zentrieren und Sensorbacke zu Flasche
        "DB_Programm".Programmsteuerung.Schrittnummer_Bool[SK_Zentrieren] := 1;
        IF "DB_Akt".Zentrierbacke.AS AND "DB_Akt".Ausrichtriemen.AS AND "DB_Akt".Sensorbacke.AS
            
        THEN
            "DB_Programm".Programmsteuerung.Schrittnummer := [B]SK_FlascheIstAngeschlossen[/B];
        END_IF;
```



> PS: Ach ja, man muss sich noch entscheiden, ob man die Konstanten lokal oder global deklariert. Kommt halt drauf an, ob man das in mehr als einem Baustein verwenden möchte.



Natürlich möglichst FB lokal oder als Enumeration, wenn von aussen der Schritt abgefragt werden soll!

Wenn mit Codesys 3.x dann den Schritt als protected set und public get implementieren.


----------



## hucki (12 April 2016)

RobiHerb schrieb:


> Dann sollte man aber auch konsequent sein. Man weiss doch was der nächste Schritt ist und wie man ihn nennen muss


Darum geht's ja.
Wenn Schritte eingefügt werden, heißt er eben nicht mehr so wie vorher.

Bei der konkreten Benennung muss demzufolge der (vorige) Schritt rausgesucht werden und der Name der Konstante geändert werden.
Beim Addieren legt man die Schrittreihenfolge ausschließlich in der Konstantendeklaration fest.
Beides hat Vor- und Nachteile. Wie immer halt.

Definitiv ist es bei Nutzung von Konstanten und Addition einfacher, neue Schritte am bestehenden Inhalt nur hinten dran zu hängen. Denn die Übersicht, welcher Schritt auf welchen folgt, steckt jetzt hauptsächlich in der Konstantendeklaration und nicht mehr so sehr im CASE selbst. Und die Deklaration ist bis auf die Schrittnummer von sämtlichen "Ballast" befreit.
Ob es das besser macht, muss wieder jeder für sich entscheiden.






RobiHerb schrieb:


> Wenn mit Codesys 3.x dann den Schritt als protected set und public get implementieren.





Bobbybau91 schrieb:


> meine Schrittketten für die *S7-1200*


----------



## PN/DP (13 April 2016)

hucki schrieb:


> Wenn Schritte eingefügt werden, heißt er eben nicht mehr so wie vorher.


?? Wieso sollte sich da der Name ändern, da bekommen höchstens die vorhandenen Namen andere Werte?

Wenn man konsequent nur den Name des Schrittes benutzt, dann ist der tatsächliche numerische Wert unwichtig. Am besten unbekannt - dann kommt man auch nicht in Versuchung, auf die Schrittnummer irgendwelche Berechnungen anzuwenden:

```
//sowas vermeiden!
#Schrittnummer := #Schrittnummer + 5;
#Ventil_Auf := (#Schrittnummer >= 5) AND (#Schrittnummer <= 7);

//richtig:
#Schrittnummer := SK_Schritt6;
#Ventil_Auf := (#Schrittnummer = SK_Schritt5) OR (#Schrittnummer = SK_Schritt6) OR (#Schrittnummer = SK_Schritt7);
```

Harald


----------



## hucki (13 April 2016)

PN/DP schrieb:


> ?? Wieso sollte sich da der Name ändern, da bekommen höchstens die vorhandenen Namen andere Werte?


Weil der vorherige *nächste* Schritt nach dem Einfügen von Zwischenschritten nicht mehr der nächste Schritt ist, sondern der übernächste oder z.B. erst der 10. danach.
Und mit dem *Namen des nächsten Schritts* hat man halt ein konkretes Sprungziel, dass dann bei Neueinfügungen angepasst werden muss. Mit einem Offset zum nächsten Schritt hat man dies nicht. Da ist der nächste Schritt immer z.B. 5 Nummern weiter. Dafür müssen bei Neueinfügungen die Schrittnummern in der Deklarationsliste angepasst werden.
Wie gesagt, hat beides Vor- und Nachteile.

Und wie MSB schon sagte, nur Graph würde das komplett automatisch erledigen.


----------



## Bobbybau91 (13 April 2016)

Den Ansatz finde ich auf jeden Fall besser als meinen bisherigen. Werde das dann mal nachher in die Tat umsetzen.

Danke schonmal für die Ideen.


----------



## thomas59 (18 April 2016)

Vorschlag:
TYPE SK_TYPE:
 (*SK_Ini, **SK_Transport*, *SK_Zentrieren*, *SK_Next* , ... )
END_TYPE


VAR 
  SK_VALUE: SK_TYPE;
END_VAR

im Programm:

case SK_VALUE of
*SK_Ini:
 machwas_1();
 SK_VALUE := **SK_Transport;

SK_Transport:
 machwas_2();
 SK_VALUE := SK_Zentrieren;

SK_Zentrieren:
 machwas_3();
 SK_VALUE := SK_Next;

SK_Next:
 machwas_4();
 SK_VALUE := SK_Ini;

*END_CASE


Nachträgliche Änderungen können in der TYPE Deklaration jederzeit einfach nachgetragen/eingefügt/gelöscht werden und es reichen die symbolischen Werte dafür aus.
So ähnlich mach ich das in "C".

Gruß
Thomas


----------

