Function Blocks
PLC Counter Programming: CTU, CTD & CTUD Examples in Structured Text
Learn how to use CTU, CTD, and CTUD counters in Structured Text with practical industrial examples — from part counting to batch control.
Understanding PLC Counters
Counters are fundamental building blocks in PLC programming. The IEC 61131-3 standard defines three counter function blocks that every automation engineer must know:
| Counter | Full Name | Purpose |
|---|---|---|
| CTU | Count Up | Increments on each rising edge |
| CTD | Count Down | Decrements on each rising edge |
| CTUD | Count Up/Down | Combines both directions |
CTU — Count Up Counter
The CTU counter increments its CV (Current Value) each time the CU input sees a rising edge. When CV reaches the preset PV, the output Q goes TRUE.
PROGRAM PartCounter
VAR
PartSensor : BOOL := FALSE;
ResetButton : BOOL := FALSE;
Counter : CTU;
PartsCount : INT := 0;
BatchComplete : BOOL := FALSE;
END_VARCounter(CU := PartSensor, RESET := ResetButton, PV := 50);
PartsCount := Counter.CV;
BatchComplete := Counter.Q;
// When 50 parts counted, signal batch complete
IF BatchComplete THEN
// Trigger conveyor stop, alert operator
END_IF;
Key Points for CTU
CU: Count input — increments on rising edge onlyRESET: Sets CV back to 0PV: Preset value (target count)Q: TRUE when CV >= PVCV: Current count valueCTD — Count Down Counter
The CTD counter decrements from a loaded value. It's ideal for tracking remaining items or countdown sequences.
PROGRAM MaterialTracker
VAR
ItemRemoved : BOOL := FALSE;
LoadParts : BOOL := FALSE;
DownCounter : CTD;
Remaining : INT := 0;
BinEmpty : BOOL := FALSE;
END_VARDownCounter(CD := ItemRemoved, LOAD := LoadParts, PV := 100);
Remaining := DownCounter.CV;
BinEmpty := DownCounter.Q;
IF BinEmpty THEN
// Request material refill
END_IF;
Key Points for CTD
CD: Count down input — decrements on rising edgeLOAD: Loads PV into CV (resets to full)Q: TRUE when CV <= 0CTUD — Count Up/Down Counter
The CTUD combines both directions, essential for tracking bidirectional processes like reversible conveyors or buffer zones.
PROGRAM BufferZoneTracker
VAR
ItemEnters : BOOL := FALSE;
ItemExits : BOOL := FALSE;
ResetCount : BOOL := FALSE;
LoadCount : BOOL := FALSE;
Buffer : CTUD;
ItemsInZone : INT := 0;
ZoneFull : BOOL := FALSE;
ZoneEmpty : BOOL := FALSE;
END_VARBuffer(
CU := ItemEnters,
CD := ItemExits,
RESET := ResetCount,
LOAD := LoadCount,
PV := 20
);
ItemsInZone := Buffer.CV;
ZoneFull := Buffer.QU; // TRUE when CV >= PV
ZoneEmpty := Buffer.QD; // TRUE when CV <= 0
IF ZoneFull THEN
// Stop infeed conveyor
ELSIF ZoneEmpty THEN
// Signal upstream to send more
END_IF;
Real-World Example: Production Batch Counter with Reject Tracking
Here's a more complete example combining multiple counters:
PROGRAM BatchProduction
VAR
GoodPartSensor : BOOL := FALSE;
RejectSensor : BOOL := FALSE;
NewBatchCmd : BOOL := FALSE;
GoodCounter : CTU;
RejectCounter : CTU;
GoodParts : INT := 0;
RejectParts : INT := 0;
TotalParts : INT := 0;
RejectRate : REAL := 0.0;
BatchDone : BOOL := FALSE;
END_VARGoodCounter(CU := GoodPartSensor, RESET := NewBatchCmd, PV := 1000);
RejectCounter(CU := RejectSensor, RESET := NewBatchCmd, PV := 100);
GoodParts := GoodCounter.CV;
RejectParts := RejectCounter.CV;
TotalParts := GoodParts + RejectParts;
BatchDone := GoodCounter.Q;
IF TotalParts > 0 THEN
RejectRate := INT_TO_REAL(RejectParts) / INT_TO_REAL(TotalParts) * 100.0;
END_IF;
// Alarm if reject rate exceeds 5%
IF RejectRate > 5.0 THEN
// Trigger quality alert
END_IF;
Common Mistakes with PLC Counters
Practice in Our Simulator
Try building a part counting system with our online PLC simulator. Start with a simple CTU, then add reject tracking with a second counter.