-
Перемеренная типа TIME
Добрый день. Подскажите пожалуйста как быть если необходимо реализовать таймер который просто считает время при активировании переменной. допустим вкл. кнопку таймер побежал, суть в том что считать нужно не всегда определенное значение времени, это может быть и год и полтора. Переменная типа TIME максимум может дает поставить 1000 часов. Дальше ошибка : константа слишком велика для типа TIME
-
TIME это миллисекунды. Вам нужны миллисекунды? Значит, и TIME ни к чему. Считайте минутами, часами, да хоть годами.
-
Каким образом? на вход таймера значения задаются в формате t#0h0m0s. или стандартными таймерами это не реализовать и нужен другой таймер?
-
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();
-
Код:
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;
-
Цитата:
Сообщение от
spectrum48k
Код:
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;
Спасибо, решил проблему созданием счетчика из него взял нужное количество дней)