SCL Counter Functions: CTU, CTD, CTUD — Complete Reference
Complete reference for IEC counter function blocks in SCL: CTU (count up), CTD (count down), CTUD (count up/down). Syntax, parameters, examples, and S5 ZV/ZR migration notes.
SCL Counter Functions: CTU, CTD, CTUD — Complete Reference
The IEC 61131-3 standard defines three counter function blocks: CTU (count up), CTD (count down), and CTUD (count up and down). In Siemens SCL (TIA Portal), these replace the legacy S5/S7 counter functions (ZV, ZR, S_CU, S_CD) with a cleaner, more portable interface.
CTU — Count Up
CTU increments a counter value on each rising edge of the CU input. When the current value (CV) reaches or exceeds the preset value (PV), the output Q becomes TRUE.
Parameters:
| Parameter | Direction | Type | Description |
|---|---|---|---|
| CU | Input | BOOL | Count up — increments CV on rising edge |
| R | Input | BOOL | Reset — sets CV to 0 when TRUE |
| PV | Input | INT | Preset value — Q becomes TRUE when CV ≥ PV |
| Q | Output | BOOL | Done — TRUE when CV ≥ PV |
| CV | Output | INT | Current counter value |
SCL Example:
VAR
myCounter : CTU;
END_VAR
// Call the counter
myCounter(CU := "Count_Sensor",
R := "Reset_Button",
PV := 100);
// Use the outputs
"Batch_Complete" := myCounter.Q; // TRUE when 100 parts counted
"Parts_Count" := myCounter.CV; // Current count value
Behavior:
- Each rising edge on CU increments CV by 1
- When R = TRUE, CV is set to 0 and Q = FALSE
- Q becomes TRUE when CV ≥ PV and remains TRUE until reset
- CV continues counting beyond PV (no automatic stop at PV)
- CV range: 0 to 32767 (INT). For larger ranges, use data type DINT (S7-1500 only)
CTD — Count Down
CTD decrements a counter value on each rising edge of the CD input. When CV reaches 0, the output Q becomes TRUE.
Parameters:
| Parameter | Direction | Type | Description |
|---|---|---|---|
| CD | Input | BOOL | Count down — decrements CV on rising edge |
| LD | Input | BOOL | Load — sets CV to PV when TRUE |
| PV | Input | INT | Preset value — loaded into CV when LD = TRUE |
| Q | Output | BOOL | Done — TRUE when CV ≤ 0 |
| CV | Output | INT | Current counter value |
SCL Example:
VAR
myDownCounter : CTD;
END_VAR
myDownCounter(CD := "Part_Ejected",
LD := "Load_Batch",
PV := 50);
"Batch_Empty" := myDownCounter.Q; // TRUE when all 50 parts ejected
"Remaining" := myDownCounter.CV; // Remaining count
Behavior:
- LD loads PV into CV (like "preset" in legacy counters)
- Each rising edge on CD decrements CV by 1
- Q becomes TRUE when CV ≤ 0
- CV can go negative (no automatic stop at 0)
CTUD — Count Up and Down
CTUD combines both count directions in one function block. It has separate up and down inputs, separate done outputs for each direction, and both reset and load functions.
Parameters:
| Parameter | Direction | Type | Description |
|---|---|---|---|
| CU | Input | BOOL | Count up — increments CV on rising edge |
| CD | Input | BOOL | Count down — decrements CV on rising edge |
| R | Input | BOOL | Reset — sets CV to 0 |
| LD | Input | BOOL | Load — sets CV to PV |
| PV | Input | INT | Preset value |
| QU | Output | BOOL | Up done — TRUE when CV ≥ PV |
| QD | Output | BOOL | Down done — TRUE when CV ≤ 0 |
| CV | Output | INT | Current counter value |
SCL Example:
VAR
myBiCounter : CTUD;
END_VAR
myBiCounter(CU := "Part_In",
CD := "Part_Out",
R := "Reset_Count",
LD := FALSE,
PV := 200);
"Buffer_Full" := myBiCounter.QU; // TRUE when 200 parts in buffer
"Buffer_Empty" := myBiCounter.QD; // TRUE when buffer empty
"Buffer_Level" := myBiCounter.CV; // Current buffer level
Migration from S5 ZV/ZR to IEC Counters
| S5 Legacy | IEC Equivalent | Key Difference |
|---|---|---|
| ZV (Zähler vorwärts) | CTU | S5: BCD output, Q = CV > 0. IEC: INT output, Q = CV ≥ PV |
| ZR (Zähler rückwärts) | CTD | S5: Q = CV > 0. IEC: Q = CV ≤ 0 |
| S_CU (S7 legacy) | CTU | Functionally similar, S_CU uses BCD |
| S_CD (S7 legacy) | CTD | Functionally similar, S_CD uses BCD |
Critical difference: In S5, U Z n tests whether the counter is greater than zero (CV > 0). In IEC CTU, Q tests whether CV has reached the preset (CV ≥ PV). These are fundamentally different conditions. When migrating, you must adjust the logic accordingly.
For the detailed migration guide, see Migrating S5 Counter Programs to S7.
Availability by Platform
| Counter | S7-300/400 | S7-1200 | S7-1500 |
|---|---|---|---|
| CTU | ✅ | ✅ | ✅ |
| CTD | ✅ | ✅ | ✅ |
| CTUD | ✅ | ✅ | ✅ |
| DINT counters | ❌ | ❌ | ✅ |
Convert Your Counter Logic Automatically
PLCcheck Pro analyzes your S5/S7 counter code and generates IEC-compliant SCL equivalents with correct preset mapping and condition adjustments.
Upload code for counter conversion → | AWL to SCL Guide →
Part of the SCL Reference. Maintained by PLCcheck.ai. Not affiliated with Siemens AG.
Related Articles
Migrating S5 Counter Programs (Z/ZV/ZR) to S7
How to migrate S5 counter programs to S7. Covers ZV (count up), ZR (count down), BCD format differences, S7 equivalents (S_CU, S_CD, CTU, CTD, CTUD), and common pitfalls.
10 min read
migration-guideS5 to S7 Migration: The Complete Guide (2026)
Step-by-step guide for migrating Siemens S5 PLC programs to S7-1500. Covers AWL→SCL conversion, timer mapping, address translation, and hardware selection.
18 min read
migration-guideS5 Absolute Addressing vs. S7 Symbolic Addressing
Why S5 uses absolute addresses (E 0.0, MW 10, DB10.DW5) and S7 prefers symbolic names (Start_Button, Temperature, Motor.Speed). Migration strategy for converting absolute to symbolic.
8 min read
Analyze your PLC code with AI
PLCcheck Pro explains, documents, optimizes, and migrates PLC code — automatically.
Try PLCcheck Pro →Not affiliated with Siemens AG. S5, S7, STEP 5, STEP 7, and TIA Portal are trademarks of Siemens AG.