Structured Text - TON Timer BUG

DerBenutzer

Level-1
Beiträge
13
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi ich habe ein kleines Problem mit einem TON Timer. Obwohl dessen Eingang auf True gesetzt ist will dieser einfach nicht anfangen zu zählen.
Kennt einer dieses Phänomen? Hier ist mal ein Bild des Ganzen, es geht dabei um TimerRichtung2. Vielleicht erkennt jemand das Ganze auch wieder, da es mit Hilfe von
ein paar netten Leuten hier im Forum entstanden ist.
timer.jpg
Code sieht wie folgt aus, ist aber doch etwas komplexer geworden - es geht hierbei aber wirklich nur um Timerrichtung2 und warum dieser im Variablenfenster nicht hochzählt. Zur Erläuterung wir befinden uns in Schritt 1 beim
Fall SuchenLinks:
Code:
PROGRAM MAIN
VAR CONSTANT   
    Start:BYTE:=0;
    SuchenLinks:BYTE:=1;
    SuchenRechts:BYTE:=2;
    Schieben:BYTE:=3;
END_VAR


(*Deklaration der Variablen*)
VAR
   x:BOOL;
   IMPULS:BOOL;
   Schritt:BYTE;
   Timer1:TON;
   Timer2:TON;
   Timer3:TON;
   Timer0:TON;
   TimerRichtung:TON;
   TimerRichtung2:TON;
   TimerRichtung3:TON;
   zaehler:BYTE;
   RichtungRechts:BOOL;
   RichtungLinks:BOOL;
   Lichtschranke:BOOL;
END_VAR







CASE Schritt OF
   Start:     
         RichtungRechts:=False;
         RichtungLinks:=False;    
         IF Timer0.Q THEN
             Timer0.IN:=FALSE;   
               RichtungLinks:=True;
             Schritt:=SuchenLinks;
         END_IF


   SuchenLinks:
  
      IF  Lichtschranke THEN
              Impuls:=True;
      END_IF   


      IF Impuls THEN
         IF zaehler>4 AND NOT TimerRichtung.Q THEN
            RichtungLinks:=False;
            TimerRichtung(IN:=TRUE, PT:=T#2S);
         ELSIF TimerRichtung.Q THEN
            RichtungRechts:=True;
            Impuls:=False;
            TimerRichtung.In:=False;
            Timer1.In:=False;
            Schritt:=Schieben;


         ELSIF zaehler<=4 THEN
            
             Impuls:=False;
            Timer1.In:=False;
            Schritt:=Schieben;
         END_IF
     
      ELSIF TimerRichtung2.Q THEN
             RichtungRechts:=TRUE;
             TimerRichtung2.IN:=FALSE;
             Timer1.IN:=FALSE;
             Schritt:=SuchenRechts;
             
      ELSIF (Timer1.Q AND NOT TimerRichtung.In) AND NOT(TimerRichtung2.IN) THEN
         RichtungLinks:=False;
         TimerRichtung2(IN:=TRUE, PT:=T#2S);
     
        
         
      END_IF
   










   
 SuchenRechts:
      IF  Lichtschranke THEN
         Impuls:=True;
      END_IF


      IF Impuls THEN
         IF zaehler<=4 AND NOT TimerRichtung.Q THEN
            RichtungRechts:=False;
            TimerRichtung3(IN:=TRUE, PT:=T#2S);
         ELSIF TimerRichtung3.Q THEN
            RichtungLinks:=True;
            Impuls:=False;
            TimerRichtung3.In:=FALSE;
            Timer2.In:=False;
            Schritt:=Schieben;
         ELSIF zaehler>4 THEN
            Impuls:=False;
                Schritt:=Schieben;
         END_IF
      ELSIF Timer2.Q AND NOT TimerRichtung3.IN THEN
         Timer2.IN:=False;
             Schritt:=Start;
      END_IF
   Schieben:
      IF Timer3.Q THEN
         Timer3.IN:=False;
         IF Zaehler<10 THEN
            Zaehler:=Zaehler+1;
         ELSE
            Zaehler:=0;
         END_IF
         Schritt:=Start;
      END_IF
END_CASE




Timer1(IN:=Schritt=SuchenLinks, PT:=T#2S);
Timer2(IN:=Schritt=SuchenRechts, PT:=T#3S);
Timer3(IN:=Schritt=Schieben, PT:=T#5S);
Timer0(IN:=Schritt=Start, PT:=T#3S);
 
Offenbar tritt nie der Zustand ein, dass das Programm in den Bereich kommt, wo
TimerRichtung2(IN:=TRUE, PT:=T#2S);
steht oder direkt im nächsten Zyklus wieder in der Bedingung für
ELSIF TimerRichtung2.Q THEN
RichtungRechts:=TRUE;
TimerRichtung2.IN:=FALSE;
Timer1.IN:=FALSE;
Schritt:=SuchenRechts;
landet.

Und als Randbemerkung: Mein Chef sagt immer, "Wer ELSIF verwendet, weiss nicht mehr weiter, obwohl es Situationen gibt, wo es Sinn macht"
Du verwendest ELSIF exzessiv und daran sieht man, dass du - so wie ich - aus der PC-Programmierung kommst und noch immer zu kompliziert denkst.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Timer(-FB) müssen in jedem Zyklus aufgerufen werden, Aufruf in IF- oder CASE-Zweigen ist falsch. Du mußt das Programm umformen, so daß in den IF-Zweigen nur eine Variable für den TimerRichtung2.IN manipuliert wird und TimerRichtung2(IN:=variable, PT:=T#2S); muß außerhalb aller IF- aufgerufen werden.

Harald
 
@DerBenutzer
Dein Problem betrifft übrigens alle Timer, nicht nur den TimerRichtung2.
Schaue mal an das Ende Deines Codes: so wie es für die Timer1, Timer2 ... gemacht ist, so mußt Du es bei allen TON machen.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Dem kann ich mich nur anschliessen. Timer und auch die meisten anderen FBs aus der Standard-Lib funktionieren nur dann richtig, wenn sie zyklisch aufgerufen werden. Wenn ein Timer nicht laufen soll, erreicht man das nicht, indem man ihn nicht aufruft, sondern indem man seinen Eingang IN auf False setzt.
Und wenn Du Dein Programm umbaust, kannst Du auch gleich ein wenig aufräumen. Da stehen immer noch bedingte Anweisungen wie "Timer1.IN:=False", die mit dem zyklischen Aufruf von Timer0...Timer3 inklusive Übergabe des passenden Wertes für Timer.IN überflüsssig geworden sind.
 
Ich danke vielmals für die Tipps. Ich habe jetzt alle If-Else Anweisungen vereinfacht, dadurch musste ich zwar die Reihenfolge der Schleifen ändern, da bei manchen Bedingungen, die neu eingeführten Variablen für die Timer abgefragt wurden und nicht wie vorher bei ELSE-If einfach aus der ganzen Bedingung rausgesprungen wurde, aber letztendlich hat es geklappt. Alle Timer befinden sich jetzt am Ende des Programms und es funktioniert alles wie es soll. Es wundert mich ehrlich gesagt nur, dass bei einem vergleichsweise so einfachem SPS Programm, soviel Gehirnakrobatik erforderlich ist und trotz der eigentlich geringen Funktionalität soviel Code (mehr als 90 Zeilen..., die man aber sicher noch auf ~60 runterbrechen kann) entsteht.

Nur mal aus Interesse, wie behält man da bei größeren Projekten den Überblick oder gibt es generell Strategien an die man sich halten kann?
Vielleicht hätte man bei mir auch irgendwas effizienter lösen können, ein paar der Timer könnte man sicher weglassen. Hier mal der fertige Code:
Code:
CASE Schritt OF   Start:	 
		 RichtungRechts:=False;
		 RichtungLinks:=False;	
   	  IF Timer4.Q THEN   
      		 RichtungLinks:=True;
			 Timer4.IN:=FALSE;
             Schritt:=SuchenLinks;
   	  END_IF


   SuchenLinks:
  
      IF Lichtschranke THEN
      		Impuls:=True;
      END_IF   


      IF Impuls THEN
		 IF zaehler>4 AND NOT x THEN
			RichtungLinks:=False;
			x:=TRUE;
		 END_IF
		 
		 IF TimerRichtung.Q THEN
			RichtungRechts:=True;
			Impuls:=False;
			x:=FALSE;
			Schritt:=Schieben;
         END_IF
		 
		 IF zaehler<=4 THEN
			
		 	Impuls:=False;
			Schritt:=Schieben;
		 END_IF
	  END_IF	 
      
      IF Timer1.Q AND NOT x THEN
		 RichtungLinks:=False;
		 y:=TRUE;
	  END_IF
	  
      IF TimerRichtung2.Q THEN
		 RichtungRechts:=True;
		 y:=FALSE;
		 Schritt:=SuchenRechts;
	  END_IF
      
      
 SuchenRechts:
      IF Lichtschranke THEN
         Impuls2:=True;
      END_IF
	  
	  IF Timer2.Q AND NOT z THEN
		    Schritt:=Start;
	  END_IF
      IF Impuls2 THEN
		 IF zaehler<=4 AND NOT z THEN
			RichtungRechts:=False;
			z:=TRUE;
		 END_IF
		 IF TimerRichtung3.Q THEN
			RichtungLinks:=True;
			Impuls2:=FALSE;
			z:=FALSE;
			Schritt:=Schieben;
		 END_IF
		 IF zaehler>4 THEN
			Impuls2:=False;
        	Schritt:=Schieben;
	     END_IF
	       
      END_IF
   Schieben:
      IF Timer3.Q THEN
		    Zaehler:=Zaehler+1;
         IF zaehler=9 THEN
            Zaehler:=0;
         END_IF
         Schritt:=Start;
      END_IF
END_CASE


Timer1(IN:=Schritt=SuchenLinks, PT:=T#2S);
Timer2(IN:=Schritt=SuchenRechts, PT:=T#4S);
Timer3(IN:=Schritt=Schieben, PT:=T#6S);
Timer4(IN:=Schritt=Start, PT:=T#3S);
TimerRichtung(IN:=x=TRUE, PT:=T#2S);
TimerRichtung2(IN:=y=TRUE, PT:=T#2S);
TimerRichtung3(IN:=z=TRUE, PT:=T#2S);
 
Da kann man sicher noch einiges vereinfachen oder übersichtlicher schreiben. Beispiel:
Im Schritt "SuchenLinks" schaltest Du irgendwann "RichtungLinks" aus und lässt dann "TimerRichtung" ablaufen, um bis zum Einschalten von "RichtungRechts" ein wenig zu warten. Die Abfrage des Timerausgangs steht auch noch bei "SuchenLinks", obwohl da schon gar nicht mehr nach links gesucht wird. Da könntest Du einen Zwischenschritt "WartenAufFreigabeRechts" einfügen. Dieser Schritt könnte dann auch als Timereingang dienen, also "TimerRichtung(IN:=Schritt=WartenAufFreigabeRechts)". Dann brauchst Du die Hilfsvariable "x" nicht mehr.

Auf die Gründe für die zyklische Programmbearbeitung sind wir ja bereits in Deinem Vorgängerthread eingegangen. Wenn mehrere voneinander unabhängige Steuerungsfunktionen quasi parallel bearbeitet werden müssen, kommt man darum nicht herum. Dazu müssen die meisten Vorgänge auf mehrere aufeinanderfolgende Aufrufe des Programms aufgeteilt werden, und das ist schon etwas aufwändiger als wenn man es "in einem Stück" schreiben könnte. Aber daran gewöhnt man sich.
 
Zurück
Oben