ленивый
09.05.2020, 22:07
В проекте необходимо измерить частоту импульсных сигналов на дискретных входах ПЛК.
Частоты 10-50 Гц (период 20-100 мс) и 0.04-0.5 Гц (2-25 с).
Использовал простой ФБ FREQ_MEASURE (да, в курсе, что есть решения гораздо лучше, но в первом приближении и это устраивало).
Описание ФБ в мануале "Руководство пользователя по программированию ПЛК в Codesys 2.3", Приложение D --> Библиотека UTIL.LIB --> Генераторы сигналов --> FREQ_MEASURE.
Обратил внимание, что выходной флаг VALID, отвечающий за "достоверность" измеренной частоты, для сигнала 10-50 Гц ведет себя примерно так, как описано: при наличии сигнала поднимается после заполнения массива усреднения, а при при исчезновении сигнала - сбрасывается.
А вот для низкочастотных сигналов этот флаг практически всегда сброшен, VALID = FALSE.
Полез в код ФБ (несущественные фрагменты опущены).
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
(* ====== исполняемый код =========*)
IF RESET THEN
(* код инициализации *)
END_IF
IF IN AND NOT OLDIN THEN (*rising edge *)
(* код вычисления усредненной частоты*)
ELSIF INIT AND VALID AND TIME_TO_DWORD(TIME()-OLDT) > 3000*OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
OLDIN:=IN;
По смыслу флаг VALID должен сбрасываться, когда на входном сигнале нет импульсов в течение 3 последних измеренных периодов.
Но OUT - это измеренная ЧАСТОТА, поэтому 3 периода (в миллисекундах) есть 3000/OUT, а не 3000*OUT, как в коде.
Это явный баг. Чем выше частота, тем дольше будет интервал ожидание сигнала, хотя должно быть ровно наоборот.
Причем даже описание флага неверно ни в комментарии ФБ, ни в мануале по Codesys.
Исправленный код (без декларации функции и описания перемененных)
IF RESET THEN
(* код инициализации *)
END_IF
IF IN AND NOT OLDIN THEN (*rising edge *)
(* код вычисления усредненной частоты*)
ELSIF INIT AND VALID THEN
IF OUT <> 0 THEN
IF TIME_TO_DWORD(TIME()-OLDT) > 3000/OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
END_IF
END_IF
OLDIN:=IN;
Если IF работает в ST, как в паскале или си (и я не знаю, так ли это), то проверку частоты на 0 можно не выносить в отдельный блок, а сразу написать
IF OUT <> 0 AND TIME_TO_DWORD(TIME()-OLDT) > 3000/OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
Ну и еще. При резком уменьшении частоты даже исправленный ФБ будет работать не очень хорошо: флаг VALID будет сбрасываться, пока не придет новый импульс. Например, частота изменяется скачком с 0.5 Гц (2 с) до 0.1 Гц (10 с) - после 6 с ожидания флаг сбросится и 4 с будет в таком состоянии ждать нового импульса. На высоких частотах лаг, естественно, будет меньше. Так вот, для себя сделал еще одну вещь: завел в ФБ дополнительный параметр - интервал ожидания импульса, не зависящий от частоты. Если я знаю примерный диапазон частот, то задав этот интервал, равный, скажем, 2 или 3 максимальным периодам, получу, что флаг VALID не упадет при резком изменении частоты входного сигнала, а свалится только когда импульса не будет в течении заданного интервала. Если же взять интервал равный нулю, то ФБ будет работать как обычно - по тройному интервалу ожидания, зависящему от частоты. Если нужно, выложу код.
Вообще, прошу проверить все эти выкладки, а то может и накосячил где. :confused:
Частоты 10-50 Гц (период 20-100 мс) и 0.04-0.5 Гц (2-25 с).
Использовал простой ФБ FREQ_MEASURE (да, в курсе, что есть решения гораздо лучше, но в первом приближении и это устраивало).
Описание ФБ в мануале "Руководство пользователя по программированию ПЛК в Codesys 2.3", Приложение D --> Библиотека UTIL.LIB --> Генераторы сигналов --> FREQ_MEASURE.
Обратил внимание, что выходной флаг VALID, отвечающий за "достоверность" измеренной частоты, для сигнала 10-50 Гц ведет себя примерно так, как описано: при наличии сигнала поднимается после заполнения массива усреднения, а при при исчезновении сигнала - сбрасывается.
А вот для низкочастотных сигналов этот флаг практически всегда сброшен, VALID = FALSE.
Полез в код ФБ (несущественные фрагменты опущены).
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
(* ====== исполняемый код =========*)
IF RESET THEN
(* код инициализации *)
END_IF
IF IN AND NOT OLDIN THEN (*rising edge *)
(* код вычисления усредненной частоты*)
ELSIF INIT AND VALID AND TIME_TO_DWORD(TIME()-OLDT) > 3000*OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
OLDIN:=IN;
По смыслу флаг VALID должен сбрасываться, когда на входном сигнале нет импульсов в течение 3 последних измеренных периодов.
Но OUT - это измеренная ЧАСТОТА, поэтому 3 периода (в миллисекундах) есть 3000/OUT, а не 3000*OUT, как в коде.
Это явный баг. Чем выше частота, тем дольше будет интервал ожидание сигнала, хотя должно быть ровно наоборот.
Причем даже описание флага неверно ни в комментарии ФБ, ни в мануале по Codesys.
Исправленный код (без декларации функции и описания перемененных)
IF RESET THEN
(* код инициализации *)
END_IF
IF IN AND NOT OLDIN THEN (*rising edge *)
(* код вычисления усредненной частоты*)
ELSIF INIT AND VALID THEN
IF OUT <> 0 THEN
IF TIME_TO_DWORD(TIME()-OLDT) > 3000/OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
END_IF
END_IF
OLDIN:=IN;
Если IF работает в ST, как в паскале или си (и я не знаю, так ли это), то проверку частоты на 0 можно не выносить в отдельный блок, а сразу написать
IF OUT <> 0 AND TIME_TO_DWORD(TIME()-OLDT) > 3000/OUT THEN
VALID:=FALSE;
V:=0;
B:=0;
END_IF
Ну и еще. При резком уменьшении частоты даже исправленный ФБ будет работать не очень хорошо: флаг VALID будет сбрасываться, пока не придет новый импульс. Например, частота изменяется скачком с 0.5 Гц (2 с) до 0.1 Гц (10 с) - после 6 с ожидания флаг сбросится и 4 с будет в таком состоянии ждать нового импульса. На высоких частотах лаг, естественно, будет меньше. Так вот, для себя сделал еще одну вещь: завел в ФБ дополнительный параметр - интервал ожидания импульса, не зависящий от частоты. Если я знаю примерный диапазон частот, то задав этот интервал, равный, скажем, 2 или 3 максимальным периодам, получу, что флаг VALID не упадет при резком изменении частоты входного сигнала, а свалится только когда импульса не будет в течении заданного интервала. Если же взять интервал равный нулю, то ФБ будет работать как обычно - по тройному интервалу ожидания, зависящему от частоты. Если нужно, выложу код.
Вообще, прошу проверить все эти выкладки, а то может и накосячил где. :confused: