3

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.

SilverShotBee
  • 1,480
  • 3
  • 23
  • 46

5 Answers5

4

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.

Felix Keil
  • 2,102
  • 1
  • 20
  • 23
2

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.

mrsargent
  • 1,824
  • 3
  • 15
  • 34
  • What resets `actualTime` back to it's original value? Everything else seems exactly what I'm looking for though! – SilverShotBee Dec 10 '15 at 16:14
  • Thanks, I've just finished tweaking it to suit my application and made a similar edit. I need it to remember when the pump stops, so I changed the trigger to occur when the pump goes OFF not ON. But the logic is sound. – SilverShotBee Dec 10 '15 at 16:24
2

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

Ozcan
  • 21
  • 2
  • While ET will remain still while you aren't calling the timer, the moment you do call it, it will jump to the time it would have been if you had kept calling it. This is because, I believe, TON timer uses system time to calculate ET at each step, meaning that if you stop calling it for say 5 minutes, then once you call it again the system time will have changed by 5 minutes, resulting in ET increasing by 5 minutes instead of just a second – Guiorgy Jul 24 '20 at 15:41
0

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;
pboedker
  • 506
  • 1
  • 3
  • 13
0

Here is a TIMER, that can be configured to:

  • loop = FALSE and resetWhenOFF = TRUE | runs like a normal TON
  • loop = FALSE and resetWhenOFF = FALSE | a TON that pauses when OFF
  • loop = TRUE and resetWhenOFF = FALSE | a TON with a rising edge output when timeLimit reached, after which, it resets and starts over (loops)
  • loop = TRUE and resetWhenOFF = TRUE | a TON with a rising edge output when timeLimit reached, after which, it resets and starts over (loops), and pauses when OFF
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
Guiorgy
  • 436
  • 4
  • 16