FUNCTION_BLOCK "Alarm_Proc"
TITLE='模拟量进行限值报警'
VERSION:'0.5'
KNOW_HOW_PROTECT
AUTHOR:Goosy
NAME:AlarmPrc
FAMILY:GooLib

VAR_INPUT
    enable_AH {S7_m_c := 'true'} : Bool := TRUE; // 允许AH报警
    enable_WH {S7_m_c := 'true'} : Bool := TRUE; // 允许WH报警
    enable_WL {S7_m_c := 'true'} : Bool := TRUE; // 允许WL报警
    enable_AL {S7_m_c := 'true'} : Bool := TRUE; // 允许AL报警
    invalid {S7_m_c := 'true'} : BOOL := FALSE;  // 数据无效，置位时不进行报警
    PV {S7_m_c := 'true'} : REAL ;               // 被监测量
    zero {S7_m_c := 'true'} : REAL ;             // 量程低值
    span {S7_m_c := 'true'} : REAL := 100.0;     // 量程高值
    AH_limit {S7_m_c := 'true'} : REAL ;         // 高高报设定值
    WH_limit {S7_m_c := 'true'} : REAL ;         // 高报设定值
    WL_limit {S7_m_c := 'true'} : REAL ;         // 低报设定值
    AL_limit {S7_m_c := 'true'} : REAL ;         // 低低报设定值
    dead_zone {S7_m_c := 'true'} : REAL := 0.5;  // 死区 （赋值0.0时无死区）
    FT_time {S7_m_c := 'true'} : DINT := 0;      // 容错时间 (单位毫秒 赋值0时无容错时间)
    ftTime AT FT_time : TIME;
END_VAR

VAR_OUTPUT 
    AH_flag {S7_m_c := 'true'} : BOOL;   // 高高报标志
    WH_flag {S7_m_c := 'true'} : BOOL;   // 高报标志
    WL_flag {S7_m_c := 'true'} : BOOL;   // 低报标志
    AL_flag {S7_m_c := 'true'} : BOOL;   // 低低报标志
    SP_error {S7_m_c := 'true'} : BOOL;  // 设置错误
    AH_PV {S7_m_c := 'true'} : REAL ;    // AH报警时的最后过程值
    WH_PV {S7_m_c := 'true'} : REAL ;    // WH报警时的最后过程值
    WL_PV {S7_m_c := 'true'} : REAL ;    // WL报警时的最后过程值
    AL_PV {S7_m_c := 'true'} : REAL ;    // AL报警时的最后过程值
END_VAR

VAR 
    trigger_AH : BOOL;   // 触发高高报
    trigger_WH : BOOL;   // 触发高报
    trigger_WL : BOOL;   // 触发低报
    trigger_AL : BOOL;   // 触发低低报
    AH_flag_set : TON;
    AH_flag_reset : TOF;
    WH_flag_set : TON;
    WH_flag_reset : TOF;
    WL_flag_set : TON;
    WL_flag_reset : TOF;
    AL_flag_set : TON;
    AL_flag_reset : TOF;
END_VAR

VAR_TEMP 
    tmp_AH : REAL;
    tmp_WH : REAL;
    tmp_WL : REAL;
    tmp_AL : REAL;
END_VAR

BEGIN

//补全限制值
IF enable_AH THEN
    tmp_AH := AH_limit;
ELSIF enable_WH THEN
    tmp_AH := WH_limit;
ELSIF enable_WL THEN
    tmp_AH := WL_limit;
ELSIF enable_AL THEN
    tmp_AH := AL_limit;
END_IF;

IF enable_WH THEN
    tmp_WH := WH_limit;
ELSE
    tmp_WH := AH_limit;
END_IF;

IF enable_WL THEN
    tmp_WL := WL_limit;
ELSE
    tmp_WL := WH_limit;
END_IF;

IF enable_AL THEN
    tmp_AL := AL_limit;
ELSE
    tmp_AL := WL_limit;
END_IF;

//参数设置错误
SP_error := (tmp_WH > tmp_AH) OR (tmp_WL > tmp_WH) OR (tmp_AL > tmp_WL);

//报警触发
IF invalid OR SP_error THEN
    AH_flag := FALSE;
    WH_flag := FALSE;
    WL_flag := FALSE;
    AL_flag := FALSE;
    trigger_AH := FALSE;
    trigger_WH := FALSE;
    trigger_WL := FALSE;
    trigger_AL := FALSE;
ELSE
    //上上限报警
    IF enable_AH AND (PV > AH_limit) THEN
        trigger_AH := TRUE;
        trigger_WH := FALSE;
        trigger_WL := FALSE;
        trigger_AL := FALSE;
        // 记录最后的报警值
        AH_PV := PV;
    END_IF;
    //上上限报警恢复
    IF NOT enable_AH OR PV < (AH_limit - dead_zone) THEN
        trigger_AH := FALSE;
    END_IF;
    
    //上限报警
    IF NOT trigger_AH AND enable_WH AND (PV > WH_limit) THEN
        trigger_WH := TRUE;
        trigger_WL := FALSE;
        trigger_AL := FALSE;
        // 记录最后的报警值
        WH_PV := PV;
    END_IF;
    //上限报警恢复
    IF NOT enable_WH OR PV < (WH_limit - dead_zone) THEN
        trigger_WH := FALSE;
    END_IF;
    
    //下下限报警
    IF enable_AL AND (PV < AL_limit) THEN
        trigger_AH := FALSE;
        trigger_WH := FALSE;
        trigger_WL := FALSE;
        trigger_AL := TRUE;
        // 记录最后的报警值
        AL_PV := PV;
    END_IF;
    //下下限报警恢复
    IF NOT enable_AL OR PV > (AL_limit + dead_zone) THEN
        trigger_AL := FALSE;
    END_IF;
    
    //下限报警
    IF NOT trigger_AL AND enable_WL AND (PV < WL_limit) THEN
        trigger_AH := FALSE;
        trigger_WH := FALSE;
        trigger_WL := TRUE;
        // 记录最后的报警值
        WL_PV := PV;
    END_IF;
    //下限报警恢复
    IF NOT enable_WL OR PV > (WL_limit + dead_zone) THEN
        trigger_WL := FALSE;
    END_IF;
END_IF;

// 容错时限后输出报警标志
IF FT_time = 0 THEN
    AH_flag := trigger_AH;
    WH_flag := trigger_WH;
    WL_flag := trigger_WL;
    AL_flag := trigger_AL;
ELSE
    // 延时置位高高报
    AH_flag_set(
        IN := trigger_AH,
        PT := ftTime);
    IF AH_flag_set.Q THEN
        AH_flag := TRUE;
    END_IF;

    // 延时复位高高报
    AH_flag_reset(
        IN := trigger_AH,
        PT := ftTime);
    IF NOT AH_flag_reset.Q THEN
        AH_flag := FALSE;
    END_IF;
    
    // 延时置位高报
    WH_flag_set(
        IN := trigger_WH,
        PT := ftTime);
    IF WH_flag_set.Q THEN
        WH_flag := TRUE;
    END_IF;

    // 延时复位高报
    WH_flag_reset(
        IN := trigger_WH,
        PT := ftTime);
    IF NOT WH_flag_reset.Q THEN
        WH_flag := FALSE;
    END_IF;
    
    // 延时置位低报
    WL_flag_set(
        IN := trigger_WL,
        PT := ftTime);
    IF WL_flag_set.Q THEN
        WL_flag := TRUE;
    END_IF;

    // 延时复位低报
    WL_flag_reset(
        IN := trigger_WL,
        PT := ftTime);
    IF NOT WL_flag_reset.Q THEN
        WL_flag := FALSE;
    END_IF;

    // 延时置位低低报
    AL_flag_set(
        IN := trigger_AL,
        PT := ftTime);
    IF AL_flag_set.Q THEN
        AL_flag := TRUE;
    END_IF;
    
    // 延时复位低低报
    AL_flag_reset(
        IN := trigger_AL,
        PT := ftTime);
    IF NOT AL_flag_reset.Q THEN
        AL_flag := FALSE;
    END_IF;
    
END_IF;

END_FUNCTION_BLOCK
