# Schrittkette und TON-Timer



## Spoon (14 Dezember 2009)

Habe folgendes Problem: Ich habe eine Schrittkette porgrammiert. Diese funktioniert auch eigentlich sehr gut und die einzelnen Schritte werden nacheinander abgearbeitet. Nur in einem Schritt wollte ich einen TON einfügen. Dieser wird aber einfach übersprungen und es geht mit dem Schritt 7 weiter.

CASE Step OF
 .........
 6: IF Sensor_1 AND NOT  Timer_3.Q THEN
    Timer_3.IN := TRUE;
    Step := Step +1;
    END_IF
 7: IF Timer_3.Q THEN
     Finish := FALSE;
     Step := Step +1;
     END_IF
 8: Step := 0;
END_CASE

Timer_3 (PT:= T#5s, );


----------



## witkatz (14 Dezember 2009)

Hallo spoon,

versuche es vielleicht mit 

7: IF Timer_3.Q THEN
Timer_3.IN := FALSE;
     Finish := FALSE;
     Step := Step +1;
     END_IF

Gruß,
witkatz


----------



## Spoon (14 Dezember 2009)

Habe es so geändert wie witkatz es beschrieben hat. Leider funktioniert es nicht. Der Timer wird einfach übersprungen und die Schrittkette springt wieder in Schritt 1. 
Bleibt dort aber stehen, da der Merker Finsh erst zurück gesetzt werden muss.


----------



## trinitaucher (15 Dezember 2009)

Kannste mal deinen Schritt 5 und evtl auch Schritt 4 posten?

Du schreibst Schritt 6 wird übersprungen. Dann wird das Problem bestimmt voher zu suchen sein.


----------



## Cerberus (15 Dezember 2009)

Hallo Spoon!

Also dein Ansatz ist soweit in Ordnung. Es fehlt aber noch an ein paar Kleinigkeiten.

1. Mit "Timer_3.IN := TRUE;" wird dein Timer nicht gestartet. Das liegt daran, dass der Timer-Baustein mit diesem Aufruf nicht aufgerufen wird. Besser ist "Timer_3(IN:= TRUE, PT:= T#5s);".

2. Um zu schauen, ob dein Timer abgelaufen ist, ist es richtig den Ausgang Q zu überprüfen. Das funktioniert auch mit "Timer_3.Q". Allerdings musst du vor deiner Abfrage den Timer aktualisieren, da er ansonsten nicht den aktuellen Wert übernimmt. Also einfach ein "Timer_3(IN:= TRUE);" vor der Abfrage einfügen.

3. Nachdem dein Timer abgelaufen ist, musst du ihn zurücksetzen, sonst kannst du ihn in deinem weiteren Programmablauf nicht mehr verwenden. Das hat auch schon witkatz angemerkt. Also einfach nach deiner Abfrage ein "Timer_3(IN:= FALSE);" einfügen.


```
6: IF Sensor_1 AND NOT Timer_3.Q THEN
Timer_3(IN := TRUE, PT := T#5s);         (* Timer starten *)
Step := Step +1;
END_IF
7: Timer_3(IN := TRUE);                  (* Timer aktualisieren *)
IF Timer_3.Q THEN                        (* Timer abgelaufen? *)
Timer_3(IN := FALSE);                    (* Timer zurücksetzen *)
Finish := FALSE;
Step := Step +1;
END_IF
```
 
Gruß Cerberus


----------



## trinitaucher (15 Dezember 2009)

@ Cerberus:
Spoon ruft den Timer am Ende der Schrittkette jeden Zyklus auf.
... hoffe zumindest, dass ich seinen Code korrekt interpretiere.



Spoon schrieb:


> CASE Step OF
> .........
> 6: IF Sensor_1 AND NOT  Timer_3.Q THEN
> Timer_3.IN := TRUE;
> ...



Ich halte die Art des Aufrufs auch für die sauberste.


----------



## Cerberus (15 Dezember 2009)

trinitaucher schrieb:


> @ Cerberus:
> Spoon ruft den Timer am Ende der Schrittkette jeden Zyklus auf.
> ... hoffe zumindest, dass ich seinen Code korrekt interpretiere.
> 
> ...


 
Sorry hab ich überlesen. In diesem Fall haben sich meine Punkte 1 und 2 erledigt. Trotzdem sollte der Timer wieder zurückgesetzt werden.


----------



## Larry Laffer (15 Dezember 2009)

Hallo,
nach meiner Meinung wird das so mit dem Timer niemals was werden. Der Timer muß um sinnvoll funktionieren zu können, die steigende und auch die fallende Flanke am IN mitbekommen. Das klappt normalerweise in einem CASE oder auch in einer IF-THEN Anweisung nicht.
Ich würde den Timer außerhalb des CASE programmieren und zuweisen - dann von mit aus den Q etc. im CASE verwenden - das gibt dann keine Probleme ...

Gruß
LL


----------



## Cerberus (15 Dezember 2009)

Larry Laffer schrieb:


> Hallo,
> nach meiner Meinung wird das so mit dem Timer niemals was werden. Der Timer muß um sinnvoll funktionieren zu können, die steigende und auch die fallende Flanke am IN mitbekommen. Das klappt normalerweise in einem CASE oder auch in einer IF-THEN Anweisung nicht.
> Ich würde den Timer außerhalb des CASE programmieren und zuweisen - dann von mit aus den Q etc. im CASE verwenden - das gibt dann keine Probleme ...
> 
> ...


 
@ Larry

Ich verwende Timer regelmäßig in CASE-Schleifen. Wie im dem oben geposteten Code. Und es funktioniert einwandfrei.

Gruß Cerberus


----------



## witkatz (15 Dezember 2009)

Spoon schrieb:


> Habe es so geändert wie witkatz es beschrieben hat. Leider funktioniert es nicht. Der Timer wird einfach übersprungen und die Schrittkette springt wieder in Schritt 1.




```
PROGRAM MAIN
VAR
    Step: INT;
    Timer_3: TON;
    Sensor_1: BOOL;
END_VAR
CASE Step OF
0:
    (*.........*)
    Timer_3.IN := FALSE;
    step:= 6;
6:
    IF Sensor_1 AND NOT Timer_3.Q THEN
        Timer_3.IN := TRUE;
        Step := Step +1;
    END_IF
7:
    IF Timer_3.Q THEN
        Timer_3.IN := FALSE;
        Step := Step +1;
    END_IF
8:
    Step := 0;
END_CASE

Timer_3 (PT:= T#5s, );
```
Die Schrittkette überspringt den Schritt 6 nicht. Der dauert nur einen Zyklus, man sieht das in der Online-Anzeige nicht. Dafür ist sie zu träge.
Um zu sehen ob der Schritt 6 bearbeitet wird, musst du einen Breakpoint oder eine Testvariable in dem Schritt setzen, oder den Schrittzähler Tracen.

Gruß,
witkatz


----------



## MasterOhh (15 Dezember 2009)

Wenn der Timer gestartet wurde und hochzählt wurde Schritt 6 erfolgreich ausgeführt. Eigentlich sollte er nach 5s in Schritt 8 springen und im nächsten Zyklus nach 0 zurück und der ganze Tanz geht von vorne los.


----------



## Spoon (15 Dezember 2009)

Danke erstmal für die vielen Antworten.

Hab das ganz nochmal ein bischen umgeschrieben:

Case Step OF
......
 6: IF Reed_1 AND NOT Time_Go THEN
  Go_Auto := FALSE;
  Finish := TRUE;
  TIME_Go := TRUE;
  Step := Step +1;
  END_IF
 7: IF TIME_OK THEN
  Time_Go := FALSE;
  Finish := FALSE;
  Step := Step +1;
  END_IF
 8: Step := 0;
END_CASE

Timer_3 (IN:=Time_Go, PT:= T#5s, Q=>, PT=>, );
IF Timer_3.Q THEN
 TIME_OK:= TRUE;
ELSE
 TIME_OK:= FALSE;
END_IF

Der Timer beginnt bei dem Aufruf des Schritt 6 zulaufen.
Es wird aber direkt in den Schritt 8 gesprungen und dann halt wieder in den Schritt 1. Als wäre die Zeit schon abgelaufen, obwohl sie ja noch läuft. So sehe ich das Online.
Ich will aber erst 5 Sekunden warten und dann wieder in den Schritt ein Springen. Vielleicht gibt es dafür noch eine andere Lösung.


----------



## trinitaucher (15 Dezember 2009)

Sicher dass du nicht noch irgendwo außerhalb der CASE ein Step := Step + 1 drin hast oder der Timer irgendwo nochmal aufgerufen wird?
Setz zur Sicherheit mal in den Schritte die Variable Step auf absolute Werte, also im Schritt 6: Step := 7, im Schritt 7: Step := 8 usw.

Lass den Timer zur Sicherheit mal allein laufen mit manuellem Setzen der .IN.


----------



## Larry Laffer (16 Dezember 2009)

Hallo,
wo ist denn TIME_OK deklariert ? TEMP oder STAT ?
Du kannst in dem CASE-Konstrukt den Timer3.Q durchaus abfragen - wichtig ist das du den Timer selbst ausserhalb steuerst.

Gruß
LL


----------



## drfunfrock (16 Dezember 2009)

Den Timer setzt man vor die Switch-Case-Anweisung. Daher


```
eier_timer(IN:=triggervar ... )

switch....
```
Setzt man den Timer über das Programm und nicht über IO-Eingänge muss der In-Eingang einen Low-High übergang machen.Entweder so: 


```
Mann kann den Timer auch in die Switch-Case-Anweisung packen, aber dann wird es richtig unübersichtlich ergo hässlich. Ich halte diese Lösung für die sauberste, weil sie leicht wartbar ist. 

case schritt_100: 
   triggervar := FALSE;
   state := schritt_101;

case schritt_101:
   triggervar := TRUE;
   if eier_timer.out then
       state := schritt_xyz;
   end_if;
```
oder


```
case schritt_100:
   eier_timer(IN:=NOT eier_timer.out);
   if eier_timer.out then
       state := schritt_xyz;
   end_if;
```
Eine dritte Lösung ist ziemlich hässlich, wenn man die obige Struktur einsetzt:

```
case schritt_100:
   eier_timer(IN:=False);
   eier_timer(IN:=True);
   state := schritt_101;

case schritt_101:
   if eier_timer.out then
        state := schritt_xyz;
    end_if;
```
Wichtig ist in jedem Fall, dass der IN-Eingang einen Low-High-Übergang macht und bei jedem Wechsel des Eingangs der FB-Code ausgeführt wird, was nur dann geschieht, wenn der so dasteht: 


```
eier_timer(....);
```


----------

