TIA Intervallschaltung von Antrieben

uweschwarz

Level-2
Beiträge
267
Reaktionspunkte
17
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo, ich arbeite mit einer S7 1516 und TIA V17. Ich möchte eine Funktion schreiben, bei der ich einen Antrieb für eine Einschaltzeit einschalte und nach einer Pausenzeit wieder einschalte. Die Funktion sollte, solange sie aktiviert ist, immer wieder von vorn beginnen. Also z.B. den Antrieb alle 10s für 5s einschalten.

Meine momentane Lösung sieht so aus:

Da ich weiß, dass ich manchmal etwas schlampig programmiere, würde ich euch bitte kritisch drauf zu schauen, ob euch etwas auffällt.
Ich weiß z.B. nicht genau ob und wann ich statDriveEnable initialisiere

1753113385349.png

Herzliche Grüße
Uwe
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Auf diese Weise habe ich eine simple Puls-Pause noch nicht gesehen.

- Ich würde es aus dem IF..END_IF-Konstrukt nehmen, einfach Enable mit an die Timer.IN sowie den Ausgang
- Timer nicht in IF..END_IF
- nutze 2 TON-Timer, lassen sich leichter zurücksetzen für Abbruch, erster schaltet ein, zweiter ist Pausenzeit wenn der erste aktiv ist
- statDriveEnable solltest Du nicht zweimal zuweisen.
- #Restzeit_Betrieb:=#instTimer_Betrieb.PT-#instTimer_Betrieb.ET;
- Antrieb startet nicht nachdem Enable aktiv ist sondern erst wenn instTimer_Pause das erste Mal durchgelaufen ist.
- Rücksetzmöglichkeit einfügen. Aktuell ein NOT Enable führt dazu das #Antrieb_An auf dem letzten gültigen Wert, evtl. true, bleibt.

Eigene persönliche Präferenz: Ich benenne Variablen in Bausteinen immer mit IN_Name, OUT_Name, INOUT_Name, STA_Name, TMP_Name, C_Name, finde es übersichtlicher da schnell erkennbar ist was das für eine Variable darstellt.
 
Wenn enable nicht gesetzt ist, die timer und den Ausgang zurück setzten und den Baustein per return verlassen.

Code:
If not #enable then
    AUSGANG := FALSE;
    // TIMMER ZURÜCK SETZEN (der scl efehl fällt mir gerade nicht ein)
    Return;
End_if;

// timmer Aufruf
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke für die Hinweise. Das meiste habe ich verstanden.
Ich habe es jetzt so versucht. Aber irgendwo ist noch ein Denkfehler. Die Timer stossen sich zwar gegenseitig an, aber der Antrieb bleibt aus.

Ich glaube, ich habe das noch nicht richtig verstanden. Wen ich nur eine Zuweisung für statDriveEnable habe, wie schalte ich dann mit einer Einschaltverzögerung den Antrieb sofort bei Aktivierung der Funktion ein?
- nutze 2 TON-Timer, lassen sich leichter zurücksetzen für Abbruch, erster schaltet ein, zweiter ist Pausenzeit wenn der erste aktiv ist
- statDriveEnable solltest Du nicht zweimal zuweisen.


Code:
//Initialisierung
//

IF NOT #Enable  THEN
    RESET_TIMER(#instTimer_Pause);
    RESET_TIMER(#instTimer_Betrieb);
    #Antrieb_An := false;
    RETURN;
END_IF;
//Antrieb starten
//
#statDriveEnable := #Enable;
//Betriebszeit starten
#instTimer_Betrieb(IN := #statDriveEnable AND NOT #instTimer_Pause.Q,
                   PT := #Einschaltdauer);
#Restzeit_Betrieb := #instTimer_Betrieb.PT - #instTimer_Betrieb.ET;

//Pausenzeit starten
#instTimer_Pause(IN := #instTimer_Betrieb.Q AND #Enable,
                 PT := #Pausendauer);
#Restzeit_Pause := #instTimer_Pause.PT - #instTimer_Pause.ET;
#statDriveEnable := #instTimer_Pause.Q;
// Ausgang zuweisen
//
#Antrieb_An := #statDriveEnable;
 
Nimm statDriveEnable aus der Gleichung, denke es verwirrt mehr als das es hilft.

So sähe meine Lösung aus:
Code:
REGION Init
    IF NOT #Enable THEN
        RESET_TIMER(#instTimer_Pause);
        RESET_TIMER(#instTimer_Betrieb);
    END_IF;
END_REGION

REGION Betriebszeit starten
    #instTimer_Betrieb(IN := #Enable AND NOT #instTimer_Pause.Q,
                       PT := #Einschaltdauer);
END_REGION

REGION Pausenzeit starten
    #instTimer_Pause(IN := #instTimer_Betrieb.Q,
                     PT := #Pausendauer);
END_REGION

REGION Ausgang zuweisen
    #Antrieb_An := #Enable AND NOT #instTimer_Betrieb.Q;
END_REGION

REGION Restzeiten
    IF #Enable THEN
        #Restzeit_Betrieb := #instTimer_Betrieb.PT - #instTimer_Betrieb.ET;
        #Restzeit_Pause := #instTimer_Pause.PT - #instTimer_Pause.ET;
    ELSE
        #Restzeit_Betrieb := T#0s;
        #Restzeit_Pause := T#0s;
    END_IF;
END_REGION
 
Du überschreibst immer noch #statDriveEnable.
Du setzt das am Bausteinanfag mit enable und weiter unten überschreibst du es mit dem Ausgang deines TP.

Code:
instTimer_Betrieb(IN := #Enable AND NOT #instTimer_Pause.Q,
                   PT := #Einschaltdauer);
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du könntest dir auch einen Baustein erstellen, welchen du öfter aufrufen kannst für die Zukunft :)
1753170576767.png
Code:
// Logik
IF #Enable THEN
    IF #Status = FALSE THEN
        // Pausenphase
        #PauseTimer(IN := TRUE,
                    PT := #Pausenzeit);
        IF #PauseTimer.Q THEN
            #Status := TRUE;
            #PauseTimer(IN := FALSE,
                        PT := T#0s);
        END_IF;
        #Antrieb := FALSE;
    ELSE
        // Einschaltphase
        #Timer(IN := TRUE,
               PT := #Einschaltzeit);
        IF #Timer.Q THEN
            #Status := FALSE;
            #Timer(IN := FALSE,
                   PT := T#0s);
        END_IF;
        #Antrieb := TRUE;
    END_IF;
ELSE
    // Reset alles, wenn nicht aktiviert
    #Timer(IN := FALSE,
           PT := T#0s);
    #PauseTimer(IN := FALSE,
                PT := T#0s);
    #Status := FALSE;
    #Antrieb := FALSE;
END_IF;

und diesen dann in einer Funktion aufrufen:

1753170670648.png

LG
 
Du könntest dir auch einen Baustein erstellen, welchen du öfter aufrufen kannst für die Zukunft :)
Anhang anzeigen 89291
Code:
// Logik
IF #Enable THEN
    IF #Status = FALSE THEN
        // Pausenphase
        #PauseTimer(IN := TRUE,
                    PT := #Pausenzeit);
        IF #PauseTimer.Q THEN
            #Status := TRUE;
            #PauseTimer(IN := FALSE,
                        PT := T#0s);
        END_IF;
        #Antrieb := FALSE;
    ELSE
        // Einschaltphase
        #Timer(IN := TRUE,
               PT := #Einschaltzeit);
        IF #Timer.Q THEN
            #Status := FALSE;
            #Timer(IN := FALSE,
                   PT := T#0s);
        END_IF;
        #Antrieb := TRUE;
    END_IF;
ELSE
    // Reset alles, wenn nicht aktiviert
    #Timer(IN := FALSE,
           PT := T#0s);
    #PauseTimer(IN := FALSE,
                PT := T#0s);
    #Status := FALSE;
    #Antrieb := FALSE;
END_IF;

und diesen dann in einer Funktion aufrufen:

Anhang anzeigen 89292

LG
Genau das macht er dich seit dem ersten Beitrag...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe die Angewohnheit, Timer immer gut sichtbar im SCL-Code zu platzieren. Meist ganz oben. Wenn im FB temporäre Variablen gesetzt werden und die Timer davon abhängig sind (IN), packe ich die Timer nach ganz unten. Die Instanz der Timer sollte immer einmal aufgerufen werden. Timer nur bedingt aufzurufen, führt zu komischen Bugs. Sie mehrmals aufzurufen, ist auch falsch. An anderen Stellen im Programm kann man direkt auf die Attribute (z.B. Q) der Instanz des Timers zugreifen.
 
Ich habe die Angewohnheit, Timer immer gut sichtbar im SCL-Code zu platzieren.
Hierbei hift eine Unterteilung mittels REGION, da dann im Baustein eine Navigation entsteht, die bei FUP/KOP gar nicht darstellbar ist (im alten Simatic Manager war es vorhanden).
Selbst innerhalb einer REGION lassen sich weitere Unterteilungen platzieren.

Beispiel:
Eine simple Klappenüberwachung hat bei mir immer 9 Überwachungen. Diese sind jeweils einzeln in Regions platziert worin weitere Regions für Timer, Auswertung und Rücksetzung der einzelnen Fehler und am Ende eine eigene Region für den Sammelfehler für diese Klappe enthalten ist/sind. Ohne Regions wäre das ein 400 Zeilen langer Code worin nach Kommentaren gesucht werden müsste falls irgendwann etwas geändert werden sollte.
 
Zurück
Oben