PDA

Просмотр полной версии : ФБ сохранения показаний на ST с энергонезависимостью.



Григори
27.12.2023, 16:42
Всем доброго времени суток, разрабатываю блок для подсчета показаний
с импульсного счетчика на ST. Общие показания сохраняются спокойно и после отключения питания остаются,
но временные показания (сутки, час, месяц, год) слетают после отключения питания.
С чем может быть связан сброс? Программу прилагаю.
Прибор: ПР200-24.2.2.0

З.Ы.: смею высказать свою теорию, что из-за несовпадения даты с сохраненной в локальные переменные блока при повторной подаче питания.

kondor3000
27.12.2023, 17:26
Всем доброго времени суток, разрабатываю блок для подсчета показаний
с импульсного счетчика на ST. Общие показания сохраняются спокойно и после отключения питания остаются,
но временные показания (сутки, час, месяц, год) слетают после отключения питания.
С чем может быть связан сброс? Программу прилагаю.
Прибор: ПР200-24.2.2.0

З.Ы.: смею высказать свою теорию, что из-за несовпадения даты с сохраненной в локальные переменные блока при повторной подаче питания.

Вы же сами всё обнуляете, например кусок кода

if i_nowDay <> l_day then
l_FlowDay := 0; // Зачем здесь обнуление?
l_day := i_nowDay;
end_if

Сначала присваиваете l_FlowDay := i_FlowDay; а потом в коде обнуляете l_FlowDay := 0; // Зачем здесь обнуление? И так везде

Григори
27.12.2023, 19:40
kondor3000, Это сравнение числа дня входной переменной с локальной, если не совпадает(по логике происходит на след. день в 00:00), l_FlowDay - переменная с данными по самому потоку (Поток день, дословно) становится равна нулю и считается заново. Аналогичные операции проделываются с годом, часом и месяцем

Григори
27.12.2023, 19:48
Вы же сами всё обнуляете, например кусок кода

if i_nowDay <> l_day then
l_FlowDay := 0; // Зачем здесь обнуление?
l_day := i_nowDay;
end_if

Сначала присваиваете l_FlowDay := i_FlowDay; а потом в коде обнуляете l_FlowDay := 0; // Зачем здесь обнуление? И так везде


Кусок кода с вычислениями расходов:


if i_Imp = TRUE then
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
end_if


Кусок кода со сравнениями переменных дат и времени для сброса когда надо:


if i_nowDay <> l_day then
l_FlowDay := 0;
l_day := i_nowDay;
end_if

if i_nowHour <> l_hour then
l_FlowHour := 0;
l_hour := i_nowHour;
end_if

if i_nowMonth <> l_month then
l_FlowMonth := 0;
l_month := i_nowMonth;
end_if

if i_nowYear <> l_year then
l_FlowYear := 0;
l_year := i_nowYear;
end_if


И каждый цикл программы в сравнениях(и просто в коде) происходит перезапись локальных переменных (которые, как я слышал, энергонезависимые).


l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass:= i_ImpMass;


В таблице переменных все с галочкой на энергонезависимость, но оно все равно сбрасывается

P.S.: все переменные с i_ - входные, l_ - локальные, а выходные без префикса. Но да, комментариев в коде я оставил мало

kondor3000
28.12.2023, 08:36
Просто закомментируйте на время кусок кода с обнулением и проверьте, будут ли сохраняться расходы, при перезагрузке по питанию.
Возможно надо ввести таймер на несколько секунд, чтобы не обнулялось при подаче питания.

Григори
28.12.2023, 09:11
Просто закомментируйте на время кусок кода с обнулением и проверьте, будут ли сохраняться расходы, при перезагрузке по питанию.
Возможно надо ввести таймер на несколько секунд, чтобы не обнулялось при подаче питания.
Да, вы правы, если исключить из условия обнуление, он не сбрасывается при перезапуске питания. Как понимаю, задержку на включение действий условия на ST тоже надо сделать.
TON из оф. видео подойдет же?
https://www.youtube.com/watch?v=agJTfeRnfy4

AlexCrane
28.12.2023, 09:42
Да, вы правы, если исключить из условия обнуление, он не сбрасывается при перезапуске питания. Как понимаю, задержку на включение действий условия на ST тоже надо сделать.
TON из оф. видео подойдет же?
https://www.youtube.com/watch?v=agJTfeRnfy4

Может проще выполнение всего блока отложить на один цикл после включения питания

Григори
28.12.2023, 09:53
Может проще выполнение всего блока отложить на один цикл после включения питания
Не совсем понимаю, как это реализовать. Поставить линии задержки на все выходные переменные?

Dimensy
28.12.2023, 09:59
Не совсем понимаю, как это реализовать. Поставить линии задержки на все выходные переменные?

Еще один вход сделать - разрешение работы

Григори
28.12.2023, 10:00
Просто закомментируйте на время кусок кода с обнулением и проверьте, будут ли сохраняться расходы, при перезагрузке по питанию.
Возможно надо ввести таймер на несколько секунд, чтобы не обнулялось при подаче питания.

Переписал ТОН из оф. ролика. Переменная теперь просто сбрасывается с задержкой таймера после включения.
Делал условие для выключения таймера, тоже не помогает



function_block Flowmeter //имя функционального блока.

var_input //объявление входных переменных
i_Imp: bool; //переменная считывания переднего фронта импульса
i_ImpMass: real; //переменна цены импульса
i_Flow: real; //Общий поток
i_FlowYear: real; //Годовой поток
i_FlowMonth: real; //Поток за месяц
i_FlowDay: real; //Поток за день
i_FlowHour: real; //Поток за час

i_nowYear: udint; //Текущий год
i_nowMonth: udint; //Текущий месяц
i_nowDay: udint; //Текущий день
i_nowHour: udint; //Текущий час
i_nowMinute: udint; //Текущая минута
i_nowSecond: udint; //Текущая секунда
end_var

var_output //объявление выходных переменных
Flow: real;
FlowDay: real;
FlowHour: real;
FlowMonth: real;
FlowYear: real;
ImpMass: real;
end_var

var //объявление локальных переменных
TON: TON_FB;
TON_Q: BOOL;
l_Flow: real;
l_FlowDay: real;
l_FlowHour: real;
l_FlowMonth: real;
l_FlowYear: real;
l_year: udint;
l_month: udint;
l_day: udint;
l_hour: udint;
l_minute: udint;
l_second: udint;
l_impMass: real;
end_var



l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass:= i_ImpMass;


if i_Imp = TRUE then
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
end_if


//Тут на поток за день сделал попытку с таймером
if i_nowDay <> l_day then
TON(IN := true, PT:= 5,SEC := i_nowSecond, Q => TON_Q);
if TON_Q then
l_day := i_nowDay;
l_FlowDay := 0;
end_if
else
TON(IN := false);
end_if

if i_nowHour <> l_hour then
l_hour := i_nowHour;
//l_FlowHour := 0;
end_if

if i_nowMonth <> l_month then
l_month := i_nowMonth;
//l_FlowMonth := 0;
end_if

if i_nowYear <> l_year then
l_year := i_nowYear;
//l_FlowYear := 0;
end_if

ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;

end_function_block

AlexCrane
28.12.2023, 10:01
Не совсем понимаю, как это реализовать. Поставить линии задержки на все выходные переменные?

Примерно так, но это не точно...

Григори
28.12.2023, 10:01
Еще один вход сделать - разрешение работы

И завести на него 1 с линией задержки, верно?

AlexCrane
28.12.2023, 10:06
И завести на него 1 с линией задержки, верно?

Нужно проверить хватит ли одного цикла

МихаилГл
28.12.2023, 10:10
Таймер (in:= not (стартовый не энергонезависимый бит), pt:= T#5s)
if Таймер.Q then
стартовать программу;
стартовый не энергонезависимый бит:= 1;
end_if

Григори
28.12.2023, 10:14
Нужно проверить хватит ли одного цикла

Поставил и сделал в блоке:
IF разрешение работать = 1
(Основной код фб)
END_IF

После перезапуска он вообще стопится, даже цена импульса из энергонезависимости не подгружается

Григори
28.12.2023, 10:34
Таймер (in:= not (стартовый не энергонезависимый бит), pt:= T#5s)
if Таймер.Q then
стартовать программу;
стартовый не энергонезависимый бит:= 1;
end_if

Сделал, отвалилась запись входных переменных (цены импульса)



FUNCTION_BLOCK Flowmeter // имя функционального блока.

VAR_INPUT // объявление входных переменных
i_Work: BOOL; // разрешение на работу
i_Imp: BOOL; // переменная считывания переднего фронта импульса
i_ImpMass: REAL; // переменна цены импульса
i_Flow: REAL; // Общий поток
i_FlowYear: REAL; // Годовой поток
i_FlowMonth: REAL; // Поток за месяц
i_FlowDay: REAL; // Поток за день
i_FlowHour: REAL; // Поток за час

i_nowYear: UDINT; // Текущий год
i_nowMonth: UDINT; // Текущий месяц
i_nowDay: UDINT; // Текущий день
i_nowHour: UDINT; // Текущий час
i_nowMinute: UDINT; // Текущая минута
i_nowSecond: UDINT; // Текущая секунда
END_VAR

VAR_OUTPUT // объявление выходных переменных
Flow: REAL;
FlowDay: REAL;
FlowHour: REAL;
FlowMonth: REAL;
FlowYear: REAL;
ImpMass: REAL;
Work: BOOL;
END_VAR

VAR // объявление локальных переменных
TON: TON_FB;
TON_Q: BOOL;
l_Flow: REAL;
l_FlowDay: REAL;
l_FlowHour: REAL;
l_FlowMonth: REAL;
l_FlowYear: REAL;
l_year: UDINT;
l_month: UDINT;
l_day: UDINT;
l_hour: UDINT;
l_minute: UDINT;
l_second: UDINT;
l_impMass: REAL;
END_VAR


TON(IN := NOT(i_Work), PT := 5, Q => TON_Q);

IF TON_Q THEN

l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass := 100;

IF i_Imp = TRUE THEN
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
END_IF

IF i_nowDay <> l_day THEN
l_day := i_nowDay;
l_FlowDay := 0;
END_IF

IF i_nowHour <> l_hour THEN
l_hour := i_nowHour;
// l_FlowHour := 0;
END_IF

IF i_nowMonth <> l_month THEN
l_month := i_nowMonth;
// l_FlowMonth := 0;
END_IF

IF i_nowYear <> l_year THEN
l_year := i_nowYear;
// l_FlowYear := 0;
END_IF

ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;

Work := true;
END_IF


END_FUNCTION_BLOCK


Код с записями переменных делал и внутри условия и вне, без изменений.

Григори
28.12.2023, 10:40
Как считаете, будет ли работать, если начать сравнение с конкретными числами:
например:
ЕСЛИ час = 00 И минута = 00 и СЕКУНДА = 00
поток день = 0
КОНЕЦ ЕСЛИ

P.S.: Так действительно значение сохраняется

Только вот, боюсь, с показаниями за месяц это работать не будет, ибо у нас бывает 28, 29, 30, 31 день в месяце. Ну и 365-366 дней в году)

МихаилГл
28.12.2023, 10:41
Почему:

Work := true;
i_Work

Вы не выходите из этого if при таком условии...

И


l_FlowDay := 0; не закомментировали... Внимательнее...

Григори
28.12.2023, 10:46
Почему:

Work := true;
i_Work

Вы не выходите из этого if при таком условии...

к i_Work и Work привязана одна и та же переменная, просто i_Work - входная, Work - выходная

Или будет лучше сделать локальную переменную, которая принимается от входной и записывает выходную?

Григори
28.12.2023, 10:49
l_FlowDay := 0; не закомментировали... Внимательнее...

Так я и пишу ФБ, чтобы сделать потоки за определенное кол-во времени, если не обнулять - будет просто общий поток(а он работает нормально)

Суть такая:

Программа считает целый день воду и, как только наступают след. сутки, она сбрасывает показания в 0 и считает заново (суточный/месячный/годовой расход).
Если в сутках у нас только 24, то сделать самое просто сравнение времени с нулями еще можно. Но вот с месяцами и годами так не выйдет, ибо всегда разное, поэтому просто каждый цикл смотрим и сравниваем текущие входные числа с локальными, если не равно, то перезаписать локальную и сбросить счетчик

МихаилГл
28.12.2023, 10:52
к i_Work и Work привязана одна и та же переменная, просто i_Work - входная, Work - выходная

Или будет лучше сделать локальную переменную, которая принимается от входной и записывает выходную?

Локальная энергоЗАВИСИМАЯ... А так вы не выходите из условия и обнуляете все... А если будет одна, то код выполнится один раз по истечении 5 секунд и все, и снова только после перезагрузки...

Не две, а ОДНА...

PS ошибся с энергозависимостью... Вы меня запутали совсем

Григори
28.12.2023, 10:58
Локальная энергоЗАВИСИМАЯ... А так вы не выходите из условия и обнуляете все... А если будет одна, то код выполнится один раз по истечении 5 секунд и все, и снова только после перезагрузки...

Не две, а ОДНА...

PS ошибся с энергозависимостью... Вы меня запутали совсем

Поменял все ворки эти, результата все равно не дает, не дает программе стартовать

Честно говоря, я вообще не понимаю причины сброса после отвала питания. Если идет сравнение годов, то он в любом случае не поменялся(по логике).
А так ощущение, что часы очень сильно подтупливают и сначала дают какую-нибудь дату 00.00.00 00:00

МихаилГл
28.12.2023, 11:00
Скиньте последний код... Гляну. Я уже совсем запутался чего вы хотите...

Григори
28.12.2023, 11:05
Скиньте последний код... Гляну. Я уже совсем запутался чего вы хотите...



FUNCTION_BLOCK Flowmeter // имя функционального блока.

VAR_INPUT // объявление входных переменных
i_Work: BOOL; // разрешение на работу
i_Imp: BOOL; // переменная считывания переднего фронта импульса
i_ImpMass: REAL; // переменна цены импульса
i_Flow: REAL; // Общий поток
i_FlowYear: REAL; // Годовой поток
i_FlowMonth: REAL; // Поток за месяц
i_FlowDay: REAL; // Поток за день
i_FlowHour: REAL; // Поток за час

i_nowYear: UDINT; // Текущий год
i_nowMonth: UDINT; // Текущий месяц
i_nowDay: UDINT; // Текущий день
i_nowHour: UDINT; // Текущий час
i_nowMinute: UDINT; // Текущая минута
i_nowSecond: UDINT; // Текущая секунда
END_VAR

VAR_OUTPUT // объявление выходных переменных
Flow: REAL;
FlowDay: REAL;
FlowHour: REAL;
FlowMonth: REAL;
FlowYear: REAL;
ImpMass: REAL;
Work: BOOL;
END_VAR

VAR // объявление локальных переменных
TON: TON_FB;
TON_Q: BOOL;
l_Flow: REAL;
l_FlowDay: REAL;
l_FlowHour: REAL;
l_FlowMonth: REAL;
l_FlowYear: REAL;
l_year: UDINT;
l_month: UDINT;
l_day: UDINT;
l_hour: UDINT;
l_minute: UDINT;
l_second: UDINT;
l_impMass: REAL;
END_VAR


TON(IN := NOT(i_Work), PT := 5, Q => TON_Q);

IF TON_Q THEN
//запись входных переменных в локальные
l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass := 100;

//блок вычисления показаний воды
IF i_Imp = TRUE THEN
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
END_IF

//сравнение дня показаний за день. Сравнение <> не работает, сравнение с нулями работает
IF i_nowHour = 00 AND i_nowMinute = 00 AND i_nowSecond = 00 THEN
l_day := i_nowDay;
l_FlowDay := 0;
END_IF

//Часовые показания
IF i_nowHour <> l_hour THEN
l_hour := i_nowHour;
l_FlowHour := 0;
END_IF

//месячные показания
IF i_nowMonth <> l_month THEN
l_month := i_nowMonth;
l_FlowMonth := 0;
END_IF

//годовые показания
IF i_nowYear <> l_year THEN
l_year := i_nowYear;
l_FlowYear := 0;
END_IF

//запись из локальных переменных в выходные
ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;

i_Work := true;
END_IF


END_FUNCTION_BLOCK

МихаилГл
28.12.2023, 11:07
Таймер (in:= not (стартовый не энергонезависимый бит), pt:= T#5s)
if Таймер.Q then
стартовать программу;
стартовый не энергонезависимый бит:= 1;
end_if


Поменял все ворки эти, результата все равно не дает, не дает программе стартовать

Честно говоря, я вообще не понимаю причины сброса после отвала питания. Если идет сравнение годов, то он в любом случае не поменялся(по логике).
А так ощущение, что часы очень сильно подтупливают и сначала дают какую-нибудь дату 00.00.00 00:00

Я вот это предлагал вообще в начале запуска программы поставить. Т.е. программа не считает вообще, пока плк не проработает 5 секунд. А там можно на ст не ФБ писать, а не основную программу?

Короче, нужен исходник...

МихаилГл
28.12.2023, 11:07
А как вы в этот код заходите я сам придумать должен? У вас ошибка до...

Григори
28.12.2023, 11:10
Я вот это предлагал вообще в начале запуска программы поставить. Т.е. программа не считает вообще, пока плк не проработает 5 секунд. А там можно на ст не ФБ писать, а не основную программу?

Короче, нужен исходник...

Исходник прилагаю.
Просто на вход разрешения работы ФБ кинуть таймер на пять секунд?

Григори
28.12.2023, 11:12
А как вы в этот код заходите я сам придумать должен? У вас ошибка до...

Честно говоря, ничего не понял. Может вы про Codesys ST говорите?
Но вот проект с ФБ

МихаилГл
28.12.2023, 11:43
Честно говоря, ничего не понял. Может вы про Codesys ST говорите?
Но вот проект с ФБ

Вот как сделать задержку на запуск подсчетов при первом запуске...

Дальше сами... Но если я пойму что вы хотите дальше, может продолжим... Наверное после НГ)

С i_Work и Work вы правы, я просто с ФБ редко связываюсь.

Григори
28.12.2023, 12:00
Вот как сделать задержку на запуск подсчетов при первом запуске...

Дальше сами... Но если я пойму что вы хотите дальше, может продолжим... Наверное после НГ)

С i_Work и Work вы правы, я просто с ФБ редко связываюсь.

Почему-то при задержке ФБ перестает считать, хотя все срабатывает (смотрю по цене импульса).
Пока сделал с тупым сравнением на равенство дат и времени (но если ПРку рубанет в эти нужные моменты, боюсь, она не сбросит показания).
Попробую еще связаться с этой проблемой к ОВЕНовцам, может они что-то подскажут)

Если получится вывести идеальный вариант ФБ, отпишусь в теме

МихаилГл
28.12.2023, 12:03
Почему-то при задержке ФБ перестает считать, хотя все срабатывает (смотрю по цене импульса).
Пока сделал с тупым сравнением на равенство дат и времени (но если ПРку рубанет в эти нужные моменты, боюсь, она не сбросит показания).
Попробую еще связаться с этой проблемой к ОВЕНовцам, может они что-то подскажут)

Если получится вывести идеальный вариант ФБ, отпишусь в теме

Потому что у вас похоже используются переменные из этого ФБ в основном коде (не смотрел внимательно), а он (ФБ) начнет работать только после 5 секунд после подачи питания.

Dimensy
28.12.2023, 12:25
FUNCTION_BLOCK Flowmeter // имя функционального блока.

VAR_INPUT // объявление входных переменных
i_Work: BOOL; // разрешение на работу
i_Imp: BOOL; // переменная считывания переднего фронта импульса
i_ImpMass: REAL; // переменна цены импульса
i_Flow: REAL; // Общий поток
i_FlowYear: REAL; // Годовой поток
i_FlowMonth: REAL; // Поток за месяц
i_FlowDay: REAL; // Поток за день
i_FlowHour: REAL; // Поток за час

i_nowYear: UDINT; // Текущий год
i_nowMonth: UDINT; // Текущий месяц
i_nowDay: UDINT; // Текущий день
i_nowHour: UDINT; // Текущий час
i_nowMinute: UDINT; // Текущая минута
i_nowSecond: UDINT; // Текущая секунда
END_VAR

VAR_OUTPUT // объявление выходных переменных
Flow: REAL;
FlowDay: REAL;
FlowHour: REAL;
FlowMonth: REAL;
FlowYear: REAL;
ImpMass: REAL;
Work: BOOL;
END_VAR

VAR // объявление локальных переменных
TON: TON_FB;
TON_Q: BOOL;
l_Flow: REAL;
l_FlowDay: REAL;
l_FlowHour: REAL;
l_FlowMonth: REAL;
l_FlowYear: REAL;
l_year: UDINT;
l_month: UDINT;
l_day: UDINT;
l_hour: UDINT;
l_minute: UDINT;
l_second: UDINT;
l_impMass: REAL;
END_VAR


TON(IN := NOT(i_Work), PT := 5, Q => TON_Q);

IF TON_Q THEN
//запись входных переменных в локальные
l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass := 100;

//блок вычисления показаний воды
IF i_Imp = TRUE THEN
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
END_IF

//сравнение дня показаний за день. Сравнение <> не работает, сравнение с нулями работает
IF i_nowHour = 00 AND i_nowMinute = 00 AND i_nowSecond = 00 THEN
l_day := i_nowDay;
l_FlowDay := 0;
END_IF

//Часовые показания
IF i_nowHour <> l_hour THEN
l_hour := i_nowHour;
l_FlowHour := 0;
END_IF

//месячные показания
IF i_nowMonth <> l_month THEN
l_month := i_nowMonth;
l_FlowMonth := 0;
END_IF

//годовые показания
IF i_nowYear <> l_year THEN
l_year := i_nowYear;
l_FlowYear := 0;
END_IF

//запись из локальных переменных в выходные
ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;

i_Work := true;
END_IF


END_FUNCTION_BLOCK


Вы запись входных и выходных переменных выведите из под условия разрешения работы - они должны всегда выполняться
Но это не поможет - у вас локальное время не сохраняется, поэтому после перезагрузки все и сбрасывается. Поэтому как-то так


Чтение входных данных
if РАЗРЕШИТЬ then
здесь считаем
else
запись текущего времени в локальные переменные
end_if
Запись выходных данных

Григори
28.12.2023, 12:37
Вы запись входных и выходных переменных выведите из под условия разрешения работы - они должны всегда выполняться
Но это не поможет - у вас локальное время не сохраняется, поэтому после перезагрузки все и сбрасывается. Поэтому как-то так


Чтение входных данных
if РАЗРЕШИТЬ then
здесь считаем
else
запись текущего времени в локальные переменные
end_if
Запись выходных данных


Тоже делал, и сейчас еще раз перепроверил, не работает

AlexCrane
28.12.2023, 13:54
Переменные l_hour, l_month и др. на выход блока и через энергонезависимую переменную обратно на входы, видимо только так

Dimensy
28.12.2023, 14:18
Тоже делал, и сейчас еще раз перепроверил, не работает

Вот, проверил, не сбрасывает


function_block Flowmeter //имя функционального блока.

var_input //объявление входных переменных
bEn: bool;
i_Imp: bool; //переменная считывания переднего фронта импульса
i_ImpMass: real; //переменна цены импульса
i_Flow: real; //Общий поток
i_FlowYear: real; //Годовой поток
i_FlowMonth: real; //Поток за месяц
i_FlowDay: real; //Поток за день
i_FlowHour: real; //Поток за час

i_nowYear: udint; //Текущий год
i_nowMonth: udint; //Текущий месяц
i_nowDay: udint; //Текущий день
i_nowHour: udint; //Текущий час
i_nowMinute: udint; //Текущая минута
i_nowSecond: udint; //Текущая секунда
end_var

var_output //объявление выходных переменных
Flow: real;
FlowDay: real;
FlowHour: real;
FlowMonth: real;
FlowYear: real;
ImpMass: real;
end_var

var //объявление локальных переменных
l_Flow: real;
l_FlowDay: real;
l_FlowHour: real;
l_FlowMonth: real;
l_FlowYear: real;
l_year: udint;
l_month: udint;
l_day: udint;
l_hour: udint;
l_minute: udint;
l_second: udint;
l_impMass: real;
end_var

l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass:= i_ImpMass;

if bEn then

if i_Imp = TRUE then
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
end_if

if i_nowDay <> l_day then
l_FlowDay := 0;
l_day := i_nowDay;
end_if

if i_nowHour <> l_hour then
l_FlowHour := 0;
l_hour := i_nowHour;
end_if

if i_nowMonth <> l_month then
l_FlowMonth := 0;
l_month := i_nowMonth;
end_if

if i_nowYear <> l_year then
l_FlowYear := 0;
l_year := i_nowYear;
end_if
else
l_year := i_nowYear;
l_month := i_nowMonth;
l_day := i_nowDay;
l_hour := i_nowHour;
end_if

ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;

end_function_block


72684

Но, есть нюанс - если перерыв питания придется на стык часа, дня и т.д., то не сбросится.
Здесь надо по другому делать

Григори
28.12.2023, 14:44
Вот, проверил, не сбрасывает


function_block Flowmeter //имя функционального блока.

var_input //объявление входных переменных
bEn: bool;
i_Imp: bool; //переменная считывания переднего фронта импульса
i_ImpMass: real; //переменна цены импульса
i_Flow: real; //Общий поток
i_FlowYear: real; //Годовой поток
i_FlowMonth: real; //Поток за месяц
i_FlowDay: real; //Поток за день
i_FlowHour: real; //Поток за час

i_nowYear: udint; //Текущий год
i_nowMonth: udint; //Текущий месяц
i_nowDay: udint; //Текущий день
i_nowHour: udint; //Текущий час
i_nowMinute: udint; //Текущая минута
i_nowSecond: udint; //Текущая секунда
end_var

var_output //объявление выходных переменных
Flow: real;
FlowDay: real;
FlowHour: real;
FlowMonth: real;
FlowYear: real;
ImpMass: real;
end_var

var //объявление локальных переменных
l_Flow: real;
l_FlowDay: real;
l_FlowHour: real;
l_FlowMonth: real;
l_FlowYear: real;
l_year: udint;
l_month: udint;
l_day: udint;
l_hour: udint;
l_minute: udint;
l_second: udint;
l_impMass: real;
end_var

l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass:= i_ImpMass;

if bEn then

if i_Imp = TRUE then
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
end_if

if i_nowDay <> l_day then
l_FlowDay := 0;
l_day := i_nowDay;
end_if

if i_nowHour <> l_hour then
l_FlowHour := 0;
l_hour := i_nowHour;
end_if

if i_nowMonth <> l_month then
l_FlowMonth := 0;
l_month := i_nowMonth;
end_if

if i_nowYear <> l_year then
l_FlowYear := 0;
l_year := i_nowYear;
end_if
else
l_year := i_nowYear;
l_month := i_nowMonth;
l_day := i_nowDay;
l_hour := i_nowHour;
end_if

ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;

end_function_block


72684

Но, есть нюанс - если перерыв питания придется на стык часа, дня и т.д., то не сбросится.
Здесь надо по другому делать

Вероятность просадки по питанию в стыки крайне мала, как мне кажется, но не равна нулю, к сожалению. Спасибо большое за предложенное решение :)
А по-другому, это как? Вернее, с какого ракурса смотреть на решение задачи?

kondor3000
28.12.2023, 14:55
Короче прошлое время всегда равно 0, поэтому всё будет сбрасываться. Сделал инициализацию времени при включении. Всё стало работать.

Григори
28.12.2023, 15:01
Короче прошлое время всегда равно 0, поэтому всё будет сбрасываться. Сделал инициализацию времени при включении. Всё стало работать.
Спасибо большое за решение, что-то совсем запутался с этой энергонезависимостью того-сего, не подумал насчет инициализации

МихаилГл
28.12.2023, 15:24
Спасибо большое за решение, что-то совсем запутался с этой энергонезависимостью того-сего, не подумал насчет инициализации

Двоишник)...

Григори
28.12.2023, 15:46
Двоишник)...
Не двоечник, а веб-разработчик :D
Где вообще можно посмотреть, какие переменные в каких соусах энергонезависимые?
Руководство по OL штудировать?

Dimensy
28.12.2023, 15:48
Вероятность просадки по питанию в стыки крайне мала, как мне кажется, но не равна нулю, к сожалению. Спасибо большое за предложенное решение :)
А по-другому, это как? Вернее, с какого ракурса смотреть на решение задачи?

Ну, вот так можно



function_block Flowmeter //имя функционального блока.

var_input //объявление входных переменных
i_Imp: bool; //переменная считывания переднего фронта импульса
i_ImpMass: real; //переменна цены импульса
i_Flow: real; //Общий поток
i_FlowYear: real; //Годовой поток
i_FlowMonth: real; //Поток за месяц
i_FlowDay: real; //Поток за день
i_FlowHour: real; //Поток за час

i_nowYear: udint; //Текущий год
i_nowMonth: udint; //Текущий месяц
i_nowDay: udint; //Текущий день
i_nowHour: udint; //Текущий час
i_nowMinute: udint; //Текущая минута
i_nowSecond: udint; //Текущая секунда
in_Time: udint;
end_var

var_output //объявление выходных переменных
Flow: real;
FlowDay: real;
FlowHour: real;
FlowMonth: real;
FlowYear: real;
ImpMass: real;
out_Time: udint;
end_var

var //объявление локальных переменных
l_Flow: real;
l_FlowDay: real;
l_FlowHour: real;
l_FlowMonth: real;
l_FlowYear: real;
l_year: udint;
l_month: udint;
l_day: udint;
l_hour: udint;
l_minute: udint;
l_second: udint;
l_impMass: real;
end_var

l_year := in_Time mod 100;
l_month := (in_Time / 100) mod 100;
l_day := (in_Time / 10000) mod 100;
l_hour := in_Time / 1000000;

l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass:= i_ImpMass;

if i_Imp then
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
end_if

if i_nowDay <> l_day then
l_FlowDay := 0;
end_if

if i_nowHour <> l_hour then
l_FlowHour := 0;
end_if

if i_nowMonth <> l_month then
l_FlowMonth := 0;
end_if

if i_nowYear <> l_year then
l_FlowYear := 0;
end_if

ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;
out_Time := i_nowHour * 1000000 + i_nowDay * 10000 + i_nowMonth * 100 + i_nowYear;

end_function_block

Григори
28.12.2023, 15:58
Ну, вот так можно



function_block Flowmeter //имя функционального блока.

var_input //объявление входных переменных
i_Imp: bool; //переменная считывания переднего фронта импульса
i_ImpMass: real; //переменна цены импульса
i_Flow: real; //Общий поток
i_FlowYear: real; //Годовой поток
i_FlowMonth: real; //Поток за месяц
i_FlowDay: real; //Поток за день
i_FlowHour: real; //Поток за час

i_nowYear: udint; //Текущий год
i_nowMonth: udint; //Текущий месяц
i_nowDay: udint; //Текущий день
i_nowHour: udint; //Текущий час
i_nowMinute: udint; //Текущая минута
i_nowSecond: udint; //Текущая секунда
in_Time: udint;
end_var

var_output //объявление выходных переменных
Flow: real;
FlowDay: real;
FlowHour: real;
FlowMonth: real;
FlowYear: real;
ImpMass: real;
out_Time: udint;
end_var

var //объявление локальных переменных
l_Flow: real;
l_FlowDay: real;
l_FlowHour: real;
l_FlowMonth: real;
l_FlowYear: real;
l_year: udint;
l_month: udint;
l_day: udint;
l_hour: udint;
l_minute: udint;
l_second: udint;
l_impMass: real;
end_var

l_year := in_Time mod 100;
l_month := (in_Time / 100) mod 100;
l_day := (in_Time / 10000) mod 100;
l_hour := in_Time / 1000000;

l_Flow := i_Flow;
l_FlowYear := i_FlowYear;
l_FlowMonth := i_FlowMonth;
l_FlowDay := i_FlowDay;
l_FlowHour := i_FlowHour;
l_impMass:= i_ImpMass;

if i_Imp then
l_flow := l_Flow + ((1 / 1000) * i_ImpMass);
l_FlowDay := l_FlowDay + ((1 / 1000) * i_ImpMass);
l_FlowHour := l_FlowHour + ((1 / 1000) * i_ImpMass);
l_FlowMonth := l_FlowMonth + ((1 / 1000) * i_ImpMass);
l_FlowYear := l_FlowYear + ((1 / 1000) * i_ImpMass);
end_if

if i_nowDay <> l_day then
l_FlowDay := 0;
end_if

if i_nowHour <> l_hour then
l_FlowHour := 0;
end_if

if i_nowMonth <> l_month then
l_FlowMonth := 0;
end_if

if i_nowYear <> l_year then
l_FlowYear := 0;
end_if

ImpMass := l_impMass;
Flow := l_Flow;
FlowHour := l_FlowHour;
FlowDay := l_FlowDay;
FlowMonth := l_FlowMonth;
FlowYear := l_FlowYear;
out_Time := i_nowHour * 1000000 + i_nowDay * 10000 + i_nowMonth * 100 + i_nowYear;

end_function_block


Перевод всего времени в UNIX c последующим вытаскиванием дат?

Dimensy
28.12.2023, 16:00
Перевод всего времени в UNIX?

Мне лень писать на ST перевод из юникса в дату, поэтому просто упаковал. А так, да, по хорошему на вход надо подавать дату в юникс формате, и входов меньше будет

Dimensy
28.12.2023, 22:40
В, общем, вроде так надо. Ведь нам надо еще синхронизировать импульсы и приращение времени, чтобы при рассогласовании не было погрешности