FUNCTION_BLOCK "MZylinder"
TITLE = Zylinderansteuerung
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : IBAE
FAMILY : Module
NAME : MZylinder
//SCL-Portierung des AWL-Bausteins FB92 "MZylinder" (verhaltensgleich).
//Schnittstelle und Instanzdaten (UDT "UZylinder") unveraendert.
   VAR_INPUT
      Automatik : Bool;   // Automatikbetrieb ist aktiv
      Handbetrieb : Bool;   // Handbetrieb ist aktiv
      T_Ast : Int := 5;   // Zeit bis AST erreicht ist (*100ms)
      T_Gst : Int := 5;   // Zeit bis GST erreicht ist (*100ms)
   END_VAR

   VAR_OUTPUT
      ZylAst : Bool;   // Vorwaerts-Ausgang des Antriebs
      ZylGst : Bool;   // Rueckwaerts-Ausgang des Antriebs
   END_VAR

   VAR
      Stat { S7_SetPoint := 'True'} : "UZylinder";
   END_VAR

   VAR_TEMP
      tZeitNullen : Bool;   // AWL-Sprungziel "tdel": Zeitzelle nullen + Old_Ast nachfuehren
      tFehler : Bool;   // NW5: undefinierter Zustand / Befehl
      tFlanke : Bool;   // NW10: Flankenergebnis
   END_VAR

BEGIN
    REGION NW1: Zeitwert loeschen
        // Endstellung erreicht oder Fahrtrichtung hat gewechselt -> Zeit nullen
        #tZeitNullen := (#ZylAst AND (#Stat.B_AST OR NOT #Stat.Old_Ast))
                        OR (NOT #ZylAst AND (#Stat.B_GST OR #Stat.Old_Ast));
    END_REGION

    IF NOT #tZeitNullen THEN
        REGION NW2: AST-Erreichtzeit abgelaufen ?
            IF #Stat.T_AST_Akt = 9999 THEN
                #Stat.T_AST_Akt := #T_Ast;   // Sollwert uebergeben (9999 = kein Zeitwert angegeben)
            END_IF;

            IF #ZylAst THEN   // Zylinder faehrt nach AST ?
                #Stat.B_GST := FALSE;
                IF #Stat.T_Zelle >= #Stat.T_AST_Akt THEN   // Gewollter Zeitwert erreicht ?
                    #Stat.B_AST := TRUE;    // Zylinder hat AST erreicht
                    #tZeitNullen := TRUE;   // AWL: JC tdel
                END_IF;
            ELSIF NOT #Stat.Typ5_3 THEN   // Zylinder haelt seine Stellung !
                #Stat.B_AST := FALSE;
            END_IF;
        END_REGION
    END_IF;

    IF NOT #tZeitNullen THEN
        REGION NW3: GST-Erreichtzeit abgelaufen ?
            IF #Stat.T_GST_Akt = 9999 THEN
                #Stat.T_GST_Akt := #T_Gst;   // Sollwert uebergeben (9999 = kein Zeitwert angegeben)
            END_IF;

            // Zylinder faehrt nach GST ? (2-fache Ansteuerung: ZylGst / 1-fache: ZylAst aus)
            IF ((#Stat.Typ5_2 OR #Stat.Typ5_3) AND #ZylGst)
               OR (#Stat.Typ3_2 AND NOT #ZylAst) THEN
                #Stat.B_AST := FALSE;
                IF #Stat.T_Zelle >= #Stat.T_GST_Akt THEN   // Gewollter Zeitwert erreicht ?
                    #Stat.B_GST := TRUE;    // Zylinder hat GST erreicht
                    #tZeitNullen := TRUE;   // AWL: JC tdel
                END_IF;
            ELSIF NOT #Stat.Typ5_3 THEN   // Zylinder haelt seine Stellung !
                #Stat.B_GST := FALSE;
            END_IF;
        END_REGION
    END_IF;

    IF NOT #tZeitNullen THEN
        REGION NW4: Zeit laeuft
            // Nicht zaehlen, wenn 2-fach angesteuerter Zylinder gar nicht angesteuert wird;
            // Zaehlung nur mit dem 100ms-Impuls
            IF "100ms-Impuls"
               AND NOT ((#Stat.Typ5_2 OR #Stat.Typ5_3) AND NOT #ZylGst AND NOT #ZylAst) THEN
                #Stat.T_Zelle := #Stat.T_Zelle + WORD_TO_INT("MW2");   // 100ms-Takte
            END_IF;
        END_REGION
    ELSE
        // AWL-Sprungziel "tdel" (aus NW1/NW2/NW3)
        #Stat.T_Zelle := 0;           // Zeitwert loeschen
        #Stat.Old_Ast := #ZylAst;     // Fuhr letzten Zyklus nach AST
    END_IF;

    REGION NW5: Undefinierte Zustaende / Befehle
        #tFehler := (#Automatik AND #Handbetrieb)                                    // Automatik + Hand aktiv
                    OR (NOT #Automatik AND NOT #Handbetrieb)                         // keine Betriebsart
                    OR (#Stat.Ast AND #Stat.Gst)                                     // AST- + GST-fahren gleichzeitig aktiv
                    OR (NOT #Stat.Typ3_2 AND NOT #Stat.Typ5_2 AND NOT #Stat.Typ5_3)  // undefinierter Ventil-Typ
                    OR (#Stat.Typ3_2 AND (#Stat.Typ5_2 OR #Stat.Typ5_3))             // mehrere Ventil-Typen
                    OR (#Stat.Typ5_2 AND #Stat.Typ5_3);

        IF #tFehler THEN   // Zylinderstellung bleibt eingefroren
            IF #Stat.Typ5_3 THEN   // Zylinder haelt seine Stellung !
                #Stat.Ast := FALSE;   // Bewegungsbits loeschen
                #Stat.Gst := FALSE;
            END_IF;
            RETURN;   // AWL: BEU
        END_IF;
    END_REGION

    REGION NW6: Zylinder auf Arbeitsstellung fahren
        #ZylAst := #Stat.Ast;
    END_REGION

    REGION NW7: Zylinder auf Grundstellung fahren
        #ZylGst := (#Stat.Typ5_2 OR #Stat.Typ5_3) AND #Stat.Gst;
    END_REGION

    REGION NW8: Daten, die zurueckgesetzt werden
        IF #Stat.Typ5_3 THEN   // Zylinder haelt seine Stellung !
            #Stat.Ast := FALSE;   // Bewegungsbits loeschen
            #Stat.Gst := FALSE;
        END_IF;
        IF #Stat.Typ3_2 THEN
            #Stat.Gst := FALSE;   // Es gibt kein GST fahren !
        END_IF;
    END_REGION

    REGION NW9: Ausgaenge an OP uebergeben
        #Stat.OP_Out_GST := #ZylGst;
        #Stat.OP_Out_AST := #ZylAst;
    END_REGION

    REGION NW10: Statistik
        // Positive Flanke ZylAst (AWL: FP Stat.FP_AST)
        #tFlanke := #ZylAst AND NOT #Stat.FP_AST;
        #Stat.FP_AST := #ZylAst;
        IF #tFlanke THEN
            #Stat.Statistik.AST_Schaltungen := #Stat.Statistik.AST_Schaltungen + 1;
        END_IF;

        // Positive Flanke ZylGst bei Typ5_3 (AWL: FP Stat.FP_AST2)
        #tFlanke := #ZylGst AND #Stat.Typ5_3 AND NOT #Stat.FP_AST2;
        #Stat.FP_AST2 := #ZylGst AND #Stat.Typ5_3;
        IF #tFlanke THEN
            #Stat.Statistik.AST2_Schaltungen := #Stat.Statistik.AST2_Schaltungen + 1;
        END_IF;
    END_REGION
END_FUNCTION_BLOCK
