紫外工控论坛

 找回密码
 立即注册

扫一扫,访问微社区

QQ登录

只需一步,快速开始

搜索
查看: 2598|回复: 0

[软件资源] 【转】西门子PLCFB41的SCL源码

[复制链接]
冰糖 发表于 2011-4-3 11:16:57 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
最近在论坛看到好多网友寻找西门子PLC FB41的SCL源码,现在就将我从网上搜集(因原始出处好像不能访问了,时间久了我也忘记了,)的源码贴出来,此源程序来源于网络,不保证编译后与原版一致,仅供参考。源码我粗略看了一遍,好象是不完全微分PID,但由于使用的是位置式PID,所以里面还做了手自动的无扰动切换,但个人感觉无扰动切换还是增量PID好,无需做任何处理就直接支持。源码可以通过编译,内容如下:
FUNCTION_BLOCK "CONT_C"
TITLE ='continuous PID controller'
AUTHOR : MT
FAMILY : ICONT
NAME : CONT_C
VERSION : '1.5'
KNOW_HOW_PROTECT
VAR_INPUT
    COM_RST :       BOOL := FALSE;  //完全重启动
    MAN_ON :        BOOL := TRUE;   //手动值打开
    PVPER_ON :      BOOL := FALSE;  //外设过程变量打开
    P_SEL :         BOOL := TRUE;   //比例作用打开
    I_SEL :         BOOL := TRUE;   //积分作用打开
    INT_HOLD :      BOOL := FALSE;  //积分作用保持
    I_ITL_ON :      BOOL := FALSE;  //积分作用初始化
    D_SEL :         BOOL := FALSE;  //微分作用打开
    CYCLE :         TIME := T#1S;   //采样时间
    SP_INT :        REAL := 0.0;    //内部设定值
    PV_IN :         REAL := 0.0;    //过程变量输入
    PV_PER :        WORD := W#16#0; //外设过程变量
    MAN :           REAL := 0.0;    //手动值
    GAIN :          REAL := 2.0;    //比例增益
    TI :            TIME := T#20S;  //积分复位时间
    TD :            TIME := T#10S;  //微分时间
    TM_LAG :        TIME := T#2S;   //微分作用时间延时
    DEADB_W :       REAL := 0.0;    //死区带宽
    LMN_HLM :       REAL := 100.0;  //积分值上限
    LMN_LLM :       REAL := 0.0;    //积分值下限
    PV_FAC :        REAL := 1.0;    //过程变量因子
    PV_OFF :        REAL := 0.0;    //过程变量偏移量
    LMN_FAC :       REAL := 1.0;    //调节值因子
    LMN_OFF :       REAL := 0.0;    //调节值偏移量
    I_ITLVAL :      REAL := 0.0;    //积分作用的初始化值
    DISV :          REAL := 0.0;    //干扰变量
END_VAR
VAR_OUTPUT
    LMN :           REAL := 0.0;    //调节值
    LMN_PER :       WORD := W#16#0; //外设调节值
    QLMN_HLM :      BOOL := FALSE;  //达到调节值上限
    QLMN_LLM :      BOOL := FALSE;  //达到调节值下限
    LMN_P :         REAL := 0.0;    //比例分量
    LMN_I :         REAL := 0.0;    //积分分量
    LMN_D :         REAL := 0.0;    //微分分量
    PV :            REAL := 0.0;    //
    ER :            REAL := 0.0;    //误差信号
END_VAR
VAR
    sInvAlt :       REAL := 0.0;    //上周期比例偏差值
    sIanteilAlt :   REAL := 0.0;    //上周期积分值
    sRestInt :      REAL := 0.0;    //上周期积分偏差量(浮点数计算偏差)
    sRestDif :      REAL := 0.0;    //上周期微分偏差量(浮点数计算偏差)
    sRueck :        REAL := 0.0;    //
    sLmn :          REAL := 0.0;    //上周期调节值
    sbArwHLmOn :    BOOL := FALSE;  //上周期达到调节值上限
    sbArwLLmOn :    BOOL := FALSE;  //上周期达到调节值下限
    sbILimOn :      BOOL := TRUE;   //备用-本程序没有使用该变量
END_VAR
VAR_TEMP
    rCycle :        REAL ;    //采样时间浮点值
    Iant :          REAL ;    //积分增量
    Diff :          REAL ;    //积分量
    Istwert :       REAL ;    //过程变量浮点值
    ErKp :          REAL ;    //偏差比例值
    rTi :           REAL ;    //积分时间浮点值
    rTd :           REAL ;    //微分时间浮点值
    rTmLag :        REAL ;    //微分作用时间延时浮点值
    Panteil :       REAL ;    //比例值
    Ianteil :       REAL ;    //积分值
    Danteil :       REAL ;    //微分值
    Verstaerk :     REAL ;    //
    RueckDiff :     REAL ;    //
    RueckAlt :      REAL ;    //上周期积分量
    dLmn :          REAL ;    //调节量
    gf :            REAL ;    //Hilfwert
    rVal :          REAL ;    //Real Hilfsvariable
END_VAR
    IF COM_RST THEN //PID初始化
        sIanteilAlt := I_ITLVAL ;
        LMN := 0.0 ;
        QLMN_HLM := FALSE ;
        QLMN_LLM := FALSE ;
        LMN_P := 0.0 ;
        LMN_I := 0.0 ;
        LMN_D := 0.0 ;
        LMN_PER := W#16#0 ;
        PV := 0.0 ;
        ER := 0.0 ;
        sInvAlt := 0.0 ;
        sRestInt := 0.0 ;
        SRestDif := 0.0 ;
        sRueck := 0.0 ;
        sLmn := 0.0 ;
        sbArwHLmOn := FALSE ;
        sbArwLLmOn := FALSE ;
    ELSE
        rCycle := DINT_TO_REAL( TIME_TO_DINT( CYCLE ) ) / 1000.0 ;   //采样时间转换为浮点数值
        Istwert := DINT_TO_REAL( INT_TO_DINT( WORD_TO_INT ( PV_PER ) ) ) * 0.003616898 ;
        Istwert := Istwert * PV_FAC + PV_OFF ;    //外设输入转换为浮点数值
        IF NOT PVPER_ON THEN    //过程变量选择
            Istwert := PV_IN ;
        END_IF;
        PV := Istwert ;
        ErKp := SP_INT - PV ;        //计算偏差
        IF ErKp < -DEADB_W THEN
            ER := ErKp + DEADB_W ;
        ELSIF ErKp > DEADB_W THEN
            ER := ErKp - DEADB_W ;
        ELSE
            ER := 0.0 ;
        END_IF;
        ErKp := ER * GAIN ; //偏差比例增益
        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 ;
        IF rTi < rCycle * 0.5 THEN      //积分时间必须 >= 采样时间的0.5倍
            rTi := rCycle * 0.5 ;
        END_IF;
        IF rTd < rCycle THEN            //微分时间必须 >= 采样时间
            rTd := rCycle ;
        END_IF;
        IF rTmLag < rCycle * 0.5 THEN   //微分作用延时时间必须 >= 采样时间的0.5倍
            rTmLag := rCycle * 0.5 ;
        END_IF;
        IF P_SEL THEN   //比例作用投入
            Panteil := ErKp ;
        ELSE
            Panteil := 0.0 ;
        END_IF;
        IF I_SEL THEN   //积分作用投入
            IF I_ITL_ON THEN    //积分初始化
                Ianteil := I_ITLVAL ;
                sRestInt := 0.0 ;
            ELSIF MAN_ON THEN   //手动值输入时的积分量计算,用于用于手动切换自动无扰切换
                Ianteil := sLmn - Panteil - DISV ;
                sRestInt := 0.0 ;
            ELSE    //积分计算
                Iant := ( rCycle / rTi ) * ( ErKp + sInvAlt ) * 0.5 + sRestInt ;
                IF ( ( Iant > 0.0 AND sbArwHLmOn ) OR INT_HOLD ) OR ( Iant < 0.0 AND sbArwLLmOn )THEN //抗积分饱和
                    Iant := 0.0 ;
                END_IF;
                Ianteil := sIanteilAlt + Iant ; //当前积分值 := 上时刻积分值 + 本次积分量
                sRestInt := sIanteilAlt - Ianteil  + Iant ; //感觉 sRestInt一直等于0.0 ;?????不知为何,通过运行发现不为0.0,可能是浮点数计算误差
            END_IF;            
        ELSE
            Ianteil := 0.0 ;
            sRestInt := 0.0 ;
        END_IF;
        Diff := ErKp ;
        IF NOT MAN_ON 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 ;
            sRueck := Diff ;
        END_IF;
        dLmn := Panteil + Ianteil + Danteil + DISV ; //PID输出
        IF MAN_ON THEN //PID手动之打开
            dLmn := MAN ;
        ELSE
            IF NOT I_ITL_ON AND I_SEL THEN  //干扰量处理
                IF Ianteil > LMN_HLM - DISV AND dLmn > LMN_HLM AND dLmn - LMN_D > LMN_HLM THEN
                    rVal := LMN_HLM - DISV ;
                    gf := dLmn - LMN_HLM ;
                    rVal := Ianteil - rVal ;
                    IF rVal > gf THEN
                        rVal := gf ;
                    END_IF;
                    Ianteil := Ianteil - rVal ;
                ELSIF Ianteil < LMN_LLM - DISV AND dLmn < LMN_LLM  AND dLmn - LMN_D < LMN_LLM  THEN
                    rVal := LMN_LLM - DISV ;
                    gf := dLmn - LMN_LLM ;
                    rVal := Ianteil - rVal ;
                    IF rVal < gf THEN
                        rVal := gf ;
                    END_IF;
                    Ianteil := Ianteil - rVal ;
                END_IF;
            END_IF;
        END_IF;
        LMN_P := Panteil ;
        LMN_I := Ianteil ;
        LMN_D := Danteil ;
        sInvAlt := Erkp ;
        sIanteilAlt := Ianteil ;
        sbArwHLmOn := FALSE ;
        sbArwLLmOn := FALSE ;
        IF dlmn >= LMN_HLM  THEN    //调节辆限幅(上限)
            QLMN_HLM := TRUE ;
            QLMN_LLM := FALSE ;
            dlmn := LMN_HLM ;
            sbArwHLmOn := TRUE ;
        ELSE
            QLMN_HLM := FALSE ;
            IF dLmn <= LMN_LLM THEN  //调节辆限幅(下限)
                QLMN_LLM := TRUE ;
                dlmn := LMN_LLM ;
                sbArwLLmOn := TRUE ;
            ELSE
                QLMN_LLM := FALSE ;
            END_IF;
        END_IF;
        sLmn := dLmn ;
        dLmn := dLmn * LMN_FAC + LMN_OFF ;
        LMN := dLmn ;
        dLmn := dLmn* 276.48 ;
        IF dLmn >= 32512.0 THEN
            dLmn := 32512.0 ;
        ELSIF dLmn <= -32512.0 THEN
            dLmn := -32512.0 ;
        END_IF;
        LMN_PER := INT_TO_WORD( DINT_TO_INT( REAL_TO_DINT( dLmn) ) ) ;
    END_IF;
END_FUNCTION_BLOCK

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


--------------------------------------------------------------------------------------------------------------------
本站是工控技术交流站点,论坛内容均为网络收集或会员所发表,并不代表本站立场,会员拥有该内容的所有权力及责任!
本站内容如有侵犯您的版权,请按下面方式联系本站管理员,我们将及时删除处理
管理员:冰糖 QQ:5483695(请直击主题), Mail:admin#ziwai.net(#改成@) 其它非本人.
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论!

QQ|Archiver|手机版|小黑屋|紫外工控论坛. ( 苏ICP备11032118号-1 )

GMT+8, 2024-5-17 12:31 , Processed in 0.390628 second(s), 17 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表