TON — Timer-On-Delay

Definition

TON (“Timer On-delay”) is the canonical IEC 61131-3 delay timer. After its IN input goes TRUE the timer starts counting; after PT of continuous IN = TRUE, the output Q goes TRUE and stays TRUE until IN returns to FALSE. If IN drops to FALSE before PT is reached, the timer resets and ET snaps back to T#0s.

Mnemonic: Q is delayed-on. Use TON whenever you want “do X after Y has been true for Z time”.

Pin layout

DirectionNameTypeDescription
InputINBOOLStart the timer when this goes TRUE; reset it when it goes FALSE
InputPTTIMEPreset time — how long IN must stay TRUE before Q fires
OutputQBOOLTRUE once IN has been TRUE continuously for at least PT
OutputETTIMEElapsed time since IN went TRUE (capped at PT)

Syntax

VAR
    stepTimer : TON;
END_VAR

stepTimer(IN := <bool_expr>,
          PT := <time_expr>);

(* read outputs through the instance *)
... := stepTimer.Q;
... := stepTimer.ET;

Examples

Simple debounce

VAR
    debounceBtn : TON;
    xButtonRaw  : BOOL;       (* hardware input, may bounce *)
    xButtonOk   : BOOL;       (* clean signal for application code *)
END_VAR

(* Call EVERY cycle — gate the trigger on IN, not on whether to call *)
debounceBtn(IN := xButtonRaw, PT := T#20ms);
xButtonOk := debounceBtn.Q;

Step sequence (per the Ackersteuerung pattern)

VAR
    tonMt    : TON;
    iMtStep  : INT := -1;
    tMtPerBed: TIME := T#10m;
END_VAR

(* When the FB is "running" on this step, run the timer.
   When the timer expires, advance the step and reset the timer. *)
IF xMtRunning THEN
    tonMt(IN := TRUE, PT := tMtPerBed);
    IF tonMt.Q THEN
        tonMt(IN := FALSE, PT := tMtPerBed);   (* reset the timer *)
        iMtStep := iMtStep + 1;
    END_IF;
ELSE
    tonMt(IN := FALSE, PT := tMtPerBed);
END_IF;

The trick in the second example is the explicit reset call tonMt(IN := FALSE, …) after Q fires. Without that, the timer would re-trigger on the very next cycle (because IN is still TRUE) and immediately re-fire Q, looking like a free-running pulse train.

Semantics

Per IEC 61131-3 Annex F.7.1, evaluated on every call:

when IN goes FALSE → TRUE   (rising edge): start counting from 0
when IN is TRUE              and not yet at PT: ET := ET + cycle_time
when ET reaches PT                              : Q := TRUE
when IN goes TRUE → FALSE                       : Q := FALSE; ET := T#0s

Q is TRUE for as long as IN remains TRUE after the preset has been reached. There is no “one-shot” mode — for that, use TP (timer pulse).

ET is monotonically increasing within one continuous-IN period and is capped at PT (it does not keep growing past the preset).

IEC reference

IEC 61131-3 third edition (2013), Annex F (normative), section F.7.1 — TON timer FB.

matiec conformance

matiec implements TON exactly per the standard. The runtime counter resolution is the task cycle: a TON with PT := T#1ms running in a 20 ms task will fire Q after one full task cycle (i.e. after 20 ms), not after the nominal 1 ms. Monitor cadence rule: see the Sampling rule for correct interpretation note in the ForgeIEC monitor docs.

ForgeIEC notes

  • The MCP library.read_block("TON") tool returns the pin list shown above. Use it before writing a TON call to confirm the parameter names (case-sensitive in matiec).
  • The monitor.snapshot tool reports Q and ET of any TON instance whose enclosing POU has monitor_enabled=true on the FB-instance variable. Useful to diagnose “Q never goes TRUE” situations live.
  • Project memory feedback_quantitative_tests: any change to a TON-driven sequence needs a measuring capture+diff script, not “looks ok in the editor”. TON behaviour at scan cycle N is non-trivially coupled to the cycle period.