Overview
On Siemens S7-300 and S7-400 controllers, legacy SIMATIC timers (S5T# format) and IEC timers (SFB3/SFB4/SFB5) accept preset values encoded as 16-bit BCD words with a time-base nibble. When a calculation in the user program produces a floating-point time value (e.g. 0.5 s from a PID output, scaling block, or flow totalizer), that REAL must be scaled, rounded, and re-encoded before it can be loaded into a timer's TV input. This reference documents the bit layout, the STL conversion sequence, the clamping limits, and the SFB-based alternatives that avoid the legacy S5T# encoding entirely.
The conversion technique below works in STEP 7 V5.x and the legacy S7-300/400 instruction set. On S7-1200/1500, the IEC timers (TP, TON, TOF) accept TIME/LTIME directly, so this conversion is unnecessary on those platforms.
S5T# Time Format Specification
The 16-bit S5T# word is divided into a 2-bit time base (bits 15-14) and a 14-bit BCD value (bits 13-0). The time base selects the resolution applied to the BCD count.
| Time base (bits 15-14) | Resolution | BCD range | Effective range | Hex base word |
|---|---|---|---|---|
| 00 | 0.01 s (10 ms) | 000 - 999 | 10 ms - 9.99 s | W#16#0000 |
| 01 | 0.1 s (100 ms) | 000 - 999 | 0.1 s - 99.9 s | W#16#1000 |
| 10 | 1 s | 000 - 999 | 1 s - 999 s | W#16#2000 |
| 11 | 10 s | 000 - 999 | 10 s - 9990 s | W#16#3000 |
The absolute maximum addressable interval is S5T#9990s (2 h 46 min 30 s). Any value above this must be clamped to W#16#3999; the CPU will reject a malformed word with no specific error code at the timer call, but the timer will simply not start.
Prerequisites
- STEP 7 V5.5 SP2 or later, or compatible TIA Portal version with S7-300/S7-400 support
- Firmware on the S7-300 CPU ≥ V2.0 (required for all timer SFBs); for S7-400 any standard firmware works
- REAL variable holding the desired delay in seconds (e.g.
REAL_TimeValuein a DB or local temp) - WORD variable declared as the S5T# target (e.g.
S5_TimeValuein the same DB) - Optional: instance DB for
SFB4(IEC TON) if the conversion is to be bypassed
Method 1 - STL Conversion Sequence
The reference STL sequence below accepts a positive REAL in seconds, clamps it to the legal S5T# range, selects the correct time base, rounds the mantissa, converts to BCD with DTB, and OR-s the time-base marker. This mirrors the classic implementation originally posted in the SIMATIC support archives.
// Input: REAL_TimeValue (seconds, >= 0)
// Output: S5_TimeValue (WORD in S5T# format)
L #REAL_TimeValue
ABS // Force positive mantissa
L 9.990000e+003 // 9990 s = S5T# maximum
>R
SPB max // If input > 9990, jump to max clamp
TAK // Restore REAL on ACCU1
L 1.000000e+002 // Scale 100x: 0.01 s resolution
*R
RND // Round to DINT milliseconds
L 999
>D
TAK
SPB M01 // <= 999 ms branch (10 ms base)
DTB // Convert ACCU1-L to BCD
SPA end
M01: L 9990
>D
TAK
SPB M10 // 1000 - 9990 ms branch (0.1 s base)
DTB
SRD 4 // Shift BCD right 4 bits = 0.1 s base
L W#16#1000
OW
SPA end
M10: L L#99900 // 99900 centiseconds = 999 s
>D
TAK
SPB M11 // 10 - 999 s branch (1 s base)
DTB
SRD 8 // Shift BCD right 8 bits = 1 s base
L W#16#2000
OW
SPA end
M11: DTB
SRD 12 // Shift BCD right 12 bits = 10 s base
L W#16#3000
OW
SPA end
max: L W#16#3999 // Hard clamp at 9990 s
end: T #S5_TimeValue
Key points in the sequence:
-
ABSdiscards any sign;S5T#does not support negative intervals. -
SPB maxclamps the input to the highest legal S5T# value before any further arithmetic - this prevents overflow in the BCD conversion. -
DTB(DINT-to-BCD) is the CPU built-in; it expects a 32-bit DINT and produces a packed BCD result in ACCU1-L. - Each
SRDshift aligns the BCD nibbles into the lower 12 bits of the 16-bit word, leaving the top 4 bits (bits 15-12) free for the time-base marker. -
OWwith the appropriateW#16#1xxx/W#16#2xxx/W#16#3xxxconstant OR-s the time-base nibble in.
Method 2 - SCL Implementation (S7-300/400)
The same logic in Structured Control Language is easier to read and maintain. Declare an FC with IN: t_req : REAL in seconds, OUT: s5t : WORD, and the following body:
FUNCTION FC100 : VOID
VAR_INPUT
t_req : REAL; // Requested time in seconds
END_VAR
VAR_OUTPUT
s5t : WORD; // Result in S5T# format
END_VAR
VAR_TEMP
ms : DINT; // Working value in milliseconds
base : WORD; // Time-base marker
END_VAR
BEGIN
ms := REAL_TO_DINT(t_req * 100.0);
IF ms < 0 THEN ms := 0; END_IF;
IF ms > 9990 THEN // Hard clamp
s5t := WORD#16#3999;
RETURN;
END_IF;
IF ms <= 999 THEN // 10 ms base
s5t := DINT_TO_BCD_WORD(WORD#16#0000, ms);
ELSIF ms <= 9990 THEN // 100 ms base
ms := ms / 10;
base := WORD#16#1000;
s5t := base OR DINT_TO_BCD_WORD(base, ms);
ELSIF ms <= 99900 THEN // 1 s base
ms := ms / 100;
base := WORD#16#2000;
s5t := base OR DINT_TO_BCD_WORD(base, ms);
ELSE // 10 s base
ms := ms / 1000;
base := WORD#16#3000;
s5t := base OR DINT_TO_BCD_WORD(base, ms);
END_IF;
END_FUNCTION
DINT_TO_BCD_WORD as a placeholder for the BCD conversion. In STEP 7 V5.x SCL, the proper conversion is performed with the standard library function I_BCD (FC/FB from the IEC library) or by manual bit manipulation: bcd := (ms MOD 10) + ((ms / 10 MOD 10) * 16) + ((ms / 100 MOD 10) * 256) + ((ms / 1000 MOD 10) * 4096).Alternative: Bypass the S5T# Encoding with SFB4
If the application is new or being refactored, the IEC timer SFBs accept a TIME value directly. This removes all of the BCD/time-base gymnastics above. SFB4 implements TP (pulse), SFB3 implements TON (on-delay), and SFB5 implements TOF (off-delay). Each takes the preset in milliseconds as a DINT, so the only conversion needed is from REAL seconds to DINT milliseconds:
L #REAL_TimeValue // seconds
L 1.000000e+003 // scale to ms
*R
RND // round to DINT ms
T #SFB4_TV // move to SFB4 input TV
CALL SFB4, DB100 // IEC TP instance DB
IN := #Start_Pulse
PT := #SFB4_TV // DINT milliseconds
Q := #Pulse_Output
ET := #Elapsed_Time
Time range for the IEC SFBs is T#0ms to T#24d20h31m23s647ms (24 days 20 h 31 min 23.647 s), which is far wider than S5T#'s 9990 s limit. This is the recommended approach for any new code on S7-300/400.
Scan Time Integration with OB1_PREV_CYCLE
To keep the conversion in step with the actual OB1 cycle time, copy OB1_PREV_CYCLE into a 16-bit INT global and use it wherever the timer block needs a task interval. The source's example FB shows this used as the timer's accumulator delta.
// In OB1, before calling the timer FB
L OB1_PREV_CYCLE // INT, OB1 scan time in ms
T MW100 // 16-bit global, used by FB
Note that OB1_PREV_CYCLE is updated by the operating system at the start of each OB1 cycle, so the value read in cycle N is the duration of cycle N-1. If the cycle time is longer than the requested timer preset, the timer will complete in a single cycle; if the cycle is short, the accumulator increments by the integer millisecond value of the previous scan.
Boundary Conditions and Clamping
| Input (s) | Rounded (ms) | Time base | BCD value | Resulting WORD | Effective time |
|---|---|---|---|---|---|
| 0.0 | 0 | 10 ms | 000 | W#16#0000 | S5T#0ms |
| 0.5 | 50 | 10 ms | 050 | W#16#0050 | S5T#500ms |
| 5.0 | 500 | 10 ms | 500 | W#16#0500 | S5T#5s |
| 9.99 | 999 | 10 ms | 999 | W#16#0999 | S5T#9s990ms |
| 10.0 | 1000 | 100 ms | 100 | W#16#1100 | S5T#10s |
| 59.5 | 5950 | 100 ms | 595 | W#16#1595 | S5T#59s500ms |
| 99.9 | 9990 | 100 ms | 999 | W#16#1999 | S5T#1m39s900ms |
| 100 | 100000 | 1 s | 100 | W#16#2100 | S5T#1m40s |
| 500 | 500000 | 1 s | 500 | W#16#2500 | S5T#8m20s |
| 999 | 999000 | 1 s | 999 | W#16#2999 | S5T#16m39s |
| 1000 | 1000000 | 10 s | 100 | W#16#3100 | S5T#16m40s |
| 5000 | 5000000 | 10 s | 500 | W#16#3500 | S5T#1h23m20s |
| 9990 | 9990000 | 10 s | 999 | W#16#3999 | S5T#2h46m30s |
| 10000+ | clamped | 10 s | 999 | W#16#3999 | S5T#2h46m30s (clamped) |
Three clamp points must be honored to avoid the timer silently failing to start:
-
Zero clamp:
S5T#0sis valid; a negative input is forced to zero. -
Top clamp: anything above 9990 s must be forced to
W#16#3999- feeding the timer a higher BCD with a 10 s base would be decoded as a value exceeding the 16-bit BCD range and is rejected by the timer logic. -
Rounding behavior:
RNDrounds half-up; if symmetric rounding is required, swap toTRUNC+ half-step correction.
Verification and Testing
- Force
REAL_TimeValueto 0.5 in the VAT table; observeS5_TimeValue = W#16#0050. - Force the input to 9.99; expect
W#16#0999. - Force the input to 9.999; the rounding brings it to 9990 ms, which is the boundary between the 10 ms and 100 ms time bases. The conversion must select the 100 ms base and produce
W#16#1100(100 × 100 ms = 10 s), notW#16#0999(which would still decode correctly but loses resolution on the next increment). - Force 10000 s; verify the output is
W#16#3999. - Wire the converted value into a
S_PULSE/S_PEXT/S_ODTtimer's TV input and start the timer in single-scan mode; confirm the Q output transitions after the expected interval using the PLC's online diagnostic buffer or a VAT trigger on a marker.
Troubleshooting Matrix
| Symptom | Likely cause | Remediation |
|---|---|---|
| Timer never starts; Q stays FALSE | Upper time-base bits not set; word is W#16#0000 with BCD=0 - decoded as S5T#0s
|
Verify the OW with the time-base constant; check that the branch (M01/M10/M11) selects correctly |
| Timer fires immediately | BCD mantissa is non-zero but time base was set to 10 ms with a value intended for the 1 s base (e.g. 50 instead of 0.5) | Confirm scaling factor (* 100.0 for ms) and that division by 10/100/1000 is applied per branch |
| Time is 10× too long or too short | Wrong branch selected (off-by-one between M01 and M10 boundaries) | Add explicit boundary tests at 999, 9990, 99900 ms |
| CPU goes to STOP on the conversion block | BCD value > 999 with time base 10 ms (illegal BCD range) | Verify the upper clamp at 9990 s; ensure no input above this reaches the conversion |
| Output word contains hex digits A-F |
DTB was called on a value that was not a valid DINT, or BCD mantissa contains non-decimal digits because the input was not properly rounded |
Re-check that RND (or explicit DINT truncation) is applied before DTB
|
| Timer time drifts with scan time | Using OB1_PREV_CYCLE as the timer delta but reading it before OB1 initializes it |
Move the read into a state where OB1 has run at least once; or use a fixed cycle OB (OB35) for a stable time base |
| SFB4 instance reports "invalid TV" | TV is negative DINT (e.g. uninitialized) |
Field-Proven Notes
- Keep the conversion in its own FC and call it once per cycle. Calling it inside the timer's coil logic adds scan-time-dependent jitter to the preset.
- If the S5T# target is in a DB, declare the target as
WORD, notS5TIME. TheS5TIMEdatatype on STEP 7 V5.x is a 16-bit WORD with an editor that enforces the BCD format - the user can monitor the value directly in the VAT without extra decoding, but the conversion logic must still produce a validWORDfirst. - On S7-300 CPUs with firmware older than V2.0, the IEC SFBs are not available. Stay on
S_PULSE/S_ODT/S_PEXTand use the S5T# conversion as documented. - On S7-1200 and S7-1500, the
S5T#format is not supported at all. Migrate toTIMEliterals and the IECTP/TON/TOFinstructions.
FAQ
What is the maximum value an S5T# timer can hold on an S7-300?
The maximum is S5T#9990s (2 h 46 min 30 s), encoded as W#16#3999. Any input above 9990 s must be clamped to this value, or the timer will not start.
Why does the BCD mantissa need to be shifted (SRD) after the DTB conversion?
DTB packs the integer value as BCD into the lower bytes of ACCU1-L. The shift SRD 4/SRD 8/SRD 12 aligns the BCD digits into the 12 mantissa bits of the S5T# word (bits 13-0), leaving the upper nibble (bits 15-12) free for the time-base marker inserted by OW.
Can I skip the S5T# conversion and feed the REAL directly to a timer?
On S7-300/400, no. The legacy S_PULSE/S_ODT/S_PEXT instructions require a WORD in S5T# format. The IEC SFBs (SFB3/SFB4/SFB5) require a DINT in milliseconds - you only need to scale the REAL to ms and round it.
How do I migrate this code to an S7-1200 or S7-1500?
Replace the S5T# conversion with the IEC TP/TON/TOF instructions in TIA Portal and pass the time as a TIME literal. The TIME type accepts up to 24 d 20 h 31 m 23 s 647 ms, so the time-base/BCD encoding is no longer required.
What happens if I OR the time-base marker with a BCD mantissa that exceeds 999?
The CPU does not flag this at conversion time; the timer simply does not start. A common cause is forgetting to scale the REAL by 100 before rounding - the mantissa reaches DTB in the thousands and produces illegal BCD digits. Always clamp to 9990 s (or to 999 ms per branch) before the BCD conversion.