FUNCTION_BLOCK PID
TITLE = 'output PID-algorithm'
AUTHOR : AUT_1
FAMILY : MODCONT
NAME : PID
VERSION : '1.4'
//KNOW_HOW_PROTECT
VAR_INPUT
  ER : REAL ;      //error-signal
  PV : REAL ;      //process variable
  GAIN : REAL := 2.000000e+000;        //proportional gain
  TI : TIME := T#20S;       //reset time
  I_ITLVAL : REAL ;      //initialization value of the integral action
  TD : TIME := T#10S;       //derivative time
  TM_LAG : TIME := T#2S;       //time lag of the derivative action
  DISV : REAL ;      //disturbance variable
  P_SEL : BOOL := TRUE;       //proportional action selected
  PFDB_SEL : BOOL ;      //proportional action in feedback path selected
  DFDB_SEL : BOOL ;      //derivative action in feedback path on
  I_SEL : BOOL := TRUE;       //integral action selected
  INT_HPOS : BOOL ;      //integral action hold in positive direction
  INT_HNEG : BOOL ;      //integral action hold in negative direction
  I_ITL_ON : BOOL ;      //initialization of the integral action on
  D_SEL : BOOL ;      //derivative action selected
  DISV_SEL : BOOL := TRUE;        //disturbance variable on
  SMOO_CHG : BOOL := TRUE;        //smooth changeover from the manual mode to the
automatic mode
  COM_RST : BOOL ;      //complete restart
  CYCLE : TIME := T#1S;       //sample time
  LMNG_PID : STRUCT
    LMN : REAL ;
    LMN_HLM : REAL ;
    LMN_LLM : REAL ;
    R_MTR_TM : REAL ;
    ARWHL_ON : BOOL ;
    ARWLL_ON : BOOL ;
    MAN_ON : BOOL ;
    LMNGS_ON : BOOL ;
    LMNR_ON : BOOL ;
  END_STRUCT ;
END_VAR
VAR_OUTPUT
  LMN_P : REAL ;      //proportionality component
  LMN_I : REAL ;      //integral component
  LMN_D : REAL ;      //derivative component
  PID_LMNG : STRUCT
    OUTV : REAL ;
    HVAR1 : REAL ;
    HVAR2 : REAL ;
    HVAR3 : REAL ;
    HBIT1 : BOOL ;
    HBIT2 : BOOL ;
    HBIT3 : BOOL ;
  END_STRUCT ;
END_VAR
VAR
  sInvAlt : REAL ;
  sIanteilAlt : REAL ;
  sRestInt : REAL ;
  sRestDif : REAL ;
  sRueck : REAL ;
  sSpOld : REAL ;
END_VAR
VAR_TEMP
  Hvar : REAL ;      //Hilfsvariable
  ErKp : REAL ;      //Variable ER*GAIN
  rTi : REAL ;      //Integrationszeit in real
  rTd : REAL ;      //Differentiationszeit in real
  rTmLag : REAL ;      //Verzögerungszeit in real
  rCycle : REAL ;      //Abtastzeit in real
  Panteil : REAL ;      //P-Anteil
  Ianteil : REAL ;      //I-Anteil
  Diff : REAL ;      //Änderungswert
  Danteil : REAL ;      //D-Anteil
  Verstaerk : REAL ;      //Verstärkung
  RueckDiff : REAL ;      //Differenz des Rückkopplungswertes
  RueckAlt : REAL ;      //Alter Rückkopplungswert
  dDisv : REAL ;      //disturbance variable
  dLmn : REAL ;      //Stellwert
  PidOutv : REAL ;      //PID-Ausgangswert
  Hvar1 : REAL ;      //PID-Ausgangswert Hilfsvariable 1
  Hvar2 : REAL ;      //PID-Ausgangswert Hilfsvariable 2
  rLmnHlm : REAL ;      //Obere Begrenzung
  rLmnLlm : REAL ;      //Untere Begrenzung
  rMtrTm : REAL ;      //Motorstellzeit
  rSp : REAL ;      //Sollwert
  RegD_PRueck : REAL ;      //Regeldifferenz und P-Anteil in Rückführung
  lmn_i_hlm : REAL ;      //provisorische Begrenzung I-Anteil
  lmn_i_llm : REAL ;      //provisorische Begrenzung I-Anteil
  iKorrektur : REAL ;      //Korrektur des I-Anteils
  iKorrektur2 : REAL ;      //Korrektur des I-Anteils
  bPantKorr : BOOL ;      //P-Anteil zur Anzeige korrigieren
  bIantKorr : BOOL ;      //I-Anteil zur Anzeige korrigieren
  bHvar : BOOL ;      //Hilfsvariable
  bArwhlOn : BOOL ;      //anti reset wind-up in high limit on
  bArwllOn : BOOL ;      //anti reset wind-up in low limit on
  bManOn : BOOL ;      //manual mode on
  bLmngsOn : BOOL ;      //PID-algorithm for step controller
  bLmnrOn : BOOL ;      //step controller with repeated manipulated value
  bHBit1 : BOOL ;      //Hilfsbit 1
  bHBit2 : BOOL ;      //Hilfsbit 2
  bHBit3 : BOOL ;      //Hilfsbit 3
END_VAR
BEGIN
    bHBit1:=FALSE;
    bHBit2:=FALSE;
    bHBit3:=FALSE;
    IF COM_RST THEN
         sRestInt:=0.0;
         sRueck:=0.0;
         sRestDif:=0.0;
         sInvAlt:=0.0;
         sIanteilAlt:=0.0;
         sSpOld:=0.0;
         ErKp:=0.0;
         Panteil:=0.0;
         Ianteil:=0.0;
    Danteil:=0.0;
    PidOutv:=0.0;
    Hvar1:=0.0;
    Hvar2:=0.0;
ELSE
    bManOn:=LMNG_PID.MAN_ON;
    bLmngsOn:=LMNG_PID.LMNGS_ON;
    bLmnrOn:=LMNG_PID.LMNR_ON;
    dLmn:=LMNG_PID.LMN;
    rLmnHlm:=LMNG_PID.LMN_HLM;
    rLmnLlm:=LMNG_PID.LMN_LLM;
    rMtrTm:=LMNG_PID.R_MTR_TM;
    bArwhlOn:=LMNG_PID.ARWHL_ON;
    bArwllOn:=LMNG_PID.ARWLL_ON;
    ErKp:=ER*GAIN;
    rSp:=ER+PV;
    rTi:=DINT_TO_REAL(TIME_TO_DINT(TI))/1000.0;
    rTd:=DINT_TO_REAL(TIME_TO_DINT(TD))/1000.0;
    rTmLag:=DINT_TO_REAL(TIME_TO_DINT(TM_LAG))/1000.0;
    rCycle:=DINT_TO_REAL(TIME_TO_DINT(CYCLE))/1000.0;
    IF rTi<(rCycle*0.5) THEN
         rTi:=rCycle*0.5;
    END_IF;
    IF rTd<rCycle THEN
         rTd:=rCycle;
    END_IF;
    IF rTmLag<(rCycle*0.5) THEN
         rTmLag:=rCycle*0.5;
    END_IF;
    IF DISV_SEL THEN
         dDisv:=DISV;
    ELSE
         dDisv:=0.0;
    END_IF;
    bPantKorr:=FALSE;
    bIantKorr:=FALSE;
    RegD_PRueck:=(-PV)*GAIN;
    Panteil:=0.0;
    IF P_SEL THEN
         IF PFDB_SEL THEN
              IF (NOT I_SEL) OR I_ITL_ON THEN
                   Panteil:=RegD_PRueck;
              ELSE
                   Panteil:=ErKp;
                   bPantKorr:=TRUE;
              END_IF;
         ELSE
              Panteil:=ErKp;
         END_IF;
    END_IF;
    IF bLmngsOn THEN
         Hvar:=rTi-ABS(0.01*ErKp*rMtrTm);
         IF Hvar<(0.1*rTi) THEN
              rTi:=0.1*rTi;
         ELSE
              rTi:=Hvar;
         END_IF;
    END_IF;
    IF I_SEL THEN
    IF I_ITL_ON THEN
         Ianteil:=I_ITLVAL;
         sRestInt:=0.0;
    ELSE
         IF (NOT bLmngsOn) OR (bLmngsOn AND bLmnrOn) THEN
              IF bManOn THEN
                   Ianteil:=dLmn-dDisv;
                   IF ((NOT bLmngsOn) AND SMOO_CHG) OR PFDB_SEL THEN
                        Ianteil:=Ianteil-Panteil;
                   END_IF;
                   sRestInt:=0.0;
              ELSE
                   Diff:=(rCycle/rTi)*(ErKp+sInvAlt)*0.5+sRestInt;
                   IF Diff>=0.0 THEN
                        bHvar:=INT_HPOS OR bArwhlOn;
                   ELSE
                        bHvar:=INT_HNEG OR bArwllOn;
                   END_IF;
                   IF bHvar THEN
                        Diff:=0.0;
                   END_IF;
                   Ianteil:=sIanteilAlt+Diff;
                   sRestInt:=sIanteilAlt-Ianteil+Diff;
                   IF PFDB_SEL AND P_SEL THEN
                        Ianteil:=Ianteil-(rSp-sSpOld)*GAIN;
                   END_IF;
              END_IF;
              bIantKorr:=TRUE;
         ELSE
              Ianteil:=0.0;
              sRestInt:=0.0;
         END_IF;
    END_IF;
ELSE
     Ianteil:=0.0;
     sRestInt:=0.0;
END_IF;
IF DFDB_SEL THEN
     Diff:=(-PV)*GAIN;
ELSE
     Diff:=ErKp;
END_IF;
IF (NOT bManOn) AND D_SEL THEN
     Verstaerk:=rTd/((rCycle*0.5)+rTmLag);
     Danteil:=(Diff-sRueck)*Verstaerk;
     RueckAlt:=sRueck;
     RueckDiff:=(rCycle/rTd)*Danteil+sRestDif;
     sRueck:=RueckDiff+RueckAlt;
     sRestDif:=RueckAlt-sRueck+RueckDiff;
ELSE
     Danteil:=0.0;
     sRestDif:=0.0;
     IF SMOO_CHG OR DFDB_SEL OR bLmngsOn THEN
          sRueck:=Diff;
     ELSE
          sRueck:=0.0;
     END_IF;
END_IF;
PidOutv:=Panteil+Ianteil+Danteil+dDisv;
        bHVar:=((NOT I_ITL_ON) AND I_SEL) AND (NOT bManOn);
        IF ((NOT bLmngsOn) AND bHVar) OR (bLmngsOn AND bLmnrOn AND bHVar) THEN
            lmn_i_hlm:=rLmnHlm-dDisv;
            lmn_i_llm:=rLmnLlm-dDisv;
            IF (Ianteil>lmn_i_hlm) AND (PidOutv>rLmnHlm) AND ((PidOutv-
Danteil)>rLmnHlm) THEN
                 iKorrektur:=Ianteil-lmn_i_hlm;
                 iKorrektur2:=PidOutv-rLmnHlm;
                 IF iKorrektur2<iKorrektur THEN
                      iKorrektur:=iKorrektur2;
                 END_IF;
                 Ianteil:=Ianteil-iKorrektur;
            ELSE
                 IF (Ianteil<lmn_i_llm) AND (PidOutv<rLmnLlm) AND ((PidOutv-
Danteil)<rLmnLlm) THEN
                      iKorrektur:=Ianteil-lmn_i_llm;
                      iKorrektur2:=PidOutv-rLmnLlm;
                      IF iKorrektur2>iKorrektur THEN
                          iKorrektur:=iKorrektur2;
                      END_IF;
                      Ianteil:=Ianteil-iKorrektur;
                 ELSE
                      ;
                 END_IF;
            END_IF;
            IF INT_HPOS OR bArwhlOn THEN
                 IF PidOutv<rLmnHlm THEN
                      iKorrektur:=(rCycle/rTi)*Panteil;
                      IF (iKorrektur+PidOutv)>=rLmnHlm THEN
                          PidOutv:=rLmnHlm;
                          Ianteil:=Ianteil+iKorrektur;
                      END_IF;
                 END_IF;
            ELSIF INT_HNEG OR bArwllOn THEN
                 IF PidOutv>rLmnLlm THEN
                      iKorrektur:=(rCycle/rTi)*Panteil;
                      IF (iKorrektur+PidOutv)<=rLmnLlm THEN
                          PidOutv:=rLmnLlm;
                          Ianteil:=Ianteil+iKorrektur;
                      END_IF;
                 END_IF;
            ELSE
                 ;
            END_IF;
        END_IF;
        sInvAlt:=ErKp;
        sIanteilAlt:=Ianteil;
        sSpOld:=rSp;
        IF bPantKorr AND bIantKorr THEN
            Ianteil:=Ianteil-(RegD_PRueck-Panteil);
        END_IF;
        IF bPantKorr THEN
            Panteil:=RegD_PRueck;
        END_IF;
        IF bLmngsOn THEN
            IF NOT bLmnrOn THEN
                 Hvar1:=ErKp/rTi;
                 Hvar2:=dDisv+Ianteil;
            ELSE
                 Hvar1:=Ianteil;
                 Hvar2:=dDisv;
             END_IF;
             bHBit1:=P_SEL AND I_SEL AND (NOT I_ITL_ON) AND (NOT PFDB_SEL) AND (NOT
DFDB_SEL);
            bHBit2:=(NOT I_ITL_ON) AND I_SEL;
            bHBit3:=rSp<>sSpOld;
         ELSE
            HVar1:=PidOutv-Danteil;
            HVar2:=0.0;
        END_IF;
        sSpOld:=rSp;
    END_IF;
    LMN_P:=Panteil;
    LMN_I:=Ianteil;
    LMN_D:=Danteil;
    PID_LMNG.OUTV:=PidOutv;
    PID_LMNG.HVAR1:=Hvar1;
    PID_LMNG.HVAR2:=Hvar2;
    PID_LMNG.HVAR3:=ErKp;
    PID_LMNG.HBIT1:=bHBit1;
    PID_LMNG.HBIT2:=bHBit2;
    PID_LMNG.HBIT3:=bHBit3;
END_FUNCTION_BLOCK