PDA

Просмотр полной версии : Перемеренная типа TIME



andrey96
17.09.2015, 14:48
Добрый день. Подскажите пожалуйста как быть если необходимо реализовать таймер который просто считает время при активировании переменной. допустим вкл. кнопку таймер побежал, суть в том что считать нужно не всегда определенное значение времени, это может быть и год и полтора. Переменная типа TIME максимум может дает поставить 1000 часов. Дальше ошибка : константа слишком велика для типа TIME

Yegor
17.09.2015, 14:55
TIME это миллисекунды. Вам нужны миллисекунды? Значит, и TIME ни к чему. Считайте минутами, часами, да хоть годами.

andrey96
17.09.2015, 15:01
Каким образом? на вход таймера значения задаются в формате t#0h0m0s. или стандартными таймерами это не реализовать и нужен другой таймер?

Yegor
17.09.2015, 23:50
Do you have any requirements? (http://programmers.life/2015/09/14/do-you-have-any-requirements/)

1. Самый простой и самый неточный способ: считать остатком деления по TIME. Удовлетворительная точность при периодах включения как минимум на пару порядков больше размерности счётчика. Корректно работает в сканах быстрее половины размерности.
VAR
on: BOOL;
uptimeSeconds: UDINT;
tickTock: R_TRIG;
END_VAR

tickTock(CLK := TIME_TO_UDINT(TIME()) MOD 1000 > 500);
uptimeSeconds := uptimeSeconds + BOOL_TO_UDINT(on AND tickTock.Q);2. Аналогичный первому и чуть более предсказуемый способ: считать по таймеру в режиме самосброса. По-прежнему требуется периодичность включения на порядки больше размерности. Корректно работает в сканах быстрее единицы размерности.
VAR
on: BOOL;
uptimeSeconds: UDINT;
tickTock: TON := (PT := T#1s);
END_VAR

tickTock(IN := on AND NOT tickTock.Q);
uptimeSeconds := uptimeSeconds + BOOL_TO_UDINT(tickTock.Q);3. Чуть более сложный и менее читаемый, но гораздо более точный и надёжный метод: копить в TIME до размерности учёта, затем складывать и сбрасывать. Время скана влияет только на точность учёта.
VAR
on: BOOL;
uptimeSeconds: UDINT;
prevTime, acc: TIME;
END_VAR

IF on THEN
acc := acc + TIME() - prevTime;
END_IF
uptimeSeconds := uptimeSeconds + TIME_TO_UDINT(acc) / 1000;
acc := UDINT_TO_TIME(TIME_TO_UDINT(acc) MOD 1000);
prevTime := TIME();

spectrum48k
18.09.2015, 00:29
FUNCTION_BLOCK TIMER
VAR_INPUT
iCntUp : BOOL;
iCntDn : BOOL;
iCntRes : BOOL;
iCntSP : TIME;
(*iIncSP : TIME;----ДОБАВЛЕНО для данного топика: величина периода, который считает/приращивает счетчик*)
END_VAR
VAR_OUTPUT
OutTime : TIME;
OutAlm : BOOL;
(*OutCnt : UINT;----ДОБАВЛЕНО для данного топика: считайте сколько нужно дней/часов/минут/недель*)
END_VAR
VAR
TimeAct : TIME;
TimeOld : TIME;
TimeDelta : TIME;
DoCalc : UINT;
Init: BOOL;
CntUpOld :BOOL;
CntDnOld : BOOL;
END_VAR



IF iCntRes THEN Init := FALSE; END_IF


(*INIT*)
IF NOT Init THEN
Init := TRUE;
iCntUp := iCntDn := CntUpOld := CntDnOld := OutAlm := FALSE;
TimeAct := TimeOld := TimeDelta := OutTime := t#0ms;
(*ДОБАВЛЕНО: OutCnt := 0;*)
DoCalc := 0;
RETURN;
END_IF


(*DOCALC*)
DoCalc := DoCalc +1;

IF (DoCalc MOD 10=0) OR (iCntUp <> CntUpOld) OR (iCntDn <> CntDnOld) THEN


TimeAct :=TIME();

IF TimeOld > t#0ms THEN
TimeDelta := TimeAct - TimeOld;

(*COUNT_UP*)
IF iCntUp OR (CntUpOld > iCntUp) THEN
IF iCntSP > OutTime THEN OutTime := OutTime + TimeDelta;
IF OutTime > iCntSP THEN OutTime := iCntSP; END_IF
END_IF;
END_IF

(*COUNT_DOWN*)
IF iCntDn OR (CntDnOld > iCntDn) THEN
IF OutTime > TimeDelta THEN OutTime := OutTime - TimeDelta;
ELSE OutTime := t#0ms;
END_IF;
END_IF

(*ДОБАВЛЕНО: IF OutTime >= iIncSP THEN OutCnt := OutCnt + 1; OutTime := OutTime - iIncSP; END_IF*)
OutAlm := iCntSP > t#0ms AND OutTime = iCntSP;

END_IF

TimeOld := TimeAct;

END_IF

CntUpOld := iCntUp;
CntDnOld := iCntDn;

andrey96
22.09.2015, 19:17
FUNCTION_BLOCK TIMER
VAR_INPUT
iCntUp : BOOL;
iCntDn : BOOL;
iCntRes : BOOL;
iCntSP : TIME;
(*iIncSP : TIME;----ДОБАВЛЕНО для данного топика: величина периода, который считает/приращивает счетчик*)
END_VAR
VAR_OUTPUT
OutTime : TIME;
OutAlm : BOOL;
(*OutCnt : UINT;----ДОБАВЛЕНО для данного топика: считайте сколько нужно дней/часов/минут/недель*)
END_VAR
VAR
TimeAct : TIME;
TimeOld : TIME;
TimeDelta : TIME;
DoCalc : UINT;
Init: BOOL;
CntUpOld :BOOL;
CntDnOld : BOOL;
END_VAR



IF iCntRes THEN Init := FALSE; END_IF


(*INIT*)
IF NOT Init THEN
Init := TRUE;
iCntUp := iCntDn := CntUpOld := CntDnOld := OutAlm := FALSE;
TimeAct := TimeOld := TimeDelta := OutTime := t#0ms;
(*ДОБАВЛЕНО: OutCnt := 0;*)
DoCalc := 0;
RETURN;
END_IF


(*DOCALC*)
DoCalc := DoCalc +1;

IF (DoCalc MOD 10=0) OR (iCntUp <> CntUpOld) OR (iCntDn <> CntDnOld) THEN


TimeAct :=TIME();

IF TimeOld > t#0ms THEN
TimeDelta := TimeAct - TimeOld;

(*COUNT_UP*)
IF iCntUp OR (CntUpOld > iCntUp) THEN
IF iCntSP > OutTime THEN OutTime := OutTime + TimeDelta;
IF OutTime > iCntSP THEN OutTime := iCntSP; END_IF
END_IF;
END_IF

(*COUNT_DOWN*)
IF iCntDn OR (CntDnOld > iCntDn) THEN
IF OutTime > TimeDelta THEN OutTime := OutTime - TimeDelta;
ELSE OutTime := t#0ms;
END_IF;
END_IF

(*ДОБАВЛЕНО: IF OutTime >= iIncSP THEN OutCnt := OutCnt + 1; OutTime := OutTime - iIncSP; END_IF*)
OutAlm := iCntSP > t#0ms AND OutTime = iCntSP;

END_IF

TimeOld := TimeAct;

END_IF

CntUpOld := iCntUp;
CntDnOld := iCntDn;


Спасибо, решил проблему созданием счетчика из него взял нужное количество дней)