Reputation: 1571
I need to be able to pause a timer and retain it's ET
value when the timer is no longer being asked to run. The timer times when the input from a proximity switch is not present, but I only want it to time when the pump that forwards on the material is running. The pump may only run for 30 seconds, but the prox switch may be 120 seconds worth of pumping away, so it would take 4 runs of the pump before any material would be detected.
I'm using Codesys v2.3 if that helps
So far I have:
IF Motor AND NOT Proxy.P1 THEN (*If the motor is running and the proxy doesn't energise, then start that proxy's timer*)
Proxy.P1_Timer.IN:= TRUE;
ELSE
Proxy.P1_Timer.IN:=FALSE;
END_IF
But the above scenario will cause the ET
value to reset when Motor goes off also, not only when Proxy.P1
becomes TRUE
. The ET
should only reset when Proxy.P1
is set to TRUE
Any advice on this? I'm surprised that there isn't just a retain option on the FB.
Upvotes: 3
Views: 8779
Reputation: 1734
Here is a TIMER, that can be configured to:
FUNCTION_BLOCK TIMER
VAR_INPUT
ON: BOOL;
reset: BOOL;
timeLimit: TIME;
loop: BOOL;
resetWhenOFF: BOOL;
END_VAR
VAR_OUTPUT
finished: BOOL;
elapsedTime: TIME;
remainingTime: TIME;
END_VAR
VAR
_TON_INST: TON;
_lastElapsedTime: TIME;
_onTrigger: F_TRIG;
_resetTrigger: R_TRIG;
_doReset: BOOL;
END_VAR
_onTrigger(CLK := ON);
IF (_onTrigger.Q) THEN
IF (resetWhenOFF) THEN
_lastElapsedTime := T#0MS;
_doReset := TRUE;
ELSE
_lastElapsedTime := _TON_INST.ET + _lastElapsedTime;
END_IF
END_IF
_resetTrigger(CLK := reset);
_TON_INST(IN := ON AND NOT (_resetTrigger.Q OR _doReset), PT := timeLimit - _lastElapsedTime);
finished := _TON_INST.Q;
elapsedTime := _TON_INST.ET + _lastElapsedTime;
remainingTime := _timeLimit - _lastElapsedTime - _TON_INST.ET;
IF (_TON_INST.Q AND _loop) THEN
_lastElapsedTime := T#0MS;
_doReset := TRUE;
END_IF
END_FUNCTION_BLOCK
Upvotes: 0
Reputation: 21
Another way is to call the timer in CASE OF, if the Case is not calling TON, it will be paused, be careful to handle the in and out of TON when in CASE and out of CASE
Upvotes: 2
Reputation: 533
Another approach could be to increment/decrement a timer variable manually, adding/subtracting the scan time at each scan while the pump is started.
This functionality could be hidden in a function block with the necessary inputs.
A simple implementation is shown below.
VAR
tRun: TIME;
bResetTimer: BOOL;
END_VAR
VAR_CONSTANT
T_SCAN := t#10ms;
END_VAR
IF Pump.run AND NOT Proximity.on THEN
tRun := tRun + tScan;
END_IF;
IF tRun >= t#120s THEN
; (* Do something *)
END_IF;
IF bResetTimer THEN
tRun := t#0s;
bResetTimer := FALSE;
END_IF;
Upvotes: 0
Reputation: 2428
Here is a TON_Pausable.
TON_Pausable behaves just like a normal TON. Additionally TON_Pausable is paused via the PAUSE Input, IN has to remain true while pausing.
FUNCTION_BLOCK TON_Pausable
VAR_INPUT
IN : BOOL;
PT : TIME;
PAUSE : BOOL;
END_VAR
VAR_OUTPUT
Q : BOOL;
ET : TIME;
END_VAR
VAR
rtPause : R_TRIG;
tTimePaused : TIME;
ton : TON;
END_VAR
IF NOT IN THEN
tTimePaused := T#0s;
END_IF
rtPause(CLK := PAUSE);
IF rtPause.Q THEN
tTimePaused := tTimePaused + ton.ET;
END_IF
ton(IN := IN AND NOT PAUSE, PT := PT - tTimePaused);
Q := ton.Q;
ET := tTimePaused + ton.ET;
This way the logic is encapsulated and reusable.
Upvotes: 4
Reputation: 2442
to pause the timer I would use the following code
rEdgeTrig(CLK:=startTimer);
IF rEdgeTrig.Q THEN
actualTime := actualTime - eTime;
END_IF;
(* TON timer *)
timer(IN:=startTimer,PT:=actualTime);
IF startTimer THEN
eTime := timer.ET;
END_IF;
if timer.Q then
acutalTime:=initialTime;
end_if;
when your timer is no longer being asked to run then load the elapsed time to a variable. Then subtract from the preset time when you want to start again.
Upvotes: 2