В проекте необходимо измерить частоту импульсных сигналов на дискретных входах ПЛК.
Частоты 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 не упадет при резком изменении частоты входного сигнала, а свалится только когда импульса не будет в течении заданного интервала. Если же взять интервал равный нулю, то ФБ будет работать как обычно - по тройному интервалу ожидания, зависящему от частоты. Если нужно, выложу код.

Вообще, прошу проверить все эти выкладки, а то может и накосячил где.