# Impulsschmierung in SCL



## dread (8 Oktober 2015)

Hallo,
ich mache gerade meine ersten Gehversuche in der SCL Programmierung.

Ich möchte gerne einen Baustein programmieren, der einen Motor zur Impulsschmierung an bzw. ausschaltet.
Dies soll entweder nach einer definierten Zeit oder nach betätigen eines Schalters der Fall sein. Hierbei wird die Schmierung nur für einen definierten Impuls gestartet.

Unten habe ich meinen FB gepostet.
Leider habe ich gerade nicht die Möglichkeit dies zu testen, und würde gerne wissen, ob es prinzipiell so geht und an welchen Stellen Verbesserungen zu machen sind, bzw gibt es Überflüssigkeiten?


Eingänge:
Imp_Hand:BOOLBei Betätigen des Schalters soll die Schmierung starten​Level_OK:BOOLFüllstand Schmiermittel​Druck_OK:BOOLnoch genügend Schmiermittel vorhanden, keine Schmierung notwendig​MSS_OK:BOOLMotorschutzschalter Schmierung OK​Reset:BOOLZeit bis zum Starten der Schmierung zurücksetzen​Periode:INTZeit zwischen zwei Schierimpulsen​Max_Imp_s:INTmaximale Impulsdauer Schmierung​stoer:BOOLOb ein Fehler anderweitig vorliegt​
Ausgänge:
Motor:BoolAusgang Motor an, Schmierung an​Restzeit: INTZeit die bleibt bis zum nächsten Schmierimpuls​ERRMsg:ByteFehlerausgabe​Err AT *ErrMsg* Array[0..7] of Bool


```
(*
    Funktion zur automatischen Impulsschmierung.
    Die Impulsschmierung wird entweder per Hand Impuls oder nach einer definierten Zeit begonnen.
    Das Schmierintervall ist vorgegeben und wird unabhängig von den Startbedingungen eingehalten
    und wird nur in Abhängigkeit vom Erreichen des Solldruckes oder eines Fehlers verkürzt.
    
    Byte ErrMsg:
                [0] Zeit zwischen Schmierimpulsen NULL oder Negativ eingegeben
                [1] Schmierdauer NULL oder Negativ eingegeben
                [2] Motorschutzschalter hat ausgelöst
                [3] Füllstand Schmiermittel zu niedrig
                [4] 6 Schmierimpulse konnten nicht durchgeführt werden, weil Druck iO war
                [5]
                [6]
                [7]
*)
//ERRMsG Byte auf Null setzen, um erneute Fehlerabfrage zu starten
#ErrMsg := 0;
WHILE NOT #stoer AND NOT #Reset AND #ErrMsg = 0 DO
    (*
        FEHLERERKENNUNG/-ABFRAGE
        Abfrage, ob Bedingungen zur Impulsschmierung erfüllt sind, und die Fehler aufs Err-Byte schreiben
    *)
    IF #Periode <= 0 THEN
        #Err[0] := TRUE;
    END_IF;
    IF #Max_Imp_s <= 0 THEN
        #Err[1] := TRUE;
    END_IF;
    IF NOT #MSS_OK THEN
        #Err[2] := TRUE;
    END_IF;
    IF NOT #Level_OK THEN
        #Err[3] := TRUE;
    END_IF;
    
    (*
    Wenn keine Fehler vorliegen, dann Impulsschmierung
    *)
    IF #ErrMsg = 0 THEN
        // Zeiten initialisiern
        // 
        #Restzeit := #Periode;
        #Schmierperiode := #Max_Imp_s;
        
        
        //Warteschleife zwischen den Schmierimpulsen
        //Kann jederzeit durch einen Handimpuls unterbrochen werden
    warteschleife_start:
        FOR #Restzeit := #Periode TO 0 BY 1 DO
            //unterbrechen, fall Hand_IMP kommt
            IF #Imp_Hand THEN
                EXIT;
            ELSE
                //ansonsten 1 Sekunde verzögern
                WAIT(1000000);
            END_IF;
        END_FOR;
        //Wenn Hand Impuls oder Wartezeit vorüber ist, und der Schmierdruck abgefallen ist,
        //kann mit der Schmierung begonnen werden
        IF (#Restzeit = 0 OR #Imp_Hand) AND NOT #Druck_OK THEN
            #Schmierung := TRUE;
            #Nulldurchgang := 0;
            //Wenn Hand Impuls und der Schmierdruck NICHT abgefallen ist,
            //Dann wieder in die warteschleife
        ELSIF #Imp_Hand AND #Druck_OK THEN
            #Schmierung := FALSE;
            GOTO warteschleife_start;
            //Wenn Wartezeit vorüber ist und der Schmierdruck NICHT abgefallen ist,
            //Dann Neustart warteschleife und Nulldurchgangszähler erhöhen
            //Wenn der Nulldurchgangszähler 6 erreicht hat, Abbruch, da vielleicht Drucksensor
            //nicht in Ordnung, oder ein anderes Problem vorliegt
        ELSIF #Restzeit = 0 AND #Druck_OK THEN
            #Restzeit := #Periode;
            #Nulldurchgang := #Nulldurchgang + 1;
            IF #Nulldurchgang >= 6 THEN
                #Err[4] := TRUE;
            ELSE
                GOTO warteschleife_start;
            END_IF;
        END_IF;
        ;
    END_IF;
    
    //Schmierimpuls starten wenn der Schmierdruck abgefallen ist und Schmierung gesetzt ist
    //Der Impuls wird abgebrochen, wenn der Druck erreicht wird, oder Impuls vorrüber ist
    FOR #Schmierperiode := #Max_Imp_s TO 0 BY 1 DO
        IF #Schmierung AND NOT #Druck_OK THEN
            #Motor := TRUE;
            WAIT(1000000);
        ELSE
            #Motor := FALSE;
            #Schmierung := FALSE;
            #Schmierperiode := 0;
        END_IF;
    END_FOR;
    #Schmierung := FALSE;
END_WHILE;


(*
    Bearbeitung nur, wenn Schleife durch ein RESET abgebrochen wird.
    Neustart der Schleife mit zurückgesetzten Werten
*)
IF #Reset THEN
    // Zeiten initialisiern
    // 
    #Restzeit := #Periode;
    #Schmierperiode := #Max_Imp_s;
    #Motor := FALSE;
    #Schmierung := FALSE;
END_IF;
```

Edit: Programm nochmal als PDF angehängt


----------



## JesperMP (8 Oktober 2015)

Ich habe nicht dein kompletten Code durchgeschaut. Nur ich bemerke dies:

Kann der WHILE NOT ein endlos-Schleife erzeugen ?
Das muss absolut vermeidet werden.
Ich verwende nie WHILE in mein SCL Code. Es ist zu gefährlich.

Anstatt einen "warteschleife", emfehle ich dir das ganze als FB und alle Timer Funktionen mit eingebettete SFB4 TON zu erzeugen.

edit: Und GOTO meide ich auch, ausser z.B. wenn das Program ein grossen Program Fehler detektiert hat (durck OK bit), dann springe ich eventuell mit GOTO zu ein Störbehandlungscode.
Wenn GOTO ein Teil von den 'normalen' Program ist, wird das ganze zu Spaghetti.


----------



## norustnotrust (8 Oktober 2015)

So programmiert man keine SPS. Alles was du hast wird in einem Zyklus abgearbeitet. Das heißt du würdest einen ewig langen Zyklus generieren.

Du brauchst einen Timer


----------



## dread (8 Oktober 2015)

Hallo JesperMP, danke für die schnelle Antwort!

An sich ist die WHILE NOT Schleife eine endlos-Schleife, da die Schmierung zyklisch durchgeführt werden soll, solange kein Fehler auftritt.

Sobald woanders im Programm (Eingang stoer) oder in diesem FB (ErrMsg) ein Fehler auftritt soll die WHILE Schleife abgebrochen werden.


Mein erster Gedanke war auch, anstelle von wait() eine Einschaltverzögerung zu nehmen, war mir aber unsicher, wie ich die Bedingung setzen soll, dass die Einschaltverzögerung bei dem HandImpuls übergangen werden soll.

Die INstanz für den Timer müsste ich dann auch als Eingangsvariable deklarieren, richtig?
Ich verwende meistens S7-300 Steuerungen und da kann ich leider keine IEC-Zeiten verwenden



@norustnotrust

Also Auslagerung in Unterfunktionen?


----------



## JesperMP (8 Oktober 2015)

Wie norustnotrust gesagt hat, so kann man kein SPS programmieren.
Wenn der Aktualisierungszeit von OB1 mehr als 500 ms dauert, geht der CPU auf SF.

Die IEC Timer TON und TOF sind Systembausteine SFB4 und SFB5, und somit ein bestand von das Befehlsumfang von sämtliche S7 CPUs.
Wie gesagt, FB anstatt FC. Die Timer in der Deklaration vond er FB einbetter, nicht über Eingang.


----------



## norustnotrust (8 Oktober 2015)

Nein, das hat mit Unterfunktionen nichts zu tun. Die While-Schleife ist ein Konstrukt um Code immer wieder zu bearbeiten. Eine SPS tut das aber sowieso, sie läuft jeden Code immer wieder im Zyklus durch. Wenn du also in HS:


```
while (condition)
{
do something;
wait();
}
```
machst

machst du in der SPS einfach:


```
if (condition)
{
 do something;
}
```

ist das verständlich?


----------



## dread (8 Oktober 2015)

ok, also schon allein wegen der Zeile 

```
WAIT(1000000)
```
würde die CPU in Fehlerzustand gehen?

Verständnisfrage:
Wenn ich einen Timer in Zeile 1 starte, läuft der Timer und das Programm wird währenddessen in Zeile 2 weiter ausgeführt?


Dann werde ich mal das Programm umschreiben.


----------



## dread (8 Oktober 2015)

Habe das Programm anhand der Hinweise umgeändert und im Anhang angefügt.

Gibt es noch Fehler, bzw Verbesserungsvorschläge?

Anhang anzeigen Baustein_1.pdf


----------

