Declaration part:
FUNCTION_BLOCK FB_GET_MIN_MAX
VAR CONSTANT
CMAXinit :REAL := -3.402823E+38;
CMINinit :REAL := 3.402823E+38;
END_VAR
VAR_INPUT
bInit :BOOL := TRUE;
nInputValue :REAL;
nMinFreqInput :REAL;
END_VAR
VAR_OUTPUT
bRESULT :BOOL;
nMaxVal :REAL;
nMinVal :REAL;
END_VAR
VAR
CMMcnt :UINT;
nMaxValCnt :UINT;
nMinValCnt :UINT;
bValidMinVal :BOOL;
bValidMaxVal :BOOL;
fbGetCurTaskIdx : GETCURTASKINDEX;
END_VAR
Execution part:
IF bInit THEN
// Counter initialization:
// [counter value] > [1/(<input frequency> * TaskCycleTime)]
fbGetCurTaskIdx();
CMMcnt := REAL_TO_UINT(
1.1E7/(nMinFreqInput*UDINT_TO_REAL(
_TaskInfo[fbGetCurTaskIdx.index].CycleTime)));
// At least an entire period have to be sampled for min/max determination
// Initialization, go on:
nMaxValCnt :=CMMcnt;
nMinValCnt :=CMMcnt;
nMaxVal :=CMAXinit;
nMinVal :=CMINinit;
bInit := FALSE;
END_IF
// Assertions: new min/max values exists:
bValidMaxVal := TRUE;
bValidMinVal := TRUE;
// Filter min/max values
IF (nMaxVal < nInputValue) THEN
bValidMaxVal := FALSE;
nMaxVal := nInputValue; // Max value was found
END_IF
IF (nMinVal > nInputValue) THEN
bValidMinVal := FALSE;
nMinVal := nInputValue; // Min value was found
END_IF
// Count down, if no new value come in:
IF (bValidMaxVal AND (nMaxValCnt > 0)) THEN
nMaxValCnt := nMaxValCnt - 1;
END_IF
// Count down, if no new value come in:
IF (bValidMinVal AND (nMinValCnt > 0)) THEN
nMinValCnt := nMinValCnt - 1;
END_IF
IF ((nMaxValCnt = 0) AND (nMinValCnt = 0)) THEN
// Consequence: min/max determined
bInit := TRUE; // Prepare next call
bRESULT := NOT (nMaxVal = nMinVal); // Sign valid results
ELSE
bRESULT := FALSE; // Sign still invalid results
END_IF