# STRUCTURED TEXT: Wartezeit in Whilescheife einbauen



## cypher (21 Januar 2015)

Hallo, ich habe eine kleines Problem mit meinem Programm in Automation Studio (Sprache Structured Text)

Folgendes: 
ein Wert A soll mit einem Wert B verglichen werden. Ist A größer als B öffnet sich ein Ausgang, der den Wert von A senkt.
Das Problem dabei ist das diese Änderung einige Zeit dauert und ich gerne in meine WHILE-Schleife eine Wartezeit einbauen möchte, sodass A ausreichend Zeit hat sich zu verändern bevor die Abfrage von neuem beginnt. 

Hier mein bisheriges Programm (eventuell unnötiger Code enthalten):

WHILE A > B DO

out := FALSE;                  (Ausgang soll Anfangs geschlossen sein)
TON_1(IN := NOT out, PT := T#1s);
out := TON_1.Q;                     (Ausgang wird geöffnet)
TON_2(IN := TON_1.Q, PT := T#5s);
out := NOT TON_2.Q;              (Ausgang nach 5 Sekunden wieder geschlossen)
<<<<<<Wartezeit>>>>>>

END_WHILE;


Wie kann ich am Besten eine Wartezeit von etwa 30 Sekunden am Ende der Schleife einbauen, bevor sie wieder die Startbedingung A>B abfragt?

Ist das Programm so überhaupt funktionsfähig? Wenn nein, gibt es Verbesserungsvorschläge?


----------



## PN/DP (21 Januar 2015)

Wartezeiten macht man in SPS nicht über Schleifen sondern man lässt einen Timer laufen und verlässt den Programmabschnitt. Wenn der Timer abgelaufen ist setzt man die Verarbeitung fort.

Bei SPS ist es "tödlich" wenn das Programm in einer Schleife festhängt, die SPS soll ja auch noch tausend andere Sachen machen, wie z.B. schauen ob eine Stop-Taste gedrückt ist oder ein Druck zu hoch ist.. deshalb wird die Programmbearbeitung in der SPS auch brutal gestoppt, wenn ein Programmdurchlauf zu lange dauert. (z.B. max 150ms)

Harald


----------



## shrimps (21 Januar 2015)

Upps, PN/DP war schneller...
Hallo Cypher,
augenscheinlich hast du die Abarbeitungsmethode einer SPS noch nicht verinnerlicht 

Die SPS arbeitet deinen Code zykisch wiederholend ab !

Du musst also keine "tödliche Bremse" einbauen !

Suche mal nach Pulsbausteinen oder Blinker.

Die schaltest du ein (Aktivzeit und Pausenzeit).
Nun brauchst du nur noch während der Aktivzeit deine Abfrage machen und den Ausgang einschalten.
Anschl. wieder ausschalten.

Ich hoffe das ist ein wenig verständlich.

Die anderen werden es sicherlich noch optimieren...

GGf. kann ich dir auch ein wenig getesteten Code zusammenstricken...

LG
Shrimps


----------



## vollmi (21 Januar 2015)

Erstens. Es ist nicht gut Timer in einer Bedingung einzuschachteln. Und du hast deren gleich zwei im While.

Zweitens. Statt einer Wartezeit im While zu machen könntest du darin einen Merker setzen.

Der Merker startet einen TON. Wenn der TON Abgelaufen ist wird der Merker zurückgesetzt. Die While bedingung soll dann nur erfüllt sein wenn zusätzlich nicht der Merker gesetzt ist. Das ist dann die Wartezeit.

Wartezeiten in CPUs gehen zwar sind aber äusserst unschön. Und werden nie gebraucht.

mfG René


----------



## shrimps (21 Januar 2015)

Hallo cypher,
nachfolgend mal ein kleines Codebeispiel, was dir das erklären soll / könnte.
Speichere dir diesen ganzen Codeblock als test.exp ab und lade ihn als Projekt-Import.
Viel Spaß beim verstehen und weiteren Fragen.
LG Shrimps

```
FUNCTION_BLOCK _fbBlinker
VAR_INPUT
    ENQ : BOOL := TRUE;
    PTH : TIME;
    PTL : TIME;
END_VAR
VAR_OUTPUT
    Q : BOOL;
END_VAR
VAR
    tx: TIME;
    tn: TIME;
    init: BOOL;
END_VAR

tx := TIME();
IF enq THEN
    tx := TIME();
    IF NOT init THEN init := TRUE; tn := tx; END_IF;
    IF tx - tn >= SEL(Q, PTL, PTH) THEN
        tn := tn + SEL(Q, PTL, PTH);
        Q := NOT Q;
    END_IF;
ELSE
    Q := FALSE;
    init := FALSE;
END_IF;

END_FUNCTION_BLOCK


PROGRAM MAIN
(* Der Baustein Blinker stammt aus OSCAT.DE *)
VAR
    fbBlinker            : _fbBlinker;     (* Den baustein instanzieren *)
    bAusgang        : BOOL;        (* Unser Ausgang *)
    rWertA, rWertB    : REAL;        (* Die beiden Vergleichswerte *)
END_VAR
(* Den Funktionsblock mit den Parametern aufrufen *)
(* Das schöne an dem Blinker ist, das er den Ausgang für die dauer der zeit auf TRUE hält und nicht wie TON nur einen Impuls gibt *)
(* Er läuft ewig *)
fbBlinker(ENQ:= TRUE ,PTH:= t#5s,PTL:= t#30s );

IF fbBlinker.Q THEN    (* Ist unser Arbeitstakt PTH aktiv ? *)

    IF rWertA > rWertB THEN    (* Ist unser WertA > WertB *)
        bAusgang := TRUE;    (* dann Ausgang enschalten *)
    END_IF

ELSE                        (* Arbeitstakt ist inaktiv (FALSE), Ausgang aus ! *)
    bAusgang := FALSE;
END_IF

(* Nun in der Onlineansicht je nach System den WertA auf 1 setzen und beobachten *)
(* LG Shrimps *)


END_PROGRAM
```


----------



## shrimps (21 Januar 2015)

Hallo Cypher,
damit du den Unterschied zu den fertigen Bausteinen (FB´s) erkennen kannst, hier mal ein Beispile mit einer
klassischen Schrittkette.
Einziges Manko bei den bisherigen Lösungen:
Die ersten 30s muss gewartet werden bis die regelung aktiv wird.
Um sofort loszulegen muss ein weiteres Flag für den Init einmalig gesetzt werden und die Schrittkette direkt auf Trab  gebracht werden...

Viel Spaß beim Lernen.
LG
Shrimps
PS: Bin selber am lernen...


```
PROGRAM MAIN
(* Viel Spaß LG Shrimps *)
VAR
    Zeit1, Zeit2    : TIME;    (* Unsere zu überwachenden Zeiten *)
    WertA    : REAL := 1.0;    (* Unsert WertA *)
    WertB    : REAL := 0.0;    (* WertB *)
    Ausgang        : BOOL;    (* Der Schaltausgang *)
    Schritt        : USINT;    (* Die Ablaufkette *)

Zeit1 := TIME();    (* Immer die aktuelle Zeit merken *)

(* Nun die Ablaufkette: 0 = Start, 10=Warten 30s, 20=Warten 5s *)
CASE schritt OF

0:    (* Start *)
    Zeit2 := Zeit1;            (* Zeit merken *)
    ausgang := FALSE;    (* Ausgang pauschal aus *)
    Schritt := 10;            (* Auf zur Warteschleife *)

10:    (* Warteschleife 1 *)
    IF Zeit1 - Zeit2 > t#30s THEN        (* 30s abgelaufen ? *)
        IF WertA > WertB THEN    (* Unsert WertA > WertB ? *)
            Ausgang := TRUE;        (* Ausgang aktivieren *)
            Zeit2 := Zeit1;            (* Wieder Zeit merken für 2.te Warteschleife *)
            Schritt := 20;            (* Auf zur 2.ten Warteschleife *)
        ELSE                    (* Unser WertA war nicht größer *)
            Schritt := 0;            (* Dann nochmal von vorn *)
        END_IF
    END_IF

20:    (* Warteschleife 2 *)
    IF Zeit1 - Zeit2 > t#5s THEN        (* 5s abgelaufen ? *)
        Ausgang := FALSE;        (* Ausgang deaktiviren *)
        Schritt := 0;                (* Auf ein neues *)
    END_IF

END_CASE


END_VAR
```


----------



## StructuredTrash (21 Januar 2015)

cypher schrieb:


> Ist das Programm so überhaupt funktionsfähig?


Nein. Ein SPS-Programm ist kein Ablaufprogramm. Du gehst davon aus, dass beim Aufruf eines Timers das Programm an dieser Stelle solange wartet, bis der Timer abgelaufen ist. Das ist aber nicht so. Schau mal hier:
https://www.sps-forum.de/index.php?Threads
Vielleicht hilft das ein bisschen weiter.


----------



## cypher (22 Januar 2015)

Vielen Dank euch allen  
Ich hatte wohl ein etwas falsches Bild wie eine SPS ein Programm abarbeitet.
Eure Beiträge haben mir wirklich weitergeholfen und waren sehr lehrreich.
Ein riesen Dankeschön an Shrimps für die sehr ausgiebige Hilfe.

LG
cypher


----------

