Timers, Counters and Data

Timer and counter types, data types, math and compare, scaling, and the number mistakes that bite.

Timers

IEC 61131-3 defines three timers. Each has an input IN, a preset time PT, a done output Q and an elapsed time ET. Brand names and syntax differ, but the behavior is the same.

TimerQ turns on…Q turns off…Typical use
TON on-delayPT after IN turns on, if IN stays onimmediately when IN turns offStart-up delays; ignore short blips; alarm delays
TOF off-delayimmediately when IN turns onPT after IN turns offFan run-on; keep a light on after leaving
TP pulseimmediately on a rising edge of INafter exactly PT, whatever IN doesFixed-length pulse: horn, dosing shot
Retentive (RTO, TONR)when the accumulated time reaches PTonly when resetRun-hours, total on-time, maintenance timers
TON (on-delay), PT = 3 sINQtoo short: Q stays offPT = 3 sTOF (off-delay), PT = 3 sINQPT = 3 s02468101214s
TON and TOF with PT = 3 s. In the TON panel the first pulse is shorter than PT, so Q never turns on. In the TOF panel the second pulse restarts the delay.
On-delay: the alarm horn sounds only if the fault lasts more than 3 sLow_PressureI0.3TONIN = rungPT = T#3sQ > Horn_DelayHorn_TimerHorn_DelayHorn_Timer.QHornQ0.4Off-delay: the cooling fan runs on for 60 s after the motor stopsMotor_RunQ0.0TOFIN = rungPT = T#60sQ > FanFan_Timer
An on-delayed horn and an off-delayed cooling fan, as ladder rungs.
  • A TON restarts from zero each time IN goes false. A signal that flickers never reaches the preset; this makes a TON a simple filter.
  • Use the done (Q) bit, not the elapsed time, to drive the next step. Comparing ET to a value makes logic that depends on scan timing.
  • Timer accuracy is to within one scan: the timer is updated once per scan. A 100 ms timer on a 12 ms scan can be 12 ms late.
  • One timer instance per use. Reusing the same timer in two places causes the two to fight over it. Give each function its own timer tag.
  • Timer range. Presets are limited by the data type; see the number gotchas below.

Timer units by platform

PlatformHow a 5 s on-delay is enteredNotes
Allen-Bradley LogixTON with .PRE = 5000 (milliseconds)Timer tag has .PRE .ACC .EN .TT .DN; use .DN as the done bit
Siemens S7-1200TON with PT := T#5sIEC timer with an instance data block; Q and ET outputs
Mitsubishi iQ-F / FXOUT T0 K50 for a 100 ms timer (50 × 100 ms)Different timer numbers have different time bases (100 ms, 10 ms, 1 ms); check the device list
Omron CP1TIM 0000 #0050 (0.1 s units)TIMH is the 10 ms version; BCD preset on older models
IDEC FC6ATIM T0 50 (typically 0.1 s units)TIM, TMH (10 ms) and TMS (1 s) variants
Unitronics VisionTimer with a preset in 10 ms units (500)Check the units of the timer in the software; presets can be a number or a data register
CODESYSTON(IN := x, PT := T#5s)Standard IEC function block; TIME type

Units are the most common source of timer mistakes when changing brands: a preset of 50 is 5 s on one platform and 50 ms on another. Always check the time base.

Timer examples

Flasher (blinker)

Two TON timers feeding each other produce a repeating on/off signal: when Flash_On is false, timer 1 counts 0.5 s and turns the output on; when the output is on, timer 2 counts 0.5 s and turns it off. In structured text:

Flash_T1(IN := NOT Flash_Out, PT := T#500ms);     (* time off *)
Flash_T2(IN := Flash_Out,     PT := T#500ms);     (* time on  *)
IF Flash_T1.Q THEN Flash_Out := TRUE;  END_IF;
IF Flash_T2.Q THEN Flash_Out := FALSE; END_IF;

Many PLCs have a built-in clock bit (for example a 1 Hz or 0.5 s system flag) that does the same in one contact.

Delayed start sequence

To start three conveyors one after another 3 s apart, use a TON per conveyor with the previous conveyor’s run bit as IN: Conv2 starts 3 s after Conv1 runs, Conv3 3 s after Conv2. Stop in reverse order with off-delays, so the material is cleared.

Timeout on a wait

Every “wait until the sensor is on” should have a timeout that raises a fault. A TON that starts when the step starts and is reset when the step ends, with the done bit moving to a fault state, prevents a stuck sensor from freezing the machine.

Run-hours

A retentive timer, or a counter driven by a one-second clock bit, holds total run time. Counting seconds in a DINT holds 2 147 483 647 s, about 68 years, which is plenty; counting in an INT overflows after 9.1 hours.

Counters

CTU counts up on each rising edge of its count input CU; CTD counts down; CTUD does both. Q (done) is on when the count value CV reaches the preset PV. A reset input sets CV to zero. Because only the edge counts, holding the input on adds one count, not many.

Count bottles (one count per rising edge) and flag a full case at 24Bottle_SensorI0.7CTUCU = rungR = ResetPV = 24Q > Case_FullCase_CounterReset the count when the case has been moved onCase_FullCase_Counter.QCase_GoneI1.0ResetM1.0
A counter counting bottles to 24 and a rung that resets it when the case has left.
  • Retentive or not? Production counts you need after a power loss go in retentive memory; counters that are only part of a cycle should reset at start-up.
  • Reset on the same event that uses the done bit. Look at the edge of Q so the case-full signal fires once per case.
  • Bounce. A noisy sensor produces extra counts: use a filter, a hardware debounce, or a time-based gate.
  • Limits. A 16-bit counter holds 32 767 (signed) or 65 535 (unsigned). A running total needs a DINT.
  • Rate. A normal input is limited by the scan; use a high-speed counter input for fast signals (see the next section).

Measuring speed with a counter

A pulse counter measures speed if you count over a fixed time window: speed = counts ÷ window. A high-speed counter input does the counting in hardware, so the scan cannot miss pulses.

rpm = (counts ÷ pulses per revolution) × (60 ÷ window in seconds)

Worked example: an encoder on a motor shaft

  • A 1 000 pulse-per-revolution encoder gives 500 counts in a window of 100.0 ms.
  • Revolutions in the window: 500 ÷ 1 000 = 0.5, so rpm = 0.5 × (60 ÷ 0.1) = 300 rpm.
  • The resolution is one count: 1 ÷ 1 000 rev in 0.1 s = 0.6 rpm per count. A longer window gives a finer, but slower, reading.
  • A 3 000 rpm shaft makes 50 rev/s, or 50 000 pulses per second with this encoder: far beyond a normal input (about 29 per second), so it needs a high-speed counter.
  • In a PLC with a scan, read the counter every 100 ms (a periodic task or a timer), subtract the previous value, and handle the rollover when the counter wraps.

Data types

TypeSizeRange (or precision)Platform names
BOOL1 bit0 or 1BOOL; bit; X; M; B
SINT / USINT8 bits−128 to 127 / 0 to 255SINT, Byte
INT / UINT16 bits−32 768 to 32 767 / 0 to 65 535Logix INT, S7 Int/UInt, Mitsubishi word, Unitronics MI
DINT / UDINT32 bits−2 147 483 648 to 2 147 483 647 / 0 to 4 294 967 295Logix DINT (the default), S7 DInt, Unitronics ML
REAL32 bitsIEEE 754 single: about 7 significant digitsLogix REAL, S7 Real, Unitronics MF
LREAL64 bitsIEEE 754 double: about 15–16 digitsS7 LReal, CODESYS LREAL
WORD / DWORD16 / 32 bitsBit strings for flags and masksWord, DWord
TIMEvariesT#5s, T#1h30m (stored in ms on most platforms)TIME; Logix timers use DINT milliseconds
STRINGvariesText, with a length limitSTRING; S7 String[254]

Number gotchas

  • Integer overflow. A 16-bit INT wraps or faults past 32 767. Counting seconds in an INT overflows after 32 767 s = 9.1 hours. Multiplying a raw analog value of 27 648 by 100 gives 2 764 800, which does not fit: convert to DINT or REAL first.
  • Integer division truncates. 7 ÷ 2 is 3 in integer math. Convert to REAL first when you need the fraction, and multiply before dividing to keep precision.
  • Timer range. A 32-bit millisecond count tops out at 2 147 483 647 ms, about 24.9 days. Count minutes or use a clock for longer.
  • REAL loses small increments on large totals. A 32-bit REAL has a 24-bit mantissa, so once the total is large enough, adding a small number does nothing.
  • Never compare REAL values with “=”. Test whether the difference is within a tolerance, or use greater-than and less-than.
  • Signed and unsigned. A raw analog value read as a signed 16-bit integer that is really unsigned (or the reverse) goes negative above 32 767; check the module’s data format.
  • Mixed types. Adding an INT to a REAL converts silently on some platforms and faults on others; convert explicitly.

Worked example: a flow totaliser that stops counting

  • A flow of 12.5 L/s is integrated every 10 ms scan: each scan adds 12.5 × 0.010 = 0.125 L to a REAL total.
  • A 32-bit REAL can represent steps no smaller than 2e−23 at a value near 2e. When the total reaches 221 = 2 097 152 L, the spacing between REAL values is 0.25 L, so adding 0.125 L rounds back to the same number: the total stops increasing.
  • At 12.5 L/s that happens after 167 772 s, about 46.6 hours: a long-running plant would see a totaliser that quietly stalls.
  • Cure: use LREAL (about 15 digits), or accumulate integer pulses from the flow meter in a DINT and convert to liters only for display, or keep a REAL for the fraction and a DINT for the whole liters.

Math, compare and scaling

InstructionDoesNotes
ADD, SUB, MUL, DIVArithmetic on integers or realsCheck overflow and divide-by-zero behavior
MODRemainderCycling a count through a range; every-nth-item logic
EQU, NEQ, GRT, GEQ, LES, LEQCompare two values (equal, not equal, greater, and so on)Output is a bit; use with hysteresis for analog control
MIN, MAX, LIMITClamp a value into a rangeProtect an output from out-of-range setpoints
SCALE / SCP / NORM_X and SCALE_XLinear scalingNames vary: Logix SCL/SCP, S7 NORM_X + SCALE_X, CODESYS structured text
CPT, CALCComputes an expressionLogix CPT, some Mitsubishi and IDEC math blocks

Analog values come into the program as raw counts and need scaling to engineering units: a straight-line conversion through two known points.

0.0 bar4.0 mA2.5 bar8.0 mA5.0 bar12.0 mA7.5 bar16.0 mA10.0 bar20.0 mA06 91213 82420 73627 648raw 20 736 = 16 mA = 7.5 barraw counts from the analog input cardEU = EU_low + (raw − raw_low) ÷ (raw_high − raw_low) × (EU_high − EU_low)A straight line through two known points: 0 counts = 4 mA = 0 bar, and 27 648 counts = 20 mA = 10 bar.
Scaling 0 to 27 648 counts to 4 to 20 mA and 0 to 10 bar. The marked point is the worked example.

EU = EUlow + (raw − rawlow) ÷ (rawhigh − rawlow) × (EUhigh − EUlow)

Worked example: a pressure transmitter

  • A 4–20 mA transmitter measures 0–10 bar, and the card gives 0 to 27 648 counts. The program reads raw = 20 736.
  • Fraction of span: 20 736 ÷ 27 648 = 0.75. Current: 4 + 16 × 0.75 = 16 mA. Pressure: 0.75 × 10 = 7.5 bar.
  • In structured text, convert to REAL before dividing: Pressure_bar := INT_TO_REAL(Raw) / 27648.0 * 10.0; Doing it in integers would truncate the result to a whole number.
  • Fault detection: raw below about −1 382 or above about 29 030 (4 mA minus 5 % and 20 mA plus 5 %) means a broken wire or an overrange: raise a fault instead of using the number.

Pump control with hysteresis

A comparator that turns a pump on below 40 % and off above 80 % needs two thresholds, so that the pump does not chatter around a single one. The ladder rung combines a “less than 40” test with a “less than 80 and already running” seal-in branch:

Pump control with hysteresis: starts below 40 %, stops above 80 % (Level is in percent)LESIN1 = LevelIN2 = 40.0PumpQ0.5LESIN1 = LevelIN2 = 80.0AutoI1.1PumpQ0.5
Hysteresis with two compare instructions: the pump starts below 40 % and keeps running until the level passes 80 %.

Bits, words and conversions

  • Masks and flags. A 16-bit word can hold 16 status bits. Status.0 addresses a single bit on many platforms; otherwise use AND with a mask (Status AND 16#0004 tests bit 2).
  • Shift and rotate move bits left or right: they multiply or divide by two, build shift registers for tracking items on a conveyor, and pack data.
  • BCD. Binary-coded decimal stores each digit in four bits; Mitsubishi, Omron and thumbwheel switches still use it. Convert with BCD_TO_INT and INT_TO_BCD; displaying a BIN number in a BCD display gives nonsense.
  • Word order for 32-bit values. A 32-bit number sent as two 16-bit words can arrive with the words swapped; a REAL read over Modbus often needs a word swap. See Modbus RTU, ASCII and TCP.
  • Strings and text use one byte per character, with length limits; build HMI messages with the platform’s string instructions.
  • Time and date. Real-time clock and date instructions give timestamps for logs; check time-zone and daylight-saving handling.

Related

FAQ

Why is my timer not timing?

Its input is not staying on long enough (it resets each time the input drops), the timer is in a routine that is not running, or the preset is in different units from what you expected. Go online and watch the accumulated value.

What is the difference between TON and a retentive timer?

A TON resets when its input goes off. A retentive timer (RTO, TONR) keeps its accumulated time and continues from there next time, until you reset it. Use it for run-hours and total on-time.

Why does my counter not count?

The input is a level, not an edge, that does not change; the counter instruction is in a rung that is not executed every scan; or the pulses are shorter than the scan. For fast pulses use a high-speed counter.

Should I use INT or DINT?

Use DINT unless memory is very tight or the protocol needs 16 bits. It avoids overflow problems, and on many platforms (Logix) it is also the native size and faster.

Why does my math give the wrong answer?

Usually integer truncation or overflow. Convert to REAL (or DINT) before multiplying, and divide last. Check each intermediate result.

References

  • IEC 61131-3, Programmable controllers, Part 3: Programming languages (standard function blocks TON, TOF, TP, CTU, CTD, CTUD).
  • IEEE 754-2019, Standard for Floating-Point Arithmetic.
  • Rockwell Automation, Logix 5000 Controllers General Instructions Reference Manual (timers and counters, data types).
  • Siemens, S7-1200 System Manual (IEC timers and counters, data types, NORM_X and SCALE_X).
  • Mitsubishi, Omron, IDEC and Unitronics instruction reference manuals for timer time bases.

Last reviewed: October 2026. Instruction names, addresses and data sizes differ by manufacturer: confirm against your controller’s manual, and keep safety functions independent of standard PLC logic.