PDA

Просмотр полной версии : Сохранение значений ФБ



deniska13
31.08.2018, 20:04
Добрый день!
Имеется ПЛК 110, написал ФБ в котором производится подсчет моточасов. Подскажите как можно сохранить накопленные значения ФБ?
Если поместить весь блок в область памяти retain значения будут сохраняться? И на сколько мне известно это не очень верное решение так как плохо в дальнейшем скажется на памяти (ограниченный ресурс). Есть второй вариант, сохранить накопленные значения в области retain после отключения питания ПЛК, после включения прочитать из области retain значения, сравнить их с значениями ФБ если не равны принудительно записать сохраненные значения в ФБ и продолжить считать. Может есть какой-то более простой способ. Подскажите.:D:D

melky
31.08.2018, 20:14
блин, у Овен ПЛК retain реализованы иначе, чем у других производителей, ничего там не попортится.

Сделайте у блока переменные типа IN_OUT и соответствующую логику и не придется весь блок запихивать в retain.

deniska13
31.08.2018, 20:26
блин, у Овен ПЛК retain реализованы иначе, чем у других производителей, ничего там не попортится.

Сделайте у блока переменные типа IN_OUT и соответствующую логику и не придется весь блок запихивать в retain.

не соображу по поводу IN_OUT и соответствующей логике, можете пояснить?
Вот собственно код ФБ

FUNCTION_BLOCK ENGINE_HOURS (*ФБ РАСЧЕТА ВРЕМЕНИ НАРАБОТКИ*)
VAR_INPUT
START: BOOL; (*АКТИВАЦИЯ СЧЕТА МОТОЧАСОВ*)
I_TH : DWORD; (*ВВОД НОВОГО ЗНАЧЕНИЯ НАРАБОТКИ В ЧАСАХ В РУЧНУЮ*)
I_TD :WORD; (*ВВОД НОВОГО ЗНАЧЕНИЯ НАРАБОТКИ В СУТКАХ В РУЧНУЮ*)
ENTER:BOOL; (*АКТИВАЦИЯ ВВЕДЕННЫХ В РУЧНУЮ ЗНАЧЕНИЙ*)
RESET: BOOL; (*СБРОС СЧЕТЧИКОВ ПРИНУДИТЕЛЬНО*)
END_VAR
VAR_OUTPUT
O_TH : DWORD; (*ВРЕМЯ НАРАБОТКИ В ЧАСАХ*)
O_TD : WORD; (*ВРЕМЯ НАРАБОТКИ В СУТКАХ*)
END_VAR
VAR
TMR :TON; (*ТАЙМЕР*)
TS:INT; (*РАБОТА В СЕКУНДАХ*)
TM:INT; (*РАБОТА В МИНУТАХ*)
END_VAR

IF ENTER THEN O_TH := I_TH; O_TD := I_TD; ELSE (*ЗАПИСЬ ЗНАЧЕНИЙ ЧАСОВ И СУТОК ПРИНУДИТЕЛЬНО В РУЧНУЮ*)
TMR(IN := NOT TMR.Q, PT := T#1ms);
IF TMR.Q THEN TS := TS + 1; END_IF (*СЧИТАЕМ СЕКУНДЫ*)
IF TS = 60 THEN TM := TM + 1; TS := 0; END_IF (*СЧИТАЕМ МИНУТЫ*)
IF TM = 60 THEN O_TH := O_TH + 1; TM := 0; END_IF (*СЧИТАЕМ ЧАСЫ*)
O_TD := REAL_TO_WORD(O_TH / 24); (*СЧИТАЕМ СУТКИ*) END_IF

IF RESET THEN O_TH := 0; O_TD := 0; END_IF (*ПРИНУДИТЕЛЬНЫЙ СБРОС СЧЕТЧИКОВ*)

melky
31.08.2018, 20:32
я на CFC делал, так что в ST не подскажу. Думаю смысл будет понятен. все переменные IN_OUT подключаются к retain переменным программы. Но не сам блок

Собственно у меня там реализован сброс по битовой маске, никто не мешает добавить входов для инициализации.

deniska13
31.08.2018, 20:42
я на CFC делал, так что в ST не подскажу. Думаю смысл будет понятен. все переменные IN_OUT подключаются к retain переменным программы. Но не сам блок

Собственно у меня там реализован сброс по битовой маске, никто не мешает добавить входов для инициализации.

Спасибо большое что откликнулись!

capzap
01.09.2018, 07:14
TMR(IN := NOT TMR.Q, PT := T#1ms);
IF TMR.Q THEN TS := TS + 1; END_IF (*СЧИТАЕМ СЕКУНДЫ*)

код вызвал усмешку, перепроверте себя сами еще раз
По поводу IN_OUT а зачем, глобальная переменная не хуже будет

deniska13
01.09.2018, 19:24
код вызвал усмешку, перепроверте себя сами еще раз
По поводу IN_OUT а зачем, глобальная переменная не хуже будет

В чем именно он у Вас вызвал усмешку?)

Трофимов Артем
01.09.2018, 19:28
таймер на миллисекунду, а комммент что секунды считаете.... вот тут и курьёз шкал

deniska13
01.09.2018, 19:34
таймер на миллисекунду, а комммент что секунды считаете.... вот тут и курьёз шкал

Ну это просто опечатка)..я думал что-то более серьезное, может другой способ программный)
Спасибо за разъяснение!)

deniska13
01.09.2018, 19:36
код вызвал усмешку, перепроверте себя сами еще раз
По поводу IN_OUT а зачем, глобальная переменная не хуже будет

Этот ФБ вызывается из программы, как мне объявить внутренние его переменные в глобальных или я что-то не так понял? Или имеете ввиду сам ФБ объявить в глобальных переменных? Этого разве будет достаточно чтобы не потерять насчитанные ФБ данные времени наработки?

capzap
01.09.2018, 19:41
если переменная глобальная, она видня в любом коде проекта без объявления

deniska13
01.09.2018, 19:59
если переменная глобальная, она видня в любом коде проекта без объявления

Это понятно. Какие мои действия для сохранения насчитанных данных счетчиков, у меня их 3. Насчитанные данные пишутся в регистры ПЛК (Slave) панель (Master) читает данные из этих регистров. При выключении питания ПЛК регистры сохранят свои значения так как область памяти (Slave) по умолчанию находится в энергонезависимой области, и тут же будут перезаписаны на те что выдает ФБ, если его поместить в область retain данные сохраняться? Объявить ФБ в области памяти retain, или же после включения ПЛК по первому фронту пишем в ФБ значения с регистров Slave, и считаем дальше. Как лучше поступить?

a_sergeevich
02.09.2018, 14:25
объявите переменные, которые надо, чтобы сохраняли свои значения после пропадания питания как retain, зачем весь фб объявлять как retain.

a_sergeevich
02.09.2018, 14:28
Вот как сделано у меня, управление насосами с подсчётом наработки. Также сохраняется время переключения насосов, которое задаётся с панели.

deniska13
02.09.2018, 15:33
Вот как сделано у меня, управление насосами с подсчётом наработки. Также сохраняется время переключения насосов, которое задаётся с панели.

не знал что так можно в ФБ переменные определять в области памяти retain....спасибо за пример и совет!

Serhioromano
05.09.2018, 07:44
Вот мой вариант блока


FUNCTION_BLOCK ENGINE_HOURS
VAR_INPUT
START: BOOL; (*АКТИВАЦИЯ СЧЕТА МОТОЧАСОВ*)
I_TH : DWORD; (*ВВОД НОВОГО ЗНАЧЕНИЯ НАРАБОТКИ В ЧАСАХ В РУЧНУЮ*)
I_TD : DWORD; (*ВВОД НОВОГО ЗНАЧЕНИЯ НАРАБОТКИ В СУТКАХ В РУЧНУЮ*)
ENTER: BOOL; (*АКТИВАЦИЯ ВВЕДЕННЫХ В РУЧНУЮ ЗНАЧЕНИЙ*)
RESET: BOOL; (*СБРОС СЧЕТЧИКОВ ПРИНУДИТЕЛЬНО*)
END_VAR
VAR_OUTPUT
O_TM : WORD; (*ВРЕМЯ НАРАБОТКИ В МИНУТАХ*)
O_TH : WORD; (*ВРЕМЯ НАРАБОТКИ В ЧАСАХ*)
O_TD : WORD; (*ВРЕМЯ НАРАБОТКИ В СУТКАХ*)
END_VAR
VAR
tStart: TIME; (* Точка времени начала счета *)
tWorking: TIME; (* Общее время работы счетчика *)
tMemmory: TIME; (* Общее время наработки после отключения *)
dwCalc: DWORD; (* Для расчета минут и часов *)
xStartMemmory: BOOL;
xResetMemmory: BOOL;
END_VAR

(* Если появился сигнал на входе сброса, сбрасываем счетчик *)
IF RESET AND NOT xResetMemmory THEN
tStart := T#0s;
tMemmory := T#0s;
END_IF;
xResetMemmory := RESET;

(* Определяем передний фронт сигнала начала измерения.
и сохраняем точку времени *)
IF START AND NOT xStartMemmory THEN
tStart := TIME();
END_IF;

(* Определяем задний фронт START, и если отключился
сохраняем наработанное время в переменную *)
IF NOT START AND xStartMemmory THEN
tMemmory := tMemmory + (TIME() - tStart);
END_IF;
xStartMemmory := START;

tWorking := (TIME() - tStart) + tMemmory;
IF ENTER THEN
tWorking := tWorking + DWORD_TO_TIME((I_TH * 3600000) + (I_TD * 86400000));
END_IF;

dwCalc := TIME_TO_DWORD(tWorking) / (1000 * 60); (* dwCalc хранит общее количество минут *)
O_TM := dwCalc MOD 60; (* Остаток минут *)
dwCalc := dwCalc / 60; (* dwCalc хранит общее количество часов *)
O_TH := dwCalc MOD 24; (* Остаток часов *)
O_TD := dwCalc / 24; (* Общее количество суток *)
END_FUNCTION_BLOCK

1. Правда такой блок имеет ограничение и может считать только до 49 дней включая добавочные часы и дни.
2. Блок должен определяться в энергонезависимой памяти.
3. Расчет часов и дней происходит не общий а остаток. Например 10 дней 12 часов. То есть часов ни когда не будет больше чем 23. Тоже самое касается минут.

Эдуард_Н
23.11.2018, 09:26
я на CFC делал, так что в ST не подскажу. Думаю смысл будет понятен. все переменные IN_OUT подключаются к retain переменным программы. Но не сам блок

Собственно у меня там реализован сброс по битовой маске, никто не мешает добавить входов для инициализации.

подскажите назначения входов-выходов.

melky
23.11.2018, 09:48
Эдуард_Н на работе сейчас не установлен CodeSys, сделайте скрин блока, тогда может по памяти скажу.
На вскидку, есть разрешение работы, есть вход импульса, есть вход сброса, сброс отдельных счетчиков происходит по битовой маске, 15 сбросит все, 1 сбросит только первый). Есть выход чтобы делать стекирование со следующим счетчиком.

Начинал делать для подсчета наработки, но в процессе он вылился в универсальный счетчик чего угодно, хоть бутылки - ящики - контейнеры считайте.
Делался из-за того, что встроенные счетчики 16-ти битные

Эдуард_Н
23.11.2018, 11:47
Эдуард_Н на работе сейчас не установлен CodeSys, сделайте скрин блока, тогда может по памяти скажу.
На вскидку, есть разрешение работы, есть вход импульса, есть вход сброса, сброс отдельных счетчиков происходит по битовой маске, 15 сбросит все, 1 сбросит только первый). Есть выход чтобы делать стекирование со следующим счетчиком.

Начинал делать для подсчета наработки, но в процессе он вылился в универсальный счетчик чего угодно, хоть бутылки - ящики - контейнеры считайте.
Делался из-за того, что встроенные счетчики 16-ти битные

Вот скрин40026

melky
23.11.2018, 14:00
CU - импульс счета
Enable - разрешение работы
PV1-PV4 - уставки для каждого счетного механизма (если не ошибаюсь, дома проверю)
PVr - битовая маска сброса. 0-й бит выход 1, 1-й бит выход 2, 2-й бит выход 3, 3-й бит выход 4
reset - подаем импульс сброса, если в битовой маске 1, то выход сбросится в 0
CV1-CV4 собственно и есть выходы с сохранением, на них подаются энергонезависимые переменные, при перезапуске ПЛК старт идет с данных значений.
stek - подается на CU следующего блока если надо расширить счет

Кажется так...
При использовании для времени PV1 = 60 (секунды), PV2 = 60 (минуты), PV3 = 24 (часы), PV4 = например 4 лярда дней :)
Соответственно импульсы должны приходить раз в секунду.

Эдуард_Н
23.11.2018, 14:39
Спасибо, будем пробовать.