В проекте необходимо измерить частоту импульсных сигналов на дискретных входах ПЛК.
Частоты 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.
Полез в код ФБ (несущественные фрагменты опущены).
По смыслу флаг VALID должен сбрасываться, когда на входном сигнале нет импульсов в течение 3 последних измеренных периодов.Код: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;
Но OUT - это измеренная ЧАСТОТА, поэтому 3 периода (в миллисекундах) есть 3000/OUT, а не 3000*OUT, как в коде.
Это явный баг. Чем выше частота, тем дольше будет интервал ожидание сигнала, хотя должно быть ровно наоборот.
Причем даже описание флага неверно ни в комментарии ФБ, ни в мануале по Codesys.
Исправленный код (без декларации функции и описания перемененных)
Если IF работает в ST, как в паскале или си (и я не знаю, так ли это), то проверку частоты на 0 можно не выносить в отдельный блок, а сразу написатьКод: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;
Ну и еще. При резком уменьшении частоты даже исправленный ФБ будет работать не очень хорошо: флаг VALID будет сбрасываться, пока не придет новый импульс. Например, частота изменяется скачком с 0.5 Гц (2 с) до 0.1 Гц (10 с) - после 6 с ожидания флаг сбросится и 4 с будет в таком состоянии ждать нового импульса. На высоких частотах лаг, естественно, будет меньше. Так вот, для себя сделал еще одну вещь: завел в ФБ дополнительный параметр - интервал ожидания импульса, не зависящий от частоты. Если я знаю примерный диапазон частот, то задав этот интервал, равный, скажем, 2 или 3 максимальным периодам, получу, что флаг VALID не упадет при резком изменении частоты входного сигнала, а свалится только когда импульса не будет в течении заданного интервала. Если же взять интервал равный нулю, то ФБ будет работать как обычно - по тройному интервалу ожидания, зависящему от частоты. Если нужно, выложу код.Код:IF OUT <> 0 AND TIME_TO_DWORD(TIME()-OLDT) > 3000/OUT THEN VALID:=FALSE; V:=0; B:=0; END_IF
Вообще, прошу проверить все эти выкладки, а то может и накосячил где.![]()




Ответить с цитированием