CTUD is the IEC 61131-3 up/down counter function block: one instance counts up on the CU input and down on the CD input, reporting full (QU, CV ≥ PV) and empty (QD, CV ≤ 0) from a single current value.
Join 1900+ learners practicing PLC programming
How it works
CTUD merges CTU and CTD into a single stateful block, and it is the standard answer whenever a quantity moves in both directions: parts entering and leaving a buffer, cars in and out of a car park, pallets on and off a staging area. The block keeps one current value, CV. A rising edge on CU increments it; a rising edge on CD decrements it; edges on both in the same execution effectively cancel.
The pin set is worth memorizing because CODESYS, TIA Portal and every other IEC 61131-3 environment expose exactly the same interface. Inputs: CU (count up), CD (count down), R (reset — forces CV to 0, dominant over everything), LD (load — sets CV to PV), and PV (the preset). Outputs: QU, true while CV ≥ PV — the "full" flag; QD, true while CV ≤ 0 — the "empty" flag; and CV itself, which you can compare against intermediate thresholds for warnings. R dominating LD, and both dominating the count inputs, is specified behaviour — a held reset pins the counter at zero no matter what pulses arrive.
Because CTUD is a function block, every use needs its own instance (a variable of type CTUD in CODESYS; an instance DB in TIA Portal). The instance is the memory — declare one counter per physical quantity you are tracking, and call it every cycle in a task that runs often enough to catch your fastest pulse edges. Calling a CTUD conditionally, so that scans skip it while counts arrive, is a classic source of missed edges.
Allen-Bradley programmers searching for a CTUD in Studio 5000 ladder will not find one: the Logix idiom is a CTU instruction and a CTD instruction addressing the same counter tag, giving one shared ACC — with the caveat that the single DN bit only covers the "full" side (ACC ≥ PRE) and an explicit compare is needed for "empty". Mitsubishi FX hardware covers the same need with its bidirectional 32-bit counters (C200–C234), whose direction is flipped by the matching special relay M8200–M8234.
Across vendors
| Platform | Name / syntax | Notes |
|---|---|---|
| IEC 61131-3 (CODESYS, OpenPLC) | CTUD FB | Standard block: CU, CD, R, LD, PV → QU, QD, CV. R dominates LD; both dominate counting. One instance per counter. |
| Siemens (TIA Portal) | CTUD | Same IEC block with an instance DB. Available in LAD, FBD and SCL; S7-1200/1500 native. |
| Allen-Bradley (Studio 5000) | CTU + CTD pair | No single CTUD ladder instruction — put CTU and CTD on the same counter tag. Shared ACC; DN covers only ACC ≥ PRE, so detect empty with LEQ ACC 0. |
| Mitsubishi (GX Works) | C200–C234 | FX-series 32-bit bidirectional counters; the paired special relay M82xx selects count direction (off = up, on = down). |
CTUD is where the IEC world is genuinely more convenient than Logix: full and empty flags come standard, and the load/reset priority is defined by the standard rather than by your rung order.
In practice
| Entry_Loop ........................... CTUD Park | |----] [------------------------------------[ CU ]-| | Exit_Loop | |----] [------------------------------------[ CD ]-| | Attendant_Reset | |----] [------------------------------------[ R ]-| | [ PV 120 ]-|
The entrance loop detector pulses CU, the exit loop pulses CD, and CV is the number of cars inside. QU (CV ≥ 120) lights the FULL sign and holds the entry barrier; QD confirms the park is empty for the overnight sweep; the attendant’s reset re-zeros after a manual recount. Intermediate signage ("spaces: 120 − CV") reads CV directly — the block is as much a live gauge as a counter.
| Infeed_Eye CTUD Buff | |----] [------------------------------------[ CU ]-| | Outfeed_Eye | |----] [------------------------------------[ CD ]-| | [ PV 8 ]-| | Buff.QU Stop_Infeed | |----] [-----------------------------------------( )-----| | Buff.QD Stop_Outfeed | |----] [-----------------------------------------( )-----|
An accumulation buffer decouples two machines running at different speeds. QU (buffer full at 8) pauses the infeed conveyor; QD (buffer empty) pauses the outfeed so it never runs dry against a starved zone. Both flags come from one instance tracking one truth — with a CTU/CTD pair on separate counters, keeping the two accumulators honest against each other becomes its own maintenance problem.
This is also the pattern where negative-count alarms earn their keep: if CV drifts negative, an eye is double-counting or a part left the universe. Alarm on it rather than clamping it silently.
Gotchas
Calling the CTUD conditionally
A function block only sees edges on the executions where it is called. Wrap the call in an IF that skips it and pulses arriving during the skip are lost. Call the instance every cycle and gate the logic with its pins instead.
Reusing one instance for two quantities
The instance IS the counter. Wiring two different sensors pairs into one CTUD instance across different program sections merges two physical quantities into one meaningless CV.
Expecting Logix to have a CTUD ladder instruction
Studio 5000 ladder has CTU and CTD but no combined CTUD — the idiom is both instructions on one counter tag. Port IEC code without noticing and you will hunt for a block that does not exist, or worse, implement two independent counters that drift apart.
Using QU/QD when the threshold is neither full nor empty
QU and QD only report CV ≥ PV and CV ≤ 0. Warnings at "2 short of full" or "3 above empty" are comparisons against CV — put them in explicit GEQ/LEQ logic rather than fudging PV.
Simultaneous CU and CD confusion
Edges on both inputs in the same cycle leave CV unchanged (increment plus decrement), which is correct — but if the two sensors can genuinely fire together, consider whether the physics allows it or whether one eye is misaligned.
Drop the instruction on a rung in the browser simulator, toggle the inputs, and watch the rung state, accumulator values and outputs update scan by scan.
Questions
CTUD is the IEC 61131-3 up/down counter function block. One instance keeps a current value CV that increments on rising edges of the CU input and decrements on rising edges of CD. It outputs QU (true while CV ≥ PV, the full flag), QD (true while CV ≤ 0, the empty flag) and CV itself. R resets CV to zero; LD loads CV with the preset PV.
Declare an instance (myCounter : CTUD;), call it each cycle — myCounter(CU := EntrySensor, CD := ExitSensor, R := ResetBtn, PV := 100) — and read myCounter.CV, .QU and .QD. Reset dominates load, and both dominate the count inputs. The block must be called every cycle or edges arriving while it is skipped are missed.
Not as a single ladder instruction. The Logix pattern is a CTU and a CTD addressing the same counter tag, sharing one ACC. Note the DN bit then only means ACC ≥ PRE (the full side); detecting empty requires an explicit comparison such as LEQ Counter.ACC 0. Structured Text in Logix does let you use CTUD from the IEC-style libraries where available.
QU is the count-up done flag: true while the current value CV is at or above the preset PV — the buffer/park/zone is full. QD is the count-down done flag: true while CV is at or below zero — the zone is empty. They can never be true simultaneously unless PV is 0.