PDA

Просмотр полной версии : Таймер RTC помогите разобраться



Mr.Plagiat
21.09.2012, 11:18
Хочу в ST создать программу, которая будет подсчитывать время наработки оборудования.
Хотел применить функцию RTC, не могу с ней разобраться как она работает.

RTC(EN:= , PDT:= , Q=> , CDT=> );

я её использовал так:

RTC(EN:=K , PDT:= , Q=> , CDT=>T);

то есть, когда K=1, таймер запускается, с выхода CDT снимается время. переменная Т у меня имеет тип TIME. Про эту функцию читал только в справке.

lara197a
21.09.2012, 12:44
FUNCTION_BLOCK Ychet_narabotki
VAR
RTC1: RTC; (*Время наработки*)
R_TRIG_Ust: R_TRIG; (*Команда запуска*)
Tek_schet_p: DWORD; (*Сигнал пуска*)
M1: BOOL;
F_TRIG_S: R_TRIG; (*Команда остановки*)
TOF_S: TOF; (*таймер задержки остановки*)
RS1: RS; (*Реле пуска -остановки наработки*)
Tek_schet_p1: DWORD;
M2: BOOL;
R_TRIG_Sch: R_TRIG;
Tim: DT;
Narabotka_p: TIME;
Narabotka_Chas_p: DWORD;
Narabotka_Chas_p1: DWORD;
Narabotka_Min_p: DWORD;
Narabotka_min_p1: DWORD;
Nt: BOOL;
END_VAR
VAR_INPUT
Tek_schet: DWORD; (*счетчик *)
In_Time: INT; (*астрономическое время(час дня)*)
END_VAR
VAR RETAIN
Narabotka: DT;
END_VAR
VAR_OUTPUT
END_VAR
VAR_OUTPUT RETAIN
Narabotka_Min: INT;
Narabotka_Chas: INT; (*наработка часов за смену*)
END_VAR

IF Tek_schet<>Tek_schet_p THEN
M1:=TRUE;
ELSE
M1:=FALSE;
END_IF;
R_TRIG_Ust(CLK:= TOF_S.Q, Q=> );
TOF_S(IN:=M1 , PT:=T#30s , Q=> , ET=> );
F_TRIG_S(CLK:=TOF_S.Q , Q=> );

RS1(SET:=R_TRIG_Ust.Q , RESET1:=F_TRIG_S.Q , Q1=> );

IF In_Time=7 OR In_Time=19 THEN (*Сброс часов*)
M2:=TRUE;
ELSE
M2:=FALSE;
END_IF;

R_TRIG_Sch(CLK:=M2 , Q=> ); (*Тригер сброса часов*)

RTC1(EN:=RS1.Q1 AND NOT R_TRIG_Sch.Q ,
PDT:=Tim , Q=> , CDT=>Narabotka );

IF R_TRIG_Sch.Q THEN
Tim:=DT#1970-01-01-00:00:00;
Narabotka:=DT#1970-01-01-00:00:00;
END_IF;

IF RS1.Q1 AND NOT R_TRIG_Sch.Q THEN
Tim:=Narabotka;
END_IF;

Narabotka_p:=DT_TO_TIME(Tim);
Narabotka_Chas_p:=TIME_TO_DWORD(Narabotka_p);
Narabotka_Chas_p1:=Narabotka_Chas_p/3600000;
Narabotka_Chas:=DWORD_TO_WORD(Narabotka_Chas_p1);

Narabotka_Min_p:=Narabotka_Chas_p-Narabotka_Chas_p1*3600000;
Narabotka_min_p1:=Narabotka_Min_p/60000;
Narabotka_Min:=DWORD_TO_WORD(Narabotka_Min_p1);

Tek_schet_p:=Tek_schet ;

Mr.Plagiat
27.09.2012, 10:02
lara197a, спасибо большое, ваш код очень сильно помог разобраться.

Выкладываю рабочую программу по учёту наработки:

PROGRAM PLC_PRG
VAR
K AT %IX0.0: BOOL; (*Переменная показывающая состояние двигателя: "К=1" - двигатель включён, "К=0" - двигатель выключен.*)
M: BYTE; (*Переменная необходимая для того чтобы "А" увеличивалась на единицу один раз за период работы двигателя.*)
RTC1: RTC; (*Время наработки*)
R_TRIG_Ust: R_TRIG; (*Команда запуска*)
Tek_schet_p: DWORD; (*Сигнал пуска*)
M1: BOOL;
F_TRIG_S: R_TRIG; (*Команда остановки*)
TOF_S: TOF; (*таймер задержки остановки*)
RS1: RS; (*Реле пуска -остановки наработки*)
Tek_schet_p1: DWORD;
M2: BOOL;
R_TRIG_Sch: R_TRIG;
Tim: DT;
Narabotka_p: TIME;
Narabotka_Chas_p: DWORD;
Narabotka_Chas_p1: DWORD;
Narabotka_Min_p: DWORD;
Narabotka_min_p1: DWORD;
Narabotka_Sek_p: DWORD;
Narabotka_sek_p1: DWORD;
Nt: BOOL;
Z: BOOL;
END_VAR
VAR_INPUT
Tek_schet: DWORD; (*счетчик *)
In_Time: INT; (*астрономическое время(час дня)*)
END_VAR
VAR RETAIN
Narabotka: DT;
A: BYTE; (*Переменная показывающая количество пусков. записывается в энергонезависимую память.*)
END_VAR
VAR_OUTPUT
END_VAR
VAR_OUTPUT RETAIN
Narabotka_Sek: INT;
Narabotka_Min: INT;
Narabotka_Chas: INT; (*наработка часов за смену*)
END_VAR



IF K=0 THEN
M:=0;
Tek_schet_p:=Tek_schet ;
Z:=1;
ELSE
Z:=0;
Tek_schet_p:=1;
IF M=0 THEN
M:=1;
A:=A+1;
END_IF
END_IF
IF Tek_schet<>Tek_schet_p THEN
M1:=TRUE;
ELSE
M1:=FALSE;
END_IF;
R_TRIG_Ust(CLK:= TOF_S.Q, Q=> );
TOF_S(IN:=M1 , PT:=T#1s , Q=> , ET=> );
F_TRIG_S(CLK:=TOF_S.Q , Q=> );

RS1(SET:=R_TRIG_Ust.Q , RESET1:=Z , Q1=> );

IF In_Time=7 OR In_Time=19 THEN (*Сброс часов*)
M2:=TRUE;
ELSE
M2:=FALSE;
END_IF;

R_TRIG_Sch(CLK:=M2 , Q=> ); (*Тригер сброса часов*)

RTC1(EN:=RS1.Q1 AND NOT R_TRIG_Sch.Q ,
PDT:=Tim , Q=> , CDT=>Narabotka );

IF R_TRIG_Sch.Q THEN
Tim:=DT#1970-01-01-00:00:00;
Narabotka:=DT#1970-01-01-00:00:00;
END_IF;

IF RS1.Q1 AND NOT R_TRIG_Sch.Q THEN
Tim:=Narabotka;
END_IF;

Narabotka_p:=DT_TO_TIME(Tim);
Narabotka_Chas_p:=TIME_TO_DWORD(Narabotka_p);
Narabotka_Chas_p1:=Narabotka_Chas_p/3600000;
Narabotka_Chas:=DWORD_TO_WORD(Narabotka_Chas_p1);

Narabotka_Min_p:=Narabotka_Chas_p-Narabotka_Chas_p1*3600000;
Narabotka_min_p1:=Narabotka_Min_p/60000;
Narabotka_Min:=DWORD_TO_WORD(Narabotka_Min_p1);

Narabotka_Sek_p:=Narabotka_Chas_p-Narabotka_Chas_p1*3600000-Narabotka_min_p1*60000;
Narabotka_sek_p1:=Narabotka_Sek_p/1000;
Narabotka_Sek:=DWORD_TO_WORD(Narabotka_sek_p1);

KRUG
10.10.2012, 14:55
А не могли бы Вы написать код для двух насосов (я хочу разобраться но не знаю с чего начать знаний программирования "0") и еще как в визуализацию вставить чтобы показывало наработку

Yegor
10.10.2012, 15:51
IF Tek_schet<>Tek_schet_p THEN
M1:=TRUE;
ELSE
M1:=FALSE;
END_IF;Это индусский код. Надо M1 := Tek_schet <> Tek_schet_p

Yegor
10.10.2012, 16:17
И вообще... не мудрите:
PROGRAM PLC_PRG
VAR
in: BOOL; (* Ну вход, чо *)
ticktock, starter: R_TRIG; (* Один срабатывает ежесекундно, другой при каждом запуске *)
END_VAR
VAR RETAIN
uptime, start_count: DWORD; (* Тут храним время наработки в секундах и число запусков *)
END_VAR

ticktock(clk := TIME_TO_DWORD(TIME()) MOD 1000 > 500);
starter(clk := in);
uptime := uptime + BOOL_TO_DWORD(in AND ticktock.Q);
start_count := start_count + BOOL_TO_DWORD(starter.Q);

lara197a
11.10.2012, 09:53
Это индусский код. Надо M1 := Tek_schet <> Tek_schet_p

Согласен, только в IF были еще действия , часть удалил.
Это только часть кода.
В примере время наработки считается относительно. Если счетчик сработал, то включаем учет наработки. Если в течении 30 сек импульсов ни с одного из счетчиков нет, то выключаем учет наработки. Там такая печь, которая работает круглосуточно, а по импульсам считаем подгружает ли человек в нее продукцию или нет.
И один ПЛК считает сразу за 10 человек.
Фактически счетчик лени работника. Ну это так частность.

energvk
14.03.2015, 23:22
И вообще... не мудрите:
PROGRAM PLC_PRG
VAR
in: BOOL; (* Ну вход, чо *)
ticktock, starter: R_TRIG; (* Один срабатывает ежесекундно, другой при каждом запуске *)
END_VAR
VAR RETAIN
uptime, start_count: DWORD; (* Тут храним время наработки в секундах и число запусков *)
END_VAR

ticktock(clk := TIME_TO_DWORD(TIME()) MOD 1000 > 500);
starter(clk := in);
uptime := uptime + BOOL_TO_DWORD(in AND ticktock.Q);
start_count := start_count + BOOL_TO_DWORD(starter.Q);

Не могу понять в чём подвох. Вроде отличный код, но почему http://www.owen.ru/forum/showthread.php?t=17206&p=136111&viewfull=1#post136111 настолько замороченее?

petera
14.03.2015, 23:39
Не могу понять в чём подвох. Вроде отличный код, но почему http://www.owen.ru/forum/showthread.php?t=17206&p=136111&viewfull=1#post136111 настолько замороченее?
Так разверните в этом варианте еще код двух используемых ФБ R_TRIG и добавьте вход для сброса времени наработки и будет не менее замороченее:)

energvk
14.03.2015, 23:46
Так разверните в этом варианте еще код двух используемых ФБ R_TRIG и добавьте вход для сброса времени наработки и будет не менее замороченее:)
Не знаю, по мне всё равно более читабельнее получается :)

petera
15.03.2015, 00:10
Не знаю, по мне всё равно более читабельнее получается :)
Так покажите, получавшийся читабельный код

energvk
15.03.2015, 16:06
Признаю, был не прав :rolleyes:

petera
15.03.2015, 21:25
Признаю, был не прав :rolleyes:
А если из OSCATовского кода удалить вход для сброса и удалить начальную инициализацию, то останется всего

FUNCTION_BLOCK ONTIME
VAR_INPUT
IN : BOOL;
END_VAR
VAR_IN_OUT
SECONDS : UDINT;
CYCLES : UDINT;
END_VAR
VAR
tx: DWORD;
last : DWORD;
edge : BOOL;
ms: DWORD;
END_VAR


tx := TIME_TO_DWORD(TIME()); (* read system time *)
IF IN THEN
ms := (tx - last) + ms; (* add the current milliseconds *)
IF ms >= 1000 THEN
seconds := seconds + 1;
ms := ms - 1000;
END_IF
cycles := cycles + BOOL_TO_UINT(NOT edge);
END_IF
last := tx;
edge := in;

Yegor
15.03.2015, 21:51
Так разверните в этом варианте еще код двух используемых ФБ R_TRIGЧто там разворачивать? Ну, плюс одна переменная, да.
VAR in, _in, ticktock, _ticktock: BOOL;
END_VAR
VAR RETAIN
uptime, start_count: DWORD;
END_VAR
ticktock := TIME_TO_DWORD(TIME()) MOD 1000 > 500;
uptime := uptime + BOOL_TO_DWORD(in AND ticktock > _ticktock);
start_count := start_count + BOOL_TO_DWORD(in > _in);
_ticktock := ticktock;
_in := in;В OSCAT'овском варианте есть функция сброса и нет ошибки накопления. Теоретически, мой код в худшем случае показывает наработку в 1000 раз больше/меньше действительной — это когда устройство включается/выключается на 501 миллисекунде и выключается/включается на 502-й ежесекундно. То есть им можно пользоваться только если вас устраивает ошибка ±1 с на каждом цикле включения.

Эдуард_Н
16.03.2015, 17:47
FUNCTION_BLOCK Ychet_narabotki
VAR
RTC1: RTC; (*Время наработки*)
R_TRIG_Ust: R_TRIG; (*Команда запуска*)
Tek_schet_p: DWORD; (*Сигнал пуска*)
M1: BOOL;
F_TRIG_S: R_TRIG; (*Команда остановки*)
TOF_S: TOF; (*таймер задержки остановки*)
RS1: RS; (*Реле пуска -остановки наработки*)
Tek_schet_p1: DWORD;
M2: BOOL;
R_TRIG_Sch: R_TRIG;
Tim: DT;
Narabotka_p: TIME;
Narabotka_Chas_p: DWORD;
Narabotka_Chas_p1: DWORD;
Narabotka_Min_p: DWORD;
Narabotka_min_p1: DWORD;
Nt: BOOL;
END_VAR
VAR_INPUT
Tek_schet: DWORD; (*счетчик *)
In_Time: INT; (*астрономическое время(час дня)*)
END_VAR
VAR RETAIN
Narabotka: DT;
END_VAR
VAR_OUTPUT
END_VAR
VAR_OUTPUT RETAIN
Narabotka_Min: INT;
Narabotka_Chas: INT; (*наработка часов за смену*)
END_VAR

IF Tek_schet<>Tek_schet_p THEN
M1:=TRUE;
ELSE
M1:=FALSE;
END_IF;
R_TRIG_Ust(CLK:= TOF_S.Q, Q=> );
TOF_S(IN:=M1 , PT:=T#30s , Q=> , ET=> );
F_TRIG_S(CLK:=TOF_S.Q , Q=> );

RS1(SET:=R_TRIG_Ust.Q , RESET1:=F_TRIG_S.Q , Q1=> );

IF In_Time=7 OR In_Time=19 THEN (*Сброс часов*)
M2:=TRUE;
ELSE
M2:=FALSE;
END_IF;

R_TRIG_Sch(CLK:=M2 , Q=> ); (*Тригер сброса часов*)

RTC1(EN:=RS1.Q1 AND NOT R_TRIG_Sch.Q ,
PDT:=Tim , Q=> , CDT=>Narabotka );

IF R_TRIG_Sch.Q THEN
Tim:=DT#1970-01-01-00:00:00;
Narabotka:=DT#1970-01-01-00:00:00;
END_IF;

IF RS1.Q1 AND NOT R_TRIG_Sch.Q THEN
Tim:=Narabotka;
END_IF;

Narabotka_p:=DT_TO_TIME(Tim);
Narabotka_Chas_p:=TIME_TO_DWORD(Narabotka_p);
Narabotka_Chas_p1:=Narabotka_Chas_p/3600000;
Narabotka_Chas:=DWORD_TO_WORD(Narabotka_Chas_p1);

Narabotka_Min_p:=Narabotka_Chas_p-Narabotka_Chas_p1*3600000;
Narabotka_min_p1:=Narabotka_Min_p/60000;
Narabotka_Min:=DWORD_TO_WORD(Narabotka_Min_p1);

Tek_schet_p:=Tek_schet ;

Я извиняюсь, что должно быть на входах блока, что бы он начал считать? Или он в эмуляции не работает?

lara197a
16.03.2015, 18:50
Tek_schet (*Сигнал пуска*)
импульсы на вход поступают.

Эдуард_Н
16.03.2015, 19:19
Подаю на Tek_schet (*Сигнал пуска*) "1" и ничего.

lara197a
16.03.2015, 20:33
после компиляции и запуска эмуляции "старт" нажимаете?

Эдуард_Н
16.03.2015, 20:39
после компиляции и запуска эмуляции "старт" нажимаете?

конечно :) просто не дождался, минимум ведь минута. Так что извините.

lara197a
16.03.2015, 21:07
код скиньте, я проверю и исправлю, если ошибка где.
Пример из рабочей программы выдернут.
Много лет работает.