# Verständnisfrage zu einfacher Timer Funktion in ST



## Monty87 (22 Oktober 2012)

Hallo zusammen,
Ich arbeite zur Zeit an meiner Abschlussprojektarbeit für meinen Techniker (Computer und Netzwerktechnik).
Im Zuge dieses Projekts möchte ich eine Steuerung mit TwinCat und einem Beckhoff-Buskoppler realisieren. 
Dazu versuche ich mich nun etwas in Structured Text und TwinCat einzuarbeiten. Leider bin ich bereit auf meine erstes Problem gestoßen, das wahrscheinlich so banal ist, dass mich jetzt die meisten schon auslachen werden^^ 

Ich wollte einen einfachen Timer programmieren, leider funktioniert dieser nicht wie geplant und ich komme einfach nicht auf meinen Fehler.

VAR_INPUT
	ZEIT:TIME;
END_VAR
VAR_OUTPUT
	OK:BOOL:=FALSE ;
END_VAR
VAR
	TIMER:TP;
END_VAR
---------------------------------------
IF TIMER.Q THEN
	TIMER.IN:=FALSE;
ELSE
	TIMER(IN:=TRUE , PT:=ZEIT);
END_IF

Für den Timer benutze ich einen Pulsgeber (PT) dieser sollte lauf Hilfe folgendermassen funktionieren:
Wenn IN FALSE ist, sind die Ausgaben FALSE bzw. 0. 
Sobald IN TRUE ist, wird auch Q TRUE und bleibt TRUE für die Impulsdauer PT. 
Solange Q TRUE ist, wird in ET die Zeit in Millisekunden hochgezählt, bis der Wert gleich dem in PT ist, dann bleibt er gleich.
Der Ausgang Q bleibt TRUE bis die Impulszeit verstrichen ist unabhängig von dem Zustand des Eingangs IN.

Sollte der Timer bereits laufen soll IN wieder auf FALSE gesetzt werden
Läuft er noch nicht wird er mit der Dauer ZEIT gestartet.
Soweit funktioniert das eigentlich auch. Aber die Zeit zählt einfach nicht weiter... Klar ich nehme den Eingang wieder weg aber wenn ich die Beschreibung richtig verstanden habe soll der PT, wenn er erst einmal gestartet wurde unabhängig von IN weiterlaufen. Wo ist hier mein Denkfehler? Das kann doch nur eine dumme Kleinigkeit sein???

Vielen Dank schon einmal
mit freundlichen Grüßen
Eike


----------



## Larry Laffer (22 Oktober 2012)

Ein Timer möchte gerne einen "0 -> 1"-Wechsel am IN erkennen können. Das klappt i.d.R. nicht, wenn er bedingt bearbeitet wird - aslo wie bei dir in einer IF-Abfrage drinhängt.

Der Timer-Aufruf muß (besser) immer ausserhalb so einer Abfrage erfolgen. Dann eignet sich natürlich ein "True" auch nicht zum Triggern ...

Gruß
Larry


----------



## Monty87 (22 Oktober 2012)

hmm okay dann starte ich den Timer doch mal ohne IF. Aber was genau meinst du mit "True eignet sich nicht zum triggern"? Was den dann? Ich könnte mit einem Block zur Erkennung der fallenden Flanke arbeiten?? etwa so: 


VAR_INPUT
    ZEIT:TIME;
END_VAR
VAR_OUTPUT
    OK:BOOL ;
END_VAR
VAR
    TIMER:TP;
    M: F_TRIG;
END_VAR
-----------------------
TIMER(IN:=TRUE , PT:=ZEIT);
M.CLK:=TIMER.Q;
OK:=M.Q;
TIMER.IN:=FALSE;

der Ausgang "OK" bekommt aber seltsamerweise immernoch kein TRUE obwohl der Timer korrekt abläuft...
oder was genau meinst du?
mfg
Eike


----------



## MSB (22 Oktober 2012)

Also du hast wohl da was ganz grundsätzliches nicht verstanden.

Der Timer bzw. allgemein ein FB, wird immer nur an der Aufrufstelle bearbeitet,
also hier Timer*()*, ob hier nun Teile der Schnittstelle drinstehen ist funktionell unerheblich.

Ergo, du ruftst deinen Timer IMMER mit IN = TRUE auf, was du davor und danach auf Timer.IN schreibst ist vollkommen unerheblich.

Du willst vermutlich also alle Zeit x ein Signal, das für einen Zyklus ansteht?
Timer ist wieder ein TP.

```
Timer( IN := NOT OK , PT := ZEIT , Q => OK ) ;
```

P.S. Dein OK kann nicht TRUE werden weil du deine Flanke gar nicht aufrufst mit M();

Mfg
Manuel


----------



## Oberchefe (22 Oktober 2012)

so wie ich das sehe kommt Dein Bit genau für einen Programmzyklus, und das nur einmalig nach dem Start des Programms (nach Ablauf der eingestellten Zeit).

aus der Hilfe:


> Sobald IN TRUE wird, wird in ET die Zeit in Millisekunden hochgezählt


wenn IN aber bereits TRUE ist (und nicht wird) zählt die Zeit nicht hoch!


TIMER(IN:=TRUE , PT:=ZEIT);         //hier wird einmalig (!) nach dem Programmstart der Timer gestartet (Flankenwechsel von IN)
M.CLK:=TIMER.Q;
OK:=M.Q;                                      //nach Ablauf der Zeit einmalig eine Flanke gebildet
TIMER.IN:=FALSE;                         //Timer.IN wird hier zwar auf 0 gesetzt, da der Timer aber hier nicht aufgerufen wird "Timer()" interessiert das nicht! Beim nächsten Aufruf im nächsten Zyklus wird er ja wieder aufegrufen mit IN:=TRUE
Selbst wenn Du einen Aufruf nachschalten würdest kommt nichts vernünftiges dabei raus, der TP würde nachgetriggert sobald er abgelaufen ist. Sollte das gewünscht sein, solltest Du es besser so machen:

TIMER(IN:=NOT TIMER.Q , PT:=ZEIT);


----------



## Monty87 (22 Oktober 2012)

MSB schrieb:


> Also du hast wohl da was ganz grundsätzliches nicht verstanden.



Nun das will ich nicht ausschließen, meine einzigen Programmiererfahrungen beruhen auf ein paar Stunden JAVA in der Schule.
Ich bin mir nicht mal sicher ob man bei dieser Programmiersprache von einer objektorientierten Sprache sprechen kann, das wäre auch mal sehr interessant zu wissen. Ich könnte mir vorstellen dass ich wie bei JAVA Klassen in FBs darstellen kann mithilfe deren ich dann Objekte (verschiedene Instanzen) erzeugen kann. Das ist eine reine Vermutung wissen tue ich leider gar nichts.



MSB schrieb:


> Der Timer bzw. allgemein ein FB, wird immer nur an der Aufrufstelle bearbeitet,
> also hier Timer*()*, ob hier nun Teile der Schnittstelle drinstehen ist funktionell unerheblich.



Bin nicht sicher ob ich das jetzt richtig verstanden habe: Das bedeutet also ich kann zwar später auf Ausgangs-Variablen eines FBs zugreifen (zB: M.CLK:=TIMER.Q kann dessen Eingangs-Variablen aber später nicht mehr verändern (zb: TIMER.IN := FALSE?



MSB schrieb:


> Du willst vermutlich also alle Zeit x ein Signal, das für einen Zyklus ansteht?
> Timer ist wieder ein TP.
> 
> ```
> ...


fast, ich benötige einen FB dem bei Aufruf die gewünschte Zeit übergeben wird. Nach Ablauf dieser Zeit soll der Ausgang "OK" auf TRUE gehen. Ich denke eines meiner Probleme war, dass ich den FB unbedingt wieder am Ende in den Ursprungszustand bringen wollte. Das scheint aber unwichtig zu sein da beim erneuten Aufruf des FBs ja eine neue Instanz dessen mit den Default-Werten erstellt wird. (Wenn das totaler Blödsinn ist klärt mich bitte auf^^) Das führt mich aber zur nächsten Frage: Wie lange genau "lebt" eine Instanz eines FBs?



MSB schrieb:


> P.S. Dein OK kann nicht TRUE werden weil du deine Flanke gar nicht aufrufst mit M();



Das ist sogar für mich einleuchtend. Ich habe das nun mal so versucht:

M();
Timer( IN := NOT OK , PT := ZEIT);
M.CLK:=Timer.Q;
OK:= M.Q;

Ich bin nicht sicher ob das ideal ist, aber scheint zumindest schon mal zu funktionieren. Vielen Dank.
mfg
Eike


----------



## Larry Laffer (23 Oktober 2012)

Monty87 schrieb:


> ...Ich bin mir nicht mal sicher ob man bei dieser Programmiersprache von einer objektorientierten Sprache sprechen kann, das wäre auch mal sehr interessant zu wissen. Ich könnte mir vorstellen dass ich wie bei JAVA Klassen in FBs darstellen kann mithilfe deren ich dann Objekte (verschiedene Instanzen) erzeugen kann.



Hallo Eike,
Du kannst hier nicht wirklich von einer OOP-Sprache sprechen - wenngleich es natürlich möglich ist, Programme zu erstellen, die in die richtige Richtung gehen.
Ein FB entspricht vom tatsächlichen Ansatz eher einer Prozedur als einer Klasse. Allerdings kannst du ihn mehrfach instanzieren und somit auch mit etwas Fantasie unterschiedlich arbeiten lassen.
Dadurch ergibt sich dann die Möglichkeit im Quasi-Methoden zu verpassen (die dann entsprechend einer Beschaltungs-Anwahl bearbeitet werden - oder auch nicht).

Gruß
Larry


----------



## Monty87 (30 Oktober 2012)

Hi 
ich bins wiedermal, und will euch schon wieder belästigen 
aus irgend einem Grund bereiten mir Timer massive Problem... Zur Übung wollte ich folgenden auf Wikipedia (Beispiel 6) zu findenden Timer nach bauen:



```
[COLOR=#000000][FONT=monospace]VAR[/FONT][/COLOR]
TIMER1: TON;  
TIMER2: TON;  
FF1: RS; (* Flipflop 1 *)  
FF2: RS; (* Flipflop 2 *)  
FF3: RS; (* Flipflop 3 *)
END_VAR

TIMER1 ( IN :=NOT FF1.Q1 , PT := T#0.2s );
FF1 (SET := TIMER1.Q);
FF1 (RESET1:= NOT TIMER2.Q);
TIMER2 ( IN :=NOT FF2.Q1 AND TIMER1.q , PT := T#0.4s );
FF2 (SET := TIMER2.Q);
FF2 (RESET1:= NOT TIMER1.Q);
FF3(SET:=TIMER1.Q); 
[COLOR=#000000][FONT=monospace]FF3(RESET1:=TIMER2.Q);[/FONT][/COLOR]
```

Wenn ich den Code auf einem Blatt nach zeichne und versuche zu verstehen komm ich zu dem Schuss, dass der Ausgang von FF3 der Ausgang des Blinksignals sein muss, weil er abwechselnd von Timer 1 gesetzt und von Timer 2 wieder rückgesetzt wird.

Wenn ich den Code in TwinCat einfüge und ausführe bleibt FF3 aber dauerhaft auf True. Es scheint als würde der Ausgang von Timer 2 nicht kommen. Aber irgendetwas scheint ja in den gewünschten Zeitabständen zu blinken... nur eben nicht das was erwartet. Bin ich einfach zu dumm dafür oder wo ist diesmal mein Denkfehler?


----------



## gloeru (31 Oktober 2012)

Ich kann dir nicht direkt weiterhelfen (bin irgendwo in der kanadischen Prärie im Zug - mit WLAN )

Versuche doch, entweder die Zeiten so gross zu machen, dass die Abläufe in TwinCAT anschauen kannst, oder mit Scope eine Aufzeichung der entsprechenden Zustände...
Weiter könntest du in mit CTRL+F5 immer nur ein Zyklus abarbeiten.
Grundsätzlich ist dieses Beispiel für S5 gemacht. Ich kenne die konkreten Unterschiede zwischen S5 und CoDeSys im bezug auf Timer und FFs nicht...
In CoDeSys braucht du für einen Blinker keine FlipFlops, 2 Timer reichen!


----------



## StructuredTrash (31 Oktober 2012)

Mal wieder ein gutes Beispiel dafür, wie man einfache Dinge kompliziert macht. Es geht auch mit einem Timer und einer einfachen BOOL-Variablen.

```
VAR
   Timer:TON;
   Blink:BOOL;
END_VAR

IF Blink
THEN
   Timer.PT:=t#200ms;
ELSE
   Timer.PT:=t#400ms;
END_IF
Timer(IN:=NOT Timer.Q);
Blink:=Blink XOR Timer.Q;
```


----------



## Monty87 (31 Oktober 2012)

Vielen Dank das sieht doch schon deutlich einfacher aus 

Aber ich werde sicher bald mit dem nächsten Problem kommen...

mfg Eike


----------



## Monty87 (1 November 2012)

als hätte ich es geahnt...

Diesmal habe ich Probleme einem Array Werte zuzuweisen:



IF RiseStart.Q THEN					(*bei steigender Flanke von Start wird i auf 1 gesetzt und damit die Messwerterfassung gestartet*)
i:=1;
END_IF


IF RiseImpuls.Q AND i>0 THEN			(*bei steigender Flanke von Impuls und wenn i größer als 0 ist werden Messwerte aufgenommen*)
Array_MW_A_:=	r_MW_A;
Array_MW_B:=	r_MW_B;
Array_MW_P:=	r_MW_P;
test1:=test2;
i:=i+1;
END_IF

Das Programm soll den aktuellen Messwert (zB r_MW_A) auf die Stelle i im Array_MW_A speichern. Das funktioniert aber nicht wirklich. Zum testen habe ich den Wert test2 dem Wert test1 zugewiesen, was auch funktioniert sprich die IF Bedingung wird korrekt ausgeführt. Aber warum klappt der Rest nicht?

mfg Eike_


----------



## lilli (1 November 2012)

IF RiseStart.Q THEN                    (*bei steigender Flanke von Start wird i auf 1 gesetzt und damit die Messwerterfassung gestartet*)
i:=1;
END_IF

IF RiseImpuls.Q AND i>0 AND i<= iMAX THEN            (*bei steigender Flanke von Impuls und wenn i größer als 0 ist werden Messwerte aufgenommen*)
Array_MW_A_:=    r_MW_A;
Array_MW_B:=    r_MW_B;
Array_MW_P:=    r_MW_P;
test1:=test2;
i:=i+1;
END_IF_


----------



## Monty87 (1 November 2012)

Hi, 
vielen Dank! Aber leider nicht die Lösung des Problems.
in meinem Fall ware iMax 10:

IF RiseImpuls.Q AND i>0 AND i<= 10 THEN

die werte werden aber so auch noch nicht gesetzt.
Habe ich vielleicht den array falsch deklariert?

VAR_OUTPUT
	Array_MW_A: 						ARRAY [1..10] OF REAL;
	Array_MW_B: 						ARRAY [1..10] OF REAL;
	Array_MW_P: 						ARRAY [1..10] OF REAL;
END_VAR


----------



## MSB (1 November 2012)

Generell soweit vom Codeschnipsel her beurteilbar muss das funktionieren.

Der Fehler muss also "extern" von dem Codeschnipsel zu suchen sein.

Mfg
Manuel


----------



## Monty87 (2 November 2012)

Vielen Dank erst mal
Habe soeben den Fehler behoben - obwohl ich in leider nicht ganz nachvollziehen kann. Ich habe den oben beschriebenen FB von einem anderen Programm aus aufgerufen. Habe in diesem Programm jetzt etwas mit den Eingangsvariablen herumgespielt und plötzlich geht alles. Irgendwie kann ich die Messwerte (zb r_MW_A) manchmal nur von dem übergeordneten Programm forcen, manchmal geht es aber auch von der FB Instanz aus.... da steig ich leider nicht so ganz dahinter
mfg


----------

