PCS 7 Variable Preset Timer: Temperature-Based Shutdown FB
Siemens PCS 7 does not ship a stock function block that lets the operator change a timer's preset value (PV) while the timer is already running. That is a real problem for any application where the shutdown delay is a function of a live process variable such as temperature: as the process variable changes, the demand on the timer changes, and the system must re-target PV mid-flight without losing the already-accumulated elapsed time. The IEC 61131-3 timer blocks TP, TON, TOF, TONR and the legacy S5 instanced timers S_PULSE, S_ODT, S_ODTS, S_OFFDT, S_PEXT all latch the PV on the active edge. Subsequent writes to the PV input are ignored until the timer is re-started. This article documents a working pattern using a custom SCL function block (FB_VarDelay) that wraps the system tick counter SFC64 (TIME_TCK) and is fully compatible with PCS 7 CFC and the Advanced Process Library (APL).
Problem Details: Variable PV With Mid-Run Re-Arming
The scenario described in the source is a temperature-driven shutdown timer for a piece of process equipment. The user has a temperature transmitter (analog input scaled to engineering units) and wants the delay time before opening the shutdown valve or stopping the motor to be calculated from a formula such as:
-
Linear inverse:
T_delay = max(0, K1 - K2 · (T - T_ref)) -
Exponential decay:
T_delay = K · e^(-α·(T - T_ref)) -
Hyperbolic:
T_delay = K3 / (T - T_ref + ε)with ε a small positive constant to avoid divide-by-zero
The intent is that the delay shrinks as the temperature rises. The shutdown command is issued once (rising edge), but if the equipment continues to heat up after the command is issued, the user wants the new, shorter delay to take effect immediately, not to wait for the next start. Conversely, if the temperature drops back below the threshold, the user wants the timer to extend, not fire spuriously.
Three behaviors are required:
- Re-arm the comparison against the new PV without losing the already-accumulated elapsed time.
- If the new PV is shorter than the current elapsed value, the timer must fire immediately (i.e., re-trigger from the formula).
- If the new PV is longer, the timer must extend seamlessly with no glitch on the output.
None of the stock IEC or S5 timers in PCS 7 can do this.
Root Cause: How PV Latching Works in S7 Timers
IEC 61131-3 defines a timer abstractly as having inputs IN and PT and outputs Q and ET, with vendor-specific implementation. For Siemens IEC_TON in the STEP 7 Standard Library, the relevant semantics are:
| Block | Type | PV Latched? | Mid-Run PV Change Effective? |
|---|---|---|---|
IEC_TP |
Pulse | On IN rising edge | No |
IEC_TON |
On-delay | On IN rising edge | No |
IEC_TOFF |
Off-delay | On IN falling edge | No |
IEC_TONR |
Retentive on-delay | On IN rising edge | No |
S_PULSE (FB 100) |
Pulse | On IN rising edge | No |
S_ODT (FB 101) |
On-delay | On IN rising edge | No |
S_ODTS (FB 102) |
Latched on-delay | On IN rising edge | No |
S_OFFDT (FB 103) |
Off-delay | On IN falling edge | No |
S_PEXT (FB 104) |
Extended pulse | On IN rising edge | No |
The standard explanation is in the STEP 7 / TIA Portal documentation set for the Siemens Industry Online Support portal. Look for the "SIMATIC S7 Standard Functions" and "S7-1500/ET 200MP System Functions" reference manuals. Both list the same behavior: the PV input is sampled on the active edge and held in an internal word; re-writing the input word while the timer is running has no effect on the in-flight comparison.
The IEC 61131-3 standard is intentionally vendor-agnostic on this point. Section 6.4.3 of IEC 61131-3:2013 defines the timer state machine but does not mandate that PT be re-evaluated each cycle. Siemens has chosen the latched implementation for all of the blocks above, so the only escape hatch is a custom block.
Solution Architecture: FB_VarDelay Custom Function Block
The custom block is built around three principles:
-
PV is an input that is re-read every scan. The comparison
elapsed >= PVis done inside the block, not by a hardware timer. - Elapsed time is computed from a stored start tick. It is not incremented per scan, so scan-time jitter does not accumulate and OB1 vs OB35 placement is irrelevant for accuracy.
- A retrigger input allows the user's formula block to re-arm the timer automatically if PV drops below the currently-elapsed value (auto-retrigger on demand change).
Inputs and outputs:
| Direction | Name | Type | Meaning |
|---|---|---|---|
| IN | Start |
BOOL | Rising edge begins timing |
| IN | Reset |
BOOL | Forces output low, clears state |
| IN | PV_Time |
TIME | Variable preset, re-read every cycle |
| IN | AutoRetrig |
BOOL | Re-arm when PV < elapsed |
| OUT | Running |
BOOL | Timer is active |
| OUT | Done |
BOOL | Elapsed ≥ PV_Time since last start |
| OUT | Elapsed |
TIME | Time accumulated in current run |
| OUT | Remaining |
TIME | Time left (0 if Done) |
SCL Implementation (STEP 7 V5.6 / TIA Portal)
The following source is valid SCL for both STEP 7 V5.6 (used with PCS 7 V8.x) and TIA Portal V16+ (used with PCS 7 V9.x / AS 410). Place the FB in the AS master data block program so it can be instantiated multiple times in CFC charts.
FUNCTION_BLOCK FB_VarDelay
{ S7_m_c := 'true' ; S7_tasklist := 'OB1' }
TITLE = 'Variable Preset On-Delay'
VERSION : '1.0'
AUTHOR : 'PCS7-Eng'
FAMILY : 'PCS7_Custom'
VAR_INPUT
Start : BOOL; // Rising edge begins timing
Reset : BOOL; // Forces output low, clears state
PV_Time : TIME; // Variable preset, re-read every cycle
AutoRetrig : BOOL := FALSE; // Re-arm when PV drops below elapsed
END_VAR
VAR_OUTPUT
Running : BOOL; // Timer is active
Done : BOOL; // Elapsed >= PV_Time since last start
Elapsed : TIME; // Time accumulated in current run
Remaining : TIME; // Time left until done (0 if Done)
END_VAR
VAR
StartEdge : BOOL;
RunState : BOOL;
DoneState : BOOL;
tStartD : DWORD; // SFC64 value at last start
tNowD : DWORD; // SFC64 value this scan
tDiffD : DWORD; // unsigned delta, wraps modulo 2^32
ElapsedMs : DINT; // elapsed in ms, signed
PvMs : DINT; // PV in ms
RemainingMs : DINT;
END_VAR
VAR_TEMP
retVal : DWORD;
END_VAR
BEGIN
// ---- 1) Reset has priority ----
IF Reset THEN
RunState := FALSE;
DoneState := FALSE;
StartEdge := FALSE;
ElapsedMs := 0;
END_IF;
// ---- 2) Read system tick (SFC64 / TIME_TCK) ----
retVal := TIME_TCK();
tNowD := retVal;
// ---- 3) Edge detection on Start ----
IF Start AND NOT StartEdge THEN
RunState := TRUE;
DoneState := FALSE;
tStartD := tNowD;
ElapsedMs := 0;
StartEdge := TRUE;
ELSIF NOT Start THEN
StartEdge := FALSE;
END_IF;
// ---- 4) Run logic: re-read PV every scan, recompute elapsed ----
IF RunState THEN
// Unsigned DWORD subtraction handles the 32-bit wrap correctly
tDiffD := tNowD - tStartD;
IF tDiffD > DWORD#16#7FFFFFFF THEN
ElapsedMs := 2147483647; // saturate to max DINT
ELSE
ElapsedMs := DWORD_TO_DINT(tDiffD);
END_IF;
PvMs := TIME_TO_DINT(PV_Time);
IF ElapsedMs >= PvMs THEN
DoneState := TRUE;
RunState := FALSE;
ELSIF AutoRetrig AND (PvMs < ElapsedMs) THEN
// PV dropped below current elapsed - re-arm
tStartD := tNowD;
ElapsedMs := 0;
END_IF;
END_IF;
// ---- 5) Outputs ----
Running := RunState;
Done := DoneState;
Elapsed := DINT_TO_TIME(ElapsedMs);
IF RunState THEN
RemainingMs := PvMs - ElapsedMs;
IF RemainingMs < 0 THEN
RemainingMs := 0;
END_IF;
Remaining := DINT_TO_TIME(RemainingMs);
ELSE
Remaining := T#0s;
END_IF;
END_FUNCTION_BLOCK
Notes on the SCL
-
TIME_TCKis SFC64 and must only be called in OB1, OB35, OB82 (diagnostic), OB121/OB122 handlers, or in CFC/SFC charts placed in OB1/OB35. Do not call it in OB100 (warm restart). -
TIME_TCKreturns a 32-bit tick. On SIMATIC S7-400 CPUs the tick period is 10 ms. On SIMATIC S7-1500 CPUs the tick period is 1 ms. This is documented in the "S7-300/400 Standard Functions" and "S7-1500 System Functions" reference manuals. The block treats the tick as milliseconds, which is correct for S7-1500 and off by 10× for S7-400; scaleElapsedaccordingly or compute the period in a CPU-type conditional. -
DINT_TO_TIMEandTIME_TO_DINTare standard SCL conversion functions. They treat the DINT as signed milliseconds; safe for our range. - The attribute
{ S7_m_c := 'true' }declares the FB as multi-instance capable, which is required for use in PCS 7 CFC charts where the block is instantiated multiple times in one chart or in a chart family. - The attribute
{ S7_tasklist := 'OB1' }tells the SCL compiler the FB may be called in OB1, allowing more efficient code generation.
Temperature Formula and REAL-to-TIME Conversion
The PV input to FB_VarDelay is of type TIME (32-bit signed milliseconds), but the formula block typically operates in REAL (engineering units, e.g. seconds). A small FC bridges the two:
FUNCTION FC_RealSecToTime : TIME
VAR_INPUT
Seconds : REAL;
END_VAR
VAR_TEMP
ms : DINT;
END_VAR
BEGIN
IF Seconds <= 0.0 THEN
FC_RealSecToTime := T#0s;
ELSIF Seconds > 2147483.0 THEN
// T#24d20h31m23s647ms limit
FC_RealSecToTime := DINT_TO_TIME(2147483647);
ELSE
ms := REAL_TO_DINT(Seconds * 1000.0);
FC_RealSecToTime := DINT_TO_TIME(ms);
END_IF;
END_FUNCTION
A reference formula block in SCL:
FUNCTION_BLOCK FB_DelayFormula
VAR_INPUT
Temperature : REAL; // degC
T_ref : REAL := 60.0;
K1 : REAL := 120.0; // seconds at T_ref
K2 : REAL := 2.0; // s/degC slope
T_min : REAL := 5.0; // minimum clamp, seconds
END_VAR
VAR_OUTPUT
DelayTime : TIME;
END_VAR
VAR
raw : REAL;
END_VAR
BEGIN
raw := K1 - K2 * (Temperature - T_ref);
IF raw < T_min THEN
raw := T_min;
ELSIF raw > K1 THEN
raw := K1;
END_IF;
DelayTime := FC_RealSecToTime(raw);
END_FUNCTION_BLOCK
For an exponential-decay formulation, replace the linear term with raw := K1 * EXP(-K2 * (Temperature - T_ref)). The EXP function is available in the SCL standard library under "Floating-point math functions".
CFC Wiring and Operator Display
In a PCS 7 CFC chart, the typical connection topology is:
The chart is compiled into the AS master data block. The OS faceplate for the timer block exposes the live values of PV_Time, Elapsed, Remaining, and Done. Standard PCS 7 faceplate techniques (WinCC faceplate designer, type FB_VarDelay as a "block icon with S7-m-c = true") allow the operator to see the timer counting down in real time. The faceplate can also expose an override toggle: a BOOL input wired to the formula block's bypass that forces Done := TRUE immediately, used for emergency shutdowns.
Verification and Commissioning Tests
Five tests are mandatory after wiring. Run them in S7-PLCSIM (PCS 7 simulation) or against the live AS with the chart in online test mode.
-
Static PV test. Force
PV_Time = T#10s, pulseStart = TRUE.Elapsedshould increment at the tick rate, andDoneshould fire at 10 s ± 1 tick. -
PV-down test (AutoRetrig = TRUE). Set
PV_Time = T#60s, start, wait 30 s, then dropPV_Time = T#5s. The block should re-arm:Remainingdrops to ~5 s andDonefires ~5 s later (total elapsed ≈ 35 s). -
PV-down test (AutoRetrig = FALSE). Same conditions, but
AutoRetrig = FALSE.Remainingdrops to 5 s andDonefires at ~35 s without re-arming, exactly as the latched timer would, except the elapsed time is preserved. -
PV-up test. Set
PV_Time = T#20s, start, wait 5 s, then raisePV_Time = T#90s.Remainingjumps from 15 s to 85 s,Donefires ~85 s later. No glitch on theDoneoutput during the change. -
Reset test. Assert
Reset = TRUEwhileRunning = TRUE. All outputs go low,Elapsed = T#0s,Donefalls, no spurious re-fire on the next scan. -
Wrap test (S7-1500 only). In S7-PLCSIM, use the SFC64 test API to force
tStartDnear 0xFFFFFFFE. After one tick,tDiffshould equal 2 (not a huge negative number); the unsigned subtraction must handle the wrap. -
Scan-time independence test. Place the FB call in OB1 (typical 100 ms cycle) and OB35 (1 s cycle). Both must give the same
Donetiming to within ±1 tick of the tick period.
The online test is available in the CFC editor (right-click → "Test mode") or via the S7-PLCSIM "Sequence" view, both of which are documented in the PCS 7 commissioning manual on the Siemens Industry Online Support portal.
Edge Cases and Safety Patterns
-
Sensor break / negative temperature. If
Temperature < T_ref, the formula block should clamp the output toT#0sor to a configured minimum. The shutdown command will then be honored immediately on the next scan, which is the correct fail-safe behavior. -
PV = 0.
Donefires on the same scan thatStartis recognized. The code setsRunState := FALSEandDoneState := TRUEin the same pass, which is a one-shot behavior. This is intentional and is the correct interpretation of a zero-delay demand. -
PV update faster than tick. If the upstream formula block updates
PV_Timeevery 10 ms and the user's logic checks every 1 ms on S7-1500, there is no race. The comparison iselapsed >= PV(not equality), and the block cannot "miss" a transient demand. -
Operator override. Add a
bypassBOOL that forcesDone := TRUEandRunning := FALSEwithout going through the timer. The formula block still updatesPV_Time, but the override wins. Wire it to the PCS 7 mode selector in the faceplate. -
Mode handling. When the operator puts the unit in "Maintenance" or "Out of Service", gate
Startfrom issuing a shutdown by AND-ing with the PCS 7MODE_INinput from the APL operator block. -
Multi-instance discipline. Always declare the FB as multi-instance (
S7_m_c := 'true') and place instance DBs in the AS master data block. Avoid DB-of-FB patterns that fragment the S7 memory model and complicate online modifications. -
AS 410 redundancy. On a fault-tolerant AS 410 H system,
SFC64returns the local CPU's tick. Both H-CPUs are synchronized to within ~10 ms, so a hot-standby failover during a run will cause at most one tick of jitter onElapsed. This is acceptable for process-grade shutdown timing; for sub-tick precision, use a separate high-resolution clock from an external timer module. -
Force / simulate. PCS 7 force tables and "simulate variable" CFC functions bypass the formula block. When the operator simulates a temperature value, the simulation must update
PV_Timein lockstep; otherwise the user can observeRemainingjumping in unexpected ways. Test force-mode operation explicitly.
Performance and Scan-Time Considerations
The FB_VarDelay block is intentionally lean:
-
TIME_TCKis a system call that takes ~5–20 µs of CPU time per invocation on AS 410. Calling it once per FB is fine. Avoid calling it multiple times per scan in the same FB to keep determinism. - The block uses ~150 bytes of work memory and ~50 bytes of load memory per instance, comparable to
IEC_TONR(FB 4) in the standard library. - The SCL compiler optimizes the DWORD subtraction and conditional into a single SUB DWORD plus a comparison, so the wrap-around case does not require a branch in the common path.
- On an AS 410 (CPU 410-5H),
FB_VarDelaycan be instantiated 200+ times in a single chart with no measurable scan-time impact. - If the block is placed in OB35 (1 s cyclic interrupt), it is called once per second and
Elapsedresolution is 1 s. For sub-second timing, place it in OB1 (or in OB32, OB33, OB34 with appropriate cycle time). PCS 7 normally places all chart logic in OB1.
Alternative Implementations Compared
| Approach | Pros | Cons |
|---|---|---|
| FB_VarDelay (recommended) | Variable PV, runtime-safe, scan-time independent, retrace | New block to validate, requires SCL |
| Counter-based FC (CTU + clock bit) | Uses only stock blocks | PV changes are not smoothly tracked, clock-bit granularity (e.g. 1 s) limits resolution |
| IEC_TONR with PV re-write | No custom code | Documented to ignore mid-run PV changes on S7-300/400/1500 |
| Time-of-day comparison (SFC1 + arithmetic) | Familiar pattern | Slower, more code, no advantage over SFC64 |
| OB35 + T_ADD / T_SUB + DONE check | Clean time arithmetic | Relies on OB35 cycle; loses correctness if OB35 cycle changes |
| Self-resetting timer pair | Uses stock TP/TOF | Re-start logic must be custom, race conditions at PV=0 |
The FB_VarDelay pattern is preferred because it is the only approach that is mathematically guaranteed to handle a variable PV across all combinations of scan time, PV update rate, and wrap-around.
Why PLC Timing Differs from Microcontroller Timing
It is worth contrasting this with microcontroller implementations for context. On an Arduino, the delay() function is a blocking call that pauses the loop for a specified number of milliseconds. There is no concept of a "running timer" because the entire CPU is halted. The next iteration of loop() can change the ms argument and the new value takes effect on the next call. In a PLC, the cycle is non-blocking and the timer must coexist with scan logic, so PV changes are observable only when the cyclic OB re-reads them. This is why IEC 61131-3 has a dedicated timer state machine and why the standard leaves PV-latching semantics to the vendor.
The same reasoning applies to other PLC platforms: Allen-Bradley TON and TOF instructions in RSLogix 5000 / Studio 5000 also latch the preset at enable; the only way to get a variable-PV on-delay is a custom AOI (Add-On Instruction) using the GSV instruction on the WallClockTime object, which is functionally identical to the TIME_TCK approach described here.
References for further study (all official manufacturer or standards pages):
- Siemens PCS 7 product family
- Siemens Industry Online Support (SIOS) — entry portal for STEP 7, TIA Portal, and PCS 7 manuals
- SIMATIC S7-1500 product page
- SIMATIC S7-400 product page
- IEC 61131-3:2013 standard — Programmable controllers, Part 3
- Arduino delay() reference — contrast for microcontroller timing
FAQ
Can I use a stock IEC_TON block with a variable PV input in PCS 7?
No. The IEC_TON block in STEP 7 / TIA Portal latches PV on the rising edge of IN. Subsequent writes to PV do not affect the in-flight run. Use the FB_VarDelay shown in this article, or an equivalent custom block, in CFC.
What is the resolution of the variable delay timer?
On AS 410 (S7-1500 CPUs used in PCS 7 V9), SFC64 returns ticks at the system clock period — 1 ms on S7-1500. On AS 400 (S7-400 CPUs used in PCS 7 V8), the tick period is typically 10 ms. For 1 ms resolution on a S7-400 system, switch to AS 410 or use a hardware counter module.
How do I handle a temperature formula that produces negative or zero delays?
Clamp the formula output at zero (or at a configured minimum like 5 s) in the calculation block. A zero delay should fire the shutdown immediately; negative delays are nonsensical. The FB_VarDelay code already handles PV = 0 correctly as a one-shot.
Can I trigger the timer multiple times in the same run?
Yes. The AutoRetrig input restarts the timer when PV drops below the current elapsed value. If you want explicit manual re-trigger, pulse the Start input again; the rising edge re-arms the block and resets Elapsed to zero, regardless of AutoRetrig.
Does FB_VarDelay need a special instance DB layout for PCS 7?
Use the default instance DB and add the block to your AS master data block. The S7_m_c := 'true' attribute makes the FB multi-instance capable, which is required for use in CFC charts that instantiate the block multiple times in one chart or in a chart family.
How does this behave across a CPU failover in an H-system?
SFC64 on a fault-tolerant AS 410 H returns the local CPU's tick, which is synchronized with the standby CPU to within ~10 ms. A hot-standby failover during a run will cause at most one tick of jitter on Elapsed. This is acceptable for process-grade shutdown timing; for sub-tick precision, use a separate high-resolution clock from an external timer module.