//**************************************************************************************
// Copyright Goosy. All Rights Reserved. Confidential
// 由 Step7 Alarm_Proc 扩展而来
//**************************************************************************************
FUNCTION_BLOCK "Alarm_Proc"
TITLE='模拟量进行限值报警'
{
  S7_tasklist := 'OB100'; // Block is called if there is in a warm restart
  S7_m_c := 'true';
  S7_alarm_ui := '1'
}
VERSION:'0.5'
KNOW_HOW_PROTECT
AUTHOR:Goosy
NAME:AlarmPrc
FAMILY:GooLib

VAR_INPUT
enable_AH { // 允许AH报警
    S7_shortcut := '允许AH报警';
    S7_m_c := 'true';
    S7_dynamic := 'true'
} : Bool := TRUE;
enable_WH { // 允许WH报警
    S7_shortcut := '允许WH报警';
    S7_m_c := 'true';
    S7_dynamic := 'true'
} : Bool := TRUE;
enable_WL { // 允许WL报警
    S7_shortcut := '允许WL报警';
    S7_m_c := 'true';
    S7_dynamic := 'true'
} : Bool := TRUE;
enable_AL { // 允许AL报警
    S7_shortcut := '允许AL报警';
    S7_m_c := 'true';
    S7_dynamic := 'true'
} : Bool := TRUE;
invalid { // 数据无效，置位时不进行报警
    S7_shortcut := '数据无效标志';
    S7_m_c := 'true';
    S7_dynamic := 'true'
} : BOOL := FALSE;
PV{ // 过程值
  S7_shortcut := '过程值';
  S7_m_c := 'true';
  S7_dynamic := 'true';
  S7_archive := 'shortterm'
} :REAL := 0.0;
zero{ // 零点
  S7_shortcut := '零点';
  S7_m_c := 'true';
  S7_dynamic := 'true'
  // S7_archive:= 'shortterm'
} : REAL := 0.0;
span{ // 量程
  S7_shortcut := '量程';
  S7_m_c := 'true';
  S7_dynamic := 'true'
  // S7_archive:= 'shortterm'
} : REAL := 100.0;
AH_limit{ // 上上限
    S7_link:='false';
    S7_shortcut := '上上限';
    S7_m_c := 'true';
    S7_dynamic := 'true'
    // S7_archive:= 'shortterm'
} : REAL ;
WH_limit{ // 上限
    S7_link:='false';
    S7_shortcut := '上限';
    S7_m_c := 'true';
    S7_dynamic := 'true'
    // S7_archive:= 'shortterm'
} : REAL ;
WL_limit{ // 下限
    S7_link:='false';
    S7_shortcut := '下限';
    S7_m_c := 'true';
    S7_dynamic := 'true'
    // S7_archive:= 'shortterm'
} : REAL ;
AL_limit{ // 下下限
    S7_link:='false';
    S7_shortcut := '下下限';
    S7_m_c := 'true';
    S7_dynamic := 'true'
    // S7_archive:= 'shortterm'
} : REAL ;
dead_zone{ // 死区 （赋值0.0时无死区）
    S7_link:='false';
    S7_shortcut := '防抖死区';
    S7_m_c := 'true';
    S7_dynamic := 'true'
    // S7_archive:= 'shortterm'
} : REAL := 0.5;
FT_time { // 容错时间，单位毫秒 赋值0时无容错时间
    S7_link:='false';
    S7_shortcut := '容错时间';
    S7_m_c := 'true'
} : DINT := 0;
ftTime AT FT_time : TIME;
END_VAR

VAR_OUTPUT 
AH_flag{ // 上上限报警标志
  S7_shortcut := '上上限报警标志';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :BOOL := 0;
WH_flag{ // 上限警告标志
  S7_shortcut := '上限警告标志';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :BOOL := 0;
WL_flag{ // 下限警告标志
  S7_shortcut := '下限警告标志';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :BOOL := 0;
AL_flag{ // 下下限报警标志
  S7_shortcut := '下下限报警标志';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :BOOL := 0;
SP_error{
  S7_shortcut := '设置错误';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :BOOL := 0;

AH_PV{ // AH报警时的最后过程值
  S7_shortcut := 'AH报警实时值';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :REAL := 0.0;
WH_PV{ // WH报警时的最后过程值
  S7_shortcut := 'WH报警实时值';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :REAL := 0.0;
WL_PV{ // WL报警时的最后过程值
  S7_shortcut := 'WL报警实时值';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :REAL := 0.0;
AL_PV{ // AL报警时的最后过程值
  S7_shortcut := 'AL报警实时值';
  S7_m_c := 'true';
  S7_dynamic := 'true'
} :REAL := 0.0;
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
