Skip to content

Timers

Timers are IEC function blocks that measure time across PLC cycles. They are not simple functions: they have internal memory, and that memory is updated when the timer is called.

IEC Timer Types

The common IEC timers are:

Timer Name Typical use
TON On-delay timer Start something only after a condition has been true for a configured time.
TOF Off-delay timer Keep something active for a configured time after the input becomes false.
TP Pulse timer Generate a pulse of a configured duration from a trigger.

In TIA Portal, these timers are usually called like function blocks. Their instance memory can be declared as a static variable inside an FB.

VAR
    _tonStartDelay : TON;
    _xboStartDelayDone : Bool;
END_VAR

BEGIN
    _tonStartDelay(
        IN := xboStartRequest,
        PT := T#2s
    );

    _xboStartDelayDone := _tonStartDelay.Q;
END_FUNCTION_BLOCK

TON

TON switches Q to true only after IN has been true for PT.

_tonAlarmDelay(
    IN := xboAlarmCondition,
    PT := T#500ms
);

xboAlarmActive := _tonAlarmDelay.Q;

Use TON for delayed alarms, startup delays, debounce logic, and minimum stable conditions.

TOF

TOF keeps Q true for PT after IN becomes false.

_tofFanRunOn(
    IN := xboCoolingRequired,
    PT := T#30s
);

xboFanRunCommand := _tofFanRunOn.Q;

Use TOF for run-on behavior, signal hold times, and controlled shutdown delays.

TP

TP generates a pulse. When triggered, Q remains true for PT.

_tpHornPulse(
    IN := xboNewAlarmDetected,
    PT := T#1s
);

xboHornPulse := _tpHornPulse.Q;

Use TP when the output should be true for a defined time independent of the trigger length.

Call Timers Once

Call timers once

Avoid calling the same timer instance in several places in one block. The timer output can change when the instance is called, so multiple calls make the logic depend on call order. Call it once, store .Q in a named Boolean, and use that Boolean later.

Prefer this:

_tonStartDelay(
    IN := xboStartRequest,
    PT := T#2s
);

_xboStartDelayDone := _tonStartDelay.Q;

IF _xboStartDelayDone THEN
    xboStartAllowed := TRUE;
END_IF;

Avoid spreading timer calls around the block:

_tonStartDelay(IN := xboStartRequest, PT := T#2s);

IF _tonStartDelay.Q THEN
    xboStartAllowed := TRUE;
END_IF;

// Later in the same block:
_tonStartDelay(IN := xboDifferentCondition, PT := T#2s);

The second call overwrites the same timer instance state for the current cycle.

Expert note: timers need static memory

IEC timers remember elapsed time, previous input state, and output state. That memory must live somewhere stable between PLC cycles.

In an FB, declare timer instances in VAR, not VAR_TEMP. Static VAR memory belongs to the FB instance DB and survives from one call to the next. VAR_TEMP is recreated for each call and is not suitable for timer instance memory.

This is why a timer is different from a pure calculation function. ABS(reValue) can return a result from its inputs alone. A TON cannot: it must know how long IN has already been true.

A practical rule: if the block must remember something across cycles, it belongs in static memory. Timers, edge detectors, counters, filters, latched alarms, and state machines all depend on this idea.

Timer Checklist

  • Declare timer instances once in static VAR.
  • Call each timer instance once per cycle.
  • Store .Q in a named Boolean if it is used in several places.
  • Keep the timer input condition simple and readable.
  • Name the timer by its engineering purpose, not only by its type.