Problem Statement: Monitoring 20 Elevator Belts with One Timer Block
A common S7 SCL question is: "Can a single timer instance drive 20 independent belt-rotation watchdogs?" The short answer is no. A TIMER or IEC timer instance is a binary state container — it can only hold one running value, one elapsed value, and one output bit at a time. Calling the same timer from twenty parallel logic branches creates scan-race conditions, residual values from the previous branch, and unpredictable STAT outputs.
This article walks through three field-proven patterns for reusing timer logic across many monitored devices:
- Multi-instance Function Block (SFB4 / TON) — the canonical Siemens answer.
- Counter-based emulation using OB35 100 ms pulses — the original poster's working solution.
- IEC_TON / TP inside a re-instantiable FB on S7-1200/1500 in TIA Portal — the modern equivalent.
All three patterns share one principle: the timer state must live in its own background DB (instance DB), one per monitored device, never shared.
Why a Single S5TIME / IEC Timer Cannot Be Reused
Each call to S_ODT, S_PULSE, S_PEXT, or S_ODTS writes to a fixed word-addressable timer word (T0..T2047 on S7-300/400, T0..T511 on S7-1200). The timer word contains the BCD-encoded time base, the time value, and the output bit. Two concurrent invocations of the same timer word overwrite each other every scan.
According to the SIMATIC S7-1200 manual on Timer Operation (IEC Timers), each IEC timer block (TP, TON, TOF, TONR) is a system function block (SFB3 / SFB4 / SFB5) that requires a dedicated instance DB holding the running elapsed time ET and the output Q. Reusing one instance DB is not supported and produces undefined behavior on overflow of the internal time accumulator.
Three documented options exist:
- Pass the timer as an in-out parameter and instantiate 20 separate instance DBs at the call site.
- Create a re-instantiable FB and instantiate it 20 times (multi-instance pattern).
- Replace the hardware/software timer with a software counter driven by a fixed clock OB.
Prerequisites
- STEP 7 V5.x (S7-300/400) or TIA Portal V16+ (S7-1200/1500).
- SCL compiler enabled (Options → Package Manager → SCL).
- For pattern 1/2: at least 20 unused timer words in the system data, or 20 unused IEC timer instance DBs.
- For pattern 3: OB35 (cyclic interrupt) configured to 100 ms in the CPU properties (Hardware → Cyclic Interrupts).
- Familiarity with FB/DB creation and multi-instance capability of the CPU (any S7-300/400/1200/1500 supports multi-instances).
Pattern 1: Multi-Instance FB with SFB4 (S_ODTS / TON)
The cleanest pattern is to wrap the timer inside a re-instantiable FB. Each call to the FB automatically allocates a new instance DB holding the timer state.
FB definition (S7-300/400 SCL)
FUNCTION_BLOCK FB_BeltWatchdog
VAR_INPUT
Run : BOOL; // motor running feedback
Pulse : BOOL; // one pulse per motor revolution
Preset_ms : INT; // timeout in milliseconds
END_VAR
VAR_OUTPUT
Alarm : BOOL; // TRUE if no pulse within Preset_ms
END_VAR
VAR
TonInst : SFB4; // IEC "TON" – multi-instance capable
ET_ms : INT; // elapsed time in ms (sampled)
xEdge : BOOL; // rising edge memory
END_VAR
BEGIN
// TON: output Q high when IN has been TRUE for PT duration
TonInst(IN := Run AND NOT Pulse,
PT := DINT_TO_TIME(INT_TO_DINT(Preset_ms)),
Q := Alarm);
END_FUNCTION_BLOCK
OB1 call site
DATA_BLOCK DB_Belt_01 FB_BeltWatchdog; BEGIN END_DATA_BLOCK;
DATA_BLOCK DB_Belt_02 FB_BeltWatchdog; BEGIN END_DATA_BLOCK;
... (repeat 20 times) ...
// OB1 – cyclic
FB_BeltWatchdog.DB_Belt_01(Run := "Mot01_Run", Pulse := "Mot01_RevPulse", Preset_ms := 8000);
FB_BeltWatchdog.DB_Belt_02(Run := "Mot02_Run", Pulse := "Mot02_RevPulse", Preset_ms := 8000);
...
Each DB_Belt_NN is a true instance DB and contains its own SFB4 state. The timer word is allocated automatically by the SFB4 instance — no manual T-number management required. This is the method Siemens officially recommends in the SiePortal "Timer in SCL" thread and in the S7-1200/1500 system manual.
FB_ElevatorBank containing 20 static FB_BeltWatchdog variables — only one IDB for the whole bank. This scales better than 20 separate DBs and is preferred for plants with hundreds of monitored devices.Pattern 2: OB35 Counter Emulation (Original Working Solution)
When the CPU has no spare SFB4 instances, or you want a fully software-defined timer independent of T-numbers, replace the timer with a down-counter clocked by OB35. The original poster's FB_CHECKTURN_ELEVATOR uses exactly this technique. Cleaned up and ported to modern SCL:
OB35 configuration (100 ms)
Open Hardware → CPU Properties → Cyclic Interrupts. Set OB35 execution time to 100 ms. The OB35 priority (default 12) pre-empts OB1, guaranteeing the 100 ms tick is consistent regardless of OB1 scan time.
OB35 – clock flag generator
// OB35 (priority 12, 100 ms)
"Clock_100ms" := NOT "Clock_100ms"; // 50% duty, 100 ms period
FB_CHECKTURN_ELEVATOR (SCL, S7-300/400-compatible)
FUNCTION_BLOCK FB_CHECKTURN_ELEVATOR
VAR_INPUT
PV : WORD; // preset in 100 ms units (e.g., 80 = 8 s)
CV_I : WORD; // retained counter value (in)
PULS : BOOL; // motor revolution pulse
RUN : BOOL; // motor running feedback
BITM_I : BOOL; // edge memory (retained)
END_VAR
VAR_OUTPUT
STAT : BOOL; // alarm
CV_O : WORD; // retained counter value (out)
BITM_O : BOOL; // edge memory (out)
END_VAR
VAR
CV : INT;
xEdge : BOOL;
END_VAR
BEGIN
// Load retained value or reset on stop / pulse
IF NOT RUN OR PULS THEN
CV := WORD_TO_INT(PV);
ELSE
CV := WORD_TO_INT(CV_I);
END_IF;
// 100 ms rising-edge detection
xEdge := "Clock_100ms" AND NOT BITM_I;
BITM_O := "Clock_100ms";
IF xEdge THEN
IF RUN THEN CV := CV - 1; END_IF;
IF CV < 0 THEN CV := 0; END_IF;
END_IF;
STAT := (CV = 0);
CV_O := INT_TO_WORD(CV);
END_FUNCTION_BLOCK
Why the retained values matter
Because OB35 is a separate priority class, the FB's read-modify-write of CV must use the value persisted in the instance DB at the end of the last call. Inputs CV_I / BITM_I and outputs CV_O / BITM_O are passed by the caller so the values survive OB35 restarts. The example shown by the original poster implements exactly this retention through the instance DB.
CV_O = CV_I on the same call does not work in a single-pass FB: the new value would be written before other instances read the old one, causing skew between belts. Always commit via the instance DB at the end of OB35, and read it at the start.Pattern 3: Modern IEC Timer in TIA Portal (S7-1200/1500)
On S7-1200 firmware V4.0+ and S7-1500, the IEC timer blocks are first-class citizens of the SCL language. The cleanest reuse pattern uses the multi-instance FB approach with a system IEC timer:
FUNCTION_BLOCK FB_BeltWatchdog_1200
VAR_INPUT
Run : BOOL;
Pulse : BOOL;
PresetTime : TIME; // e.g., T#8s
END_VAR
VAR_OUTPUT
Alarm : BOOL;
END_VAR
VAR
Ton_Inst : IEC_TIMER; // TON, TP, TOF, or TONR
Ton_DB : IEC_TON_DB; // background DB type, allocated by SCL
END_VAR
BEGIN
Ton_Inst(IN := Run AND NOT Pulse,
PT := PresetTime,
Q := Alarm);
END_FUNCTION_BLOCK
Compile and call the FB twenty times — TIA Portal automatically generates twenty distinct instance DBs of type FB_BeltWatchdog_1200, each containing its own IEC_TON_DB. No manual T-number bookkeeping, no OB35 needed, no CPU priority tuning.
Parameter Reference: Timer-Type Selection
| Timer type | Block | Behavior | Belt-watchdog fit |
|---|---|---|---|
| TP – pulse | SFB3 / IEC_TP | Q high for fixed PT, retriggerable | Poor (does not latch) |
| TON – on-delay | SFB4 / IEC_TON | Q high after IN true for PT | Best for this use case |
| TOF – off-delay | SFB5 / IEC_TOF | Q stays high PT after IN false | Good alternative |
| TONR – retentive on-delay | SFB6 / IEC_TONR | Accumulates; reset via R input | OK; needs explicit reset |
| S_ODT / S5TIME | Classic | BCD-encoded, max 9 990 s | Legacy only |
| OB35 down-counter | User code | Counts 100 ms ticks, no SFB | CPU without spare timers |
Verification Procedure
- Offline compile. In STEP 7 / TIA Portal, compile the SCL source. Expect 0 errors. Warnings about "timer not used" should be ignored if the timer is hidden inside the FB.
- Cross-reference. Run PLC → Monitor/Modify → Cross References on the FB name. Confirm 20 unique instance DBs, each referencing exactly one timer word or one IEC_TON_DB.
-
Online force PULS low. With the motor running, force PULS = FALSE on one belt. Verify that
STATtransitions TRUE withinPV × 100 ms(OB35 pattern) orPresetTime(IEC timer pattern). -
Online force PULS high. Verify that
STATclears on the next pulse and the counter reloadsPV. - Load distribution check. In OB35 mode, set PV to a known value (e.g., 50 = 5 s) and observe CV_O in the instance DB decrementing once every 100 ms with "Clock_100ms" toggling.
- OB35 overrun check. In TIA Portal: Online → Diagnostics → Cycle Time. The OB35 measured time must be < configured time (100 ms) or the system raises OB80 (time error) and skips ticks. With 20 belts, OB35 runtime is typically < 1 ms, well within budget.
-
Restart test. Power-cycle the CPU (or STOP→RUN). Verify retained values
CV_O/BITM_Opersist when using the OB35 pattern with the instance DB marked Non-Retain = No (default for IDBs).
Common Pitfalls and Diagnostics
| Symptom | Likely cause | Fix |
|---|---|---|
| Alarm never asserts on any belt | PULS and RUN are inverted at I/O wiring | Cross-check with the motor's encoder; trace Run AND NOT Pulse in monitor |
| All 20 belts alarm simultaneously | One shared timer word re-used (no multi-instance) | Convert to multi-instance FB or 20 unique instance DBs |
| OB80 "time error" CPU diagnostic | OB35 runtime > 100 ms, or OB35 disabled | Reduce OB35 logic; verify OB35 is loaded in CPU |
| CV counter drifts across belts | OB35 priority pre-empted by OB1 in user-modified priority schema | Do not lower OB35 priority below 12 |
| Timer overflow at 9 990 s (S5TIME legacy) | S5TIME 16-bit BCD limit | Switch to IEC_TON with TIME datatype on S7-1200/1500 |
| TON Q flickers on a noisy pulse | Mechanical contact bounce on PULS input | Add 5 ms hardware filter or use IEC_TON with PT ≥ 50 ms |
| Multi-instance FB will not compile | Inside the FB, the IEC timer is declared as VAR_TEMP
|
Move to VAR / VAR_STATIC so the IDB retains it |
Migration: S5TIME to IEC_TIMER
Legacy S7-300/400 code frequently uses S_ODT(T_NO := T12, ...) with S5TIME values. When porting to S7-1200/1500:
- Replace
S5TIMEwithTIME(1.0 ns resolution;T#8sliteral). - Replace
T_NOparameter with a multi-instance variable of typeIEC_TIMER. - Convert
BI(BCD out) toET(elapsed TIME) —BIis removed in IEC blocks. - Confirm CPU firmware ≥ V4.0 (S7-1200) or V1.8 (S7-1500) for full IEC_TON support.
Field Notes and Recommendations
For plants of 20 to 50 monitored belts, the multi-instance FB pattern (Pattern 1 or 3) is the lowest-maintenance solution. It uses one timer SFB per FB instance, all allocated automatically, and the FB is fully re-usable across projects. Reserve Pattern 2 (OB35 counter) for very small CPUs where SFB4 instance count is constrained, or where the time base must be exact and independent of SFB4 scheduling jitter.
Avoid mixing patterns: do not call Pattern 1 and Pattern 2 against the same alarm tag, or the alarm semantics (latched vs. pulse) will differ between belts.
Document the time base — "PresetTime = T#8s means 8.0 s ± 1 OB35 tick" — in the FB header comment. Field engineers are frequently tripped up by OB35 pattern quantisation when an SFB TON would deliver 1 ms precision.
FAQ
Can a single S7 timer word (T12) really drive 20 independent alarms?
No. A timer word stores one running value, one output bit, and one BCD time base. Concurrent invocations overwrite each other. Use a multi-instance FB so each monitored device has its own instance DB, or use a counter clocked by OB35 at 100 ms.
What is the difference between SFB4 and IEC_TON in TIA Portal?
SFB4 is the legacy multi-instance capable on-delay timer for S7-300/400. IEC_TON is the equivalent on S7-1200/1500, declared as a variable of type IEC_TIMER inside a re-instantiable FB. Both produce the same Q-output semantics: Q goes high when IN has been true continuously for PT.
How do I set OB35 to 100 ms on a S7-300 CPU 315-2 PN/DP?
Open HW Config → CPU 315-2 PN/DP → Properties → Cyclic Interrupts. Set OB35 execution time to 100 ms, priority 12 (default). Save and download to the CPU. The OB35 will be called every 100 ms regardless of OB1 scan time.
What S5TIME value gives 8 seconds on a legacy S7-300?
S5TIME is BCD-encoded: time base 1 = 0.01 s, base 2 = 0.1 s, base 3 = 1 s, base 4 = 10 s. For 8 s use base 3 with value 8, i.e., W#16#3008. Note the maximum representable time is 9 990 s (base 4, value 999); for longer times migrate to IEC_TON with TIME datatype on S7-1200/1500.
Will the counter values survive a CPU STOP→RUN if the instance DB is non-retain?
Yes. S7 instance DBs (multi-instance or single) are non-volatile by default and retain their last written values across STOP→RUN transitions and power cycles, because the load memory is mirrored to work memory at startup. You only lose values if you mark the IDB as "Non-Retain" or call SFC 82 / SFC 83 to re-initialise the DB.