Timers and Counters: Controlling Time and Repetition on the Production Line
TON Timer: On-Delay
The TON (Timer On-Delay) is the most frequently used timer in industrial PLC programming. It starts timing when its input goes TRUE and produces a TRUE output only after the preset time has fully elapsed. If the input goes FALSE before the preset is reached, the timer resets to zero.
VAR
tonFillDelay : TON;
END_VAR
tonFillDelay(IN := bStartFilling, PT := T#3s);
IF tonFillDelay.Q THEN
bOpenValve := TRUE;
END_IF;
Common industrial uses for TON:
- Debouncing sensors: ignore brief false triggers from vibrating equipment (PT := T#50ms)
- Startup delay: wait 5 seconds after power-up before enabling outputs
- Sequential delays: pause between stages in a filling or packaging sequence
- Timeout detection: if a cylinder does not reach position within 10 seconds, trigger an alarm
TOF Timer: Off-Delay
The TOF (Timer Off-Delay) produces the opposite behavior of the TON. Its output goes TRUE immediately when the input goes TRUE, and stays TRUE for the preset time after the input goes FALSE.
VAR
tofConveyor : TOF;
END_VAR
tofConveyor(IN := bSensorDetectsProduct, PT := T#10s);
bConveyorMotor := tofConveyor.Q;
Common industrial uses for TOF:
- Conveyor run-on: keep the belt running for 10 seconds after the last product is detected
- Cooling fan: keep the fan running for 2 minutes after the heater turns off
- Lubrication pump: maintain oil flow for 30 seconds after the machine stops
TP Timer: Fixed-Duration Pulse
The TP (Timer Pulse) produces a fixed-duration output pulse when triggered. The output goes TRUE on the rising edge of the input and stays TRUE for exactly the preset time, regardless of the input state.
VAR
tpAlarmBuzzer : TP;
END_VAR
tpAlarmBuzzer(IN := bFaultDetected, PT := T#2s);
bBuzzer := tpAlarmBuzzer.Q;
Common industrial uses for TP:
- Alarm buzzer: sound for exactly 2 seconds when a fault occurs
- Pneumatic valve pulse: open a valve for 500ms to eject a product
- Signal pulse: generate a fixed-width pulse for a downstream counter
CTU: Count Up
The CTU (Count Up) counter increments by one on each rising edge of its count input. When the current value (CV) reaches or exceeds the preset value (PV), the output (Q) goes TRUE.
VAR
ctuBoxes : CTU;
END_VAR
ctuBoxes(CU := bBoxSensor, RESET := bResetCounter, PV := 12);
IF ctuBoxes.Q THEN
bDiverterActivate := TRUE;
ctuBoxes(RESET := TRUE);
END_IF;
Industrial uses for CTU:
- Batch counting: count 12 bottles, then activate a case packer
- Maintenance scheduling: count 10,000 cycles, then display a service reminder
- Production totals: track daily output on an HMI display
CTD: Count Down
The CTD (Count Down) counter decrements from a preset value toward zero on each rising edge of its count input. When CV reaches zero, the output goes TRUE.
VAR
ctdRemaining : CTD;
END_VAR
ctdRemaining(CD := bPartProduced, LOAD := bNewBatchStart, PV := 500);
IF ctdRemaining.Q THEN
bBatchComplete := TRUE;
END_IF;
Industrial uses for CTD:
- Batch remaining: load 500, count down each part, signal when the batch is complete
- Material tracking: load the number of blanks in a magazine, alert when empty
- Packaging: count down remaining labels on a roll, trigger a roll-change alarm
Some applications use both counters together. A warehouse conveyor might use CTU to count items entering a buffer zone and CTD to count items leaving. The difference gives the current number of items in the buffer.
Practical Example: Counting Produced Parts With Batch Delays
A packaging line has a photoeye sensor that detects each finished box. The system must count boxes until a batch of 24 is reached, pause the conveyor for 5 seconds to allow pallet exchange, then resume and start the next batch.
VAR
ctuBatch : CTU;
ctuTotalBatch : CTU;
tonPause : TON;
bBoxSensor : BOOL;
bConveyorRun : BOOL;
bPausing : BOOL;
nBatchCount : INT;
END_VAR
// Count boxes in current batch
ctuBatch(CU := bBoxSensor, RESET := bPausing AND tonPause.Q, PV := 24);
// When batch is full, start pause
IF ctuBatch.Q AND NOT bPausing THEN
bPausing := TRUE;
bConveyorRun := FALSE;
END_IF;
// Time the pause
tonPause(IN := bPausing, PT := T#5s);
// When pause is complete, resume
IF bPausing AND tonPause.Q THEN
bPausing := FALSE;
bConveyorRun := TRUE;
ctuTotalBatch(CU := TRUE, RESET := FALSE, PV := 9999);
nBatchCount := ctuTotalBatch.CV;
END_IF;
// Normal running state
IF NOT bPausing AND NOT ctuBatch.Q THEN
bConveyorRun := TRUE;
END_IF;
This program combines a CTU counter for batch detection, a TON timer for the pause delay, and a second CTU for tracking total production batches. The pattern of counting, pausing, and resuming is found in virtually every packaging and palletizing application.
Summary
IEC 61131-3 defines three timer types and two counter types that cover the vast majority of industrial timing and counting needs. TON provides an on-delay for startup sequences and timeouts. TOF provides an off-delay for run-on applications like conveyor clearing. TP generates fixed-duration pulses for alarms and dosing. CTU counts events upward for batch detection and production tracking, while CTD counts downward for remaining-quantity monitoring. Combining these blocks creates complete industrial sequences like the batch-counting packaging line demonstrated in this lesson.