🔍
v1.3.8

Timers

Timers are fundamental building blocks in TSharkRex recipes. They let you introduce time-based behavior: delays before activation, hold periods after deactivation, periodic polling, and debouncing of noisy signals. TSharkRex provides two timer types - TON (on-delay) and TOF (off-delay) - which cover the vast majority of timing needs.

Flash & RAM constraints: XBB devices have limited flash and RAM. Write compact code - prefer TOF over TON + manual reset when appropriate, write expressions inline rather than storing intermediate variables, and avoid allocating timers you do not need.

TON - On-Delay Timer

TON delays the activation of its output. The output Q goes TRUE only after the input IN has been continuously TRUE for the duration specified by PT. If IN goes FALSE before the time elapses, the timer resets and Q remains FALSE.

Parameters

Parameter Type Direction Description
IN BOOL Input Timer input - starts timing when TRUE
PT UDINT Input Preset time in milliseconds (use T# literals)
Q BOOL Output TRUE when IN has been TRUE for at least PT
ET UDINT Output Elapsed time in milliseconds (counts up from 0 to PT)

Timing Behavior

IN:  _____|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|__________
           |<--- PT --->|
Q:   _____|_____________|‾‾‾‾‾|__________
ET:  0    0  ...  PT    PT    0

When IN goes TRUE, ET starts counting up. When ET reaches PT, Q goes TRUE. When IN goes FALSE, both Q and ET reset to zero immediately.

Basic Example

Wait 2 seconds after ignition is detected before enabling the CAN controller:

VAR
    TMR_STARTUP : TON;
    SIGNAL_TANDNING : BOOL;
    canReady : BOOL;
END_VAR;

TMR_STARTUP(IN := SIGNAL_TANDNING, PT := T#2s);
canReady := TMR_STARTUP.Q;

Reset Example

Reset the timer by driving IN to FALSE:

VAR
    TMR_DELAY : TON;
    startCondition : BOOL;
    resetCondition : BOOL;
END_VAR;

// Timer runs only when start is TRUE and reset is FALSE
TMR_DELAY(IN := startCondition AND NOT resetCondition, PT := T#5s);

Self-Resetting Periodic Timer

One of the most common patterns in TSharkRex is the self-resetting timer, which creates periodic execution. Feed the inverted output back into the input:

VAR
    TMR_PERIODIC : TON;
END_VAR;

TMR_PERIODIC(IN := NOT TMR_PERIODIC.Q, PT := T#1s);
IF TMR_PERIODIC.Q THEN
    // This block executes every 1 second
    TMR_PERIODIC(IN := FALSE);   // Reset for next cycle
END_IF;

How it works:

  1. TMR_PERIODIC.Q starts as FALSE, so NOT FALSE = TRUE - the timer starts.
  2. After 1 second, Q goes TRUE.
  3. The IF body executes and immediately resets the timer with IN := FALSE.
  4. On the next scan, Q is FALSE again, so the cycle repeats.
Tip: This is the standard way to poll CAN DIDs or refresh sensor readings at a fixed interval. Most recipes have at least one periodic timer driving the main polling loop.

Practical Example: CAN DID Polling

VAR
    TMR_POLL : TON;
    CANSEND : CAN_TX;
    SENDDATA : ARRAY[0..7] OF BYTE;
END_VAR;

// Poll vehicle speed every 200ms
TMR_POLL(IN := NOT TMR_POLL.Q, PT := T#200ms);
IF TMR_POLL.Q THEN
    SENDDATA[0] := 0x03;
    SENDDATA[1] := 0x22;
    SENDDATA[2] := 0xF4;
    SENDDATA[3] := 0x0D;
    CANSEND(ENABLE := TRUE, ID := 0x7E0, EXT := FALSE, DATALENGTH := 8, DATA := SENDDATA);
    TMR_POLL(IN := FALSE);
END_IF;

TOF - Off-Delay Timer

TOF is the opposite of TON: it delays the deactivation of its output. When IN goes TRUE, Q goes TRUE immediately. When IN goes FALSE, Q remains TRUE for the duration PT before turning off.

Parameters

Parameter Type Direction Description
IN BOOL Input Timer input - output follows immediately on rising edge
PT UDINT Input Off-delay time in milliseconds
Q BOOL Output TRUE while IN is TRUE, then stays TRUE for PT after IN goes FALSE
ET UDINT Output Elapsed time since IN went FALSE (counts up to PT)

Timing Behavior

IN:  _____|‾‾‾‾‾‾|____________________
                      |<--- PT --->|
Q:   _____|‾‾‾‾‾‾|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|____
ET:  0    0      0  ...  PT       0

Example: Hold Output After Signal Disappears

Keep an output active for 1 second after the ignition signal goes away - useful for graceful shutdown sequences:

VAR
    TMR_DELAY : TOF;
    SIGNAL_TANDNING : BOOL;
END_VAR;

TMR_DELAY(IN := SIGNAL_TANDNING, PT := T#1s);

Example: CAN Keep-Alive After Ignition Off

VAR
    TMR_KEEPALIVE : TOF;
    SIGNAL_TANDNING : BOOL;
    canActive : BOOL;
END_VAR;

// Keep CAN communication alive for 5 seconds after ignition off
TMR_KEEPALIVE(IN := SIGNAL_TANDNING, PT := T#5s);
canActive := TMR_KEEPALIVE.Q;

Common Timer Patterns

Debouncing

Noisy signals (mechanical switches, proximity sensors) can rapidly toggle between TRUE and FALSE. Use TON to filter out transient spikes:

VAR
    TMR_DEBOUNCE : TON;
    rawSwitch : BOOL;
    stableSwitch : BOOL;
END_VAR;

// Signal must be stable for 50ms before it is accepted
TMR_DEBOUNCE(IN := rawSwitch, PT := T#50ms);
stableSwitch := TMR_DEBOUNCE.Q;
Tip: For full debounce (both rising and falling edges), combine TON and TOF:
VAR
    TMR_ON : TON;
    TMR_OFF : TOF;
    rawSignal : BOOL;
    debouncedSignal : BOOL;
END_VAR;

TMR_ON(IN := rawSignal, PT := T#50ms);
TMR_OFF(IN := TMR_ON.Q, PT := T#50ms);
debouncedSignal := TMR_OFF.Q;

Timeout Detection (CAN Bus)

Detect when a CAN response has not arrived within an expected time window. This is critical for error handling - if the ECU does not respond, you should stop waiting and take a fallback action:

VAR
    TMR_TIMEOUT : TON;
    waitingForResponse : BOOL;
    responseReceived : BOOL;
    timeout : BOOL;
END_VAR;

TMR_TIMEOUT(IN := waitingForResponse AND NOT responseReceived, PT := T#500ms);
timeout := TMR_TIMEOUT.Q;

IF timeout THEN
    // ECU did not respond within 500ms - handle error
    waitingForResponse := FALSE;
END_IF;

Periodic Polling

As shown in the self-resetting timer section, periodic execution is achieved by feeding the inverted output back into the input. Vary the PT value to control the polling rate:

Interval PT Value Typical Use
50ms T#50ms Fast signals (RPM, wheel speed)
100ms T#100ms Standard DID polling
200ms T#200ms Moderate signals (speed, temperature)
500ms T#500ms Slow signals (battery voltage, ambient temp)
1s T#1s Status checks, heartbeats

Delayed Shutdown

When the ignition turns off, wait a period before entering sleep mode. This gives time for final CAN messages and graceful cleanup:

VAR
    TMR_SHUTDOWN : TON;
    SIGNAL_TANDNING : BOOL;
    shouldSleep : BOOL;
    CANMODE : CAN_MODE;
END_VAR;

// Start shutdown timer when ignition is off
TMR_SHUTDOWN(IN := NOT SIGNAL_TANDNING, PT := T#10s);
shouldSleep := TMR_SHUTDOWN.Q;

IF shouldSleep THEN
    CANMODE(MODE := CAN_MODE_SLEEP, BAUDRATE := 500);
END_IF;
Warning: Be careful with the delayed shutdown pattern above. The CAN_MODE call in the IF block will be called on every scan cycle once the timer expires. For a production recipe, combine this with an INIT-style flag or use a state machine to ensure CAN_MODE is called only once.