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:

CounterFull NamePurpose
CTUCount UpIncrements on each rising edge
CTDCount DownDecrements on each rising edge
CTUDCount Up/DownCombines 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_VAR

Counter(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 only
  • RESET: Sets CV back to 0
  • PV: Preset value (target count)
  • Q: TRUE when CV >= PV
  • CV: Current count value
  • CTD — 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_VAR

    DownCounter(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 edge
  • LOAD: Loads PV into CV (resets to full)
  • Q: TRUE when CV <= 0
  • Useful for inventory tracking, magazine feeders, and remaining-cycle counters
  • CTUD — 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_VAR

    Buffer( 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_VAR

    GoodCounter(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

  • Forgetting edge detection — Counters count on rising edges. If your input stays TRUE, it only counts once.
  • Not resetting — Always provide a reset mechanism, especially for CTU counters in continuous production.
  • Overflow — INT counters max out at 32767. For large counts, use DINT or LINT.
  • Using counters as timers — Counters count events, not time. Use TON/TOF for time-based logic.
  • 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.