Хорошо.
Переименовал ФБ в FREQ_MEASURE_EX.
Кто захочет использовать - добавит его в Util.lib сам.
По ключевым вопросам расхождений нет.
Благодарю за разъяснения и вообще.
Финальные варианты кодов.
Исправленный код ФБ FREQ_MEASURE.
Для использования открыть библиотеку Util.lib, внести исправления в код ФБ FREQ_MEASURE, перекомпилировать библиотеку (F11).
Код:
FUNCTION_BLOCK FREQ_MEASURE
(* FB to measure the frequency of a signal *)
VAR_INPUT
IN:BOOL; (* input signal *)
PERIODS: INT (1..10) :=1; (* out is the average frequency during PERIODS (number of periods) *)
RESET: BOOL; (* reset measurement *)
END_VAR
VAR_OUTPUT
OUT:REAL; (* frequency [Hz]*)
VALID:BOOL; (* FALSE: not yet PERIODS measurements done OR time distance between two rising edges > 3/OUT *)
END_VAR
VAR
OLDIN: BOOL;
INIT: BOOL;
OLDT: TIME;
DIFF: DWORD;
ADIFF: ARRAY[0..9] OF DWORD;
V: INT;
B:INT;
I: INT;
END_VAR
IF RESET THEN
B:=0;
V:=0;
INIT:=FALSE;
VALID:=FALSE;
OUT:=0;
RETURN;
END_IF
IF IN AND NOT OLDIN THEN (*rising edge *)
IF INIT THEN
DIFF := TIME_TO_DWORD(TIME()-OLDT);
IF Diff > 0 THEN
ADIFF[B] := DIFF;
B := (B+1) MOD PERIODS;
V:= MIN(V+1, PERIODS);
IF V=PERIODS THEN
OUT := 0;
FOR I:=0 TO PERIODS-1 DO
OUT := OUT + ADIFF[I];
END_FOR
OUT := 1000.0 * PERIODS / OUT;
VALID:=TRUE;
ELSE
VALID:=FALSE;
END_IF
END_IF
END_IF
INIT := TRUE;
OLDT := TIME();
ELSIF INIT AND VALID AND TIME_TO_DWORD(TIME()-OLDT) > 3000 / OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
OLDIN:=IN;
Код ФБ FREQ_MEASURE_EX с расширенными настройками.
Для использования открыть библиотеку Util.lib, добавить в POU (в папку Signals) новый ФБ FREQ_MEASURE_EX, внести в окно объявления ФБ переменные, внести в окно кода ФБ текст исполняемого кода, перекомпилировать библиотеку (F11).
Код:
(* ===== объявление переменных ФБ =====*)
FUNCTION_BLOCK FREQ_MEASURE_EX
(* FB to measure the frequency of a signal *)
VAR_INPUT
IN:BOOL; (* input signal *)
PERIODS: INT (1..10) :=1; (* out is the average frequency during PERIODS (number of periods) *)
RESET: BOOL; (* reset measurement *)
INTERVAL: TIME := T#0s; (* absolute interval of signal inactivity *)
END_VAR
VAR_OUTPUT
OUT:REAL; (* frequency [Hz]*)
VALID:BOOL; (* FALSE: not yet PERIODS measurements done *)
(* OR time distance between two rising edges > INTERVAL if INTERVAL > 0*)
(* OR time distance between two rising edges > 3s / OUT if INTERVAL = 0*)
END_VAR
VAR
OLDIN: BOOL;
INIT: BOOL;
OLDT: TIME;
DIFF: DWORD;
ADIFF: ARRAY[0..9] OF DWORD;
V: INT;
B:INT;
I: INT;
INACTIVEINTERVAL: DWORD;
END_VAR
(* ===== исполняемый код ФБ =====*)
IF RESET THEN
B:=0;
V:=0;
INIT:=FALSE;
VALID:=FALSE;
OUT:=0;
INACTIVEINTERVAL := TIME_TO_DWORD(INTERVAL);
RETURN;
END_IF
IF IN AND NOT OLDIN THEN (*rising edge *)
IF INIT THEN
DIFF := TIME_TO_DWORD(TIME()-OLDT);
IF Diff > 0 THEN
ADIFF[B] := DIFF;
B := (B+1) MOD PERIODS;
V:= MIN(V+1, PERIODS);
IF V=PERIODS THEN
OUT := 0;
FOR I:=0 TO PERIODS-1 DO
OUT := OUT + ADIFF[I];
END_FOR
OUT := 1000.0 * PERIODS / OUT;
VALID:=TRUE;
ELSE
VALID:=FALSE;
END_IF
END_IF
END_IF
INIT := TRUE;
OLDT := TIME();
ELSIF INIT AND VALID THEN
IF INACTIVEINTERVAL <> 0 THEN
IF TIME_TO_DWORD(TIME()-OLDT) > INACTIVEINTERVAL THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
ELSIF TIME_TO_DWORD(TIME()-OLDT) > 3000 / OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
END_IF
OLDIN:=IN;
Использование ФБ FREQ_MEASURE_EX
Код:
(* объявление глобальных переменных *)
(* дополнительно дискретный вход 1 в Конфигурации ПЛК должен быть именован как InputSignal *)
VAR_GLOBAL
FreqMeasure1 : FREQ_MEASURE_EX;
FreqMeasure2 : FREQ_MEASURE_EX;
Frequency1 : REAL;
Frequency2 : REAL;
Valid1 : BOOL;
Valid2 : BOOL;
INIT : BOOL := FALSE;
END_VAR
(* основная программа *)
PROGRAM PLC_PRG
VAR
END_VAR
(* инициализация *)
IF NOT(INIT) THEN
FreqMeasure1(PERIODS:=3, RESET := TRUE, INTERVAL := T#12s); (* усреднение по 3 периодам, ожидание сигнала не более 12с *)
FreqMeasure2(PERIODS:=3, RESET := TRUE); (* усреднение по 3 периодам, ожидание сигнала 3 последних измеренных периода, как ФБ FREQ_MEASUE *)
INIT := TRUE;
END_IF
(* измерение частоты *)
FreqMeasure1.IN := InputSignal;
Frequency1 := FreqMeasure1.OUT;
Valid1 := FreqMeasure1.VALID;
FreqMeasure2.IN := InputSignal;
Frequency2 := FreqMeasure2.OUT;
Valid2 := FreqMeasure2.VALID;
(* подаем на дискретный вход 1 импульсный сигнал с частотой 1 Гц *)
(* после выхода измерителей на режим Vald1 = Valid2 = TRUE резко уменьшаем частоту до 0.1 Гц*)
(* флаг Valid1 сбросится в FALSE примерно через 3с и восстановится через еще через 7с с новым значением частоты*)
(* флаг Valid2 будет удерживаться 12с и дождется нового значения частоты*)
(* новое значение частоты будет усредненным и выйдет на 0.1Гц примерно через 30с (3 периода) после изменения*)