1. Overview: From Operator Set-Point to HMI Countdown
When a Siemens S7-1200 CPU is configured as the controller for a batch or dwell-time application, the operator enters a duration in hours through a TIA Portal HMI tag (e.g., 20 h). The CPU stores that value in a TIME tag and feeds it to an IEC timer such as TON, TP, or TONR. While the process runs, the engineer wants the same panel to display a live countdown showing how many hours and minutes remain before the timer expires.
The TIME data type on S7-1200 and S7-1500 is a 32-bit signed integer that counts milliseconds. TIA Portal's editor renders the value as T#20h0m0s0ms, but the underlying integer is just 72,000,000. A raw transfer of that integer to an HMI text field shows "72000000" — technically correct, but operationally unreadable. The conversion from the millisecond integer to a human-readable HH H MM M string must happen on the PLC side; the HMI only renders the result.
The source requirement is a string of the form "10H 43M 12S" on a TIA Portal HMI panel (KTP700, KTP1200, Comfort, or Unified). The seconds component is optional, but the hours and minutes must be readable at a glance from a 7-inch Basic panel at 2 m distance. This article covers three engineering approaches:
- Convert
TIMEto aDTLstructure withT_CONV, then read the HOUR and MINUTE fields. - Decompose the millisecond integer with SCL arithmetic into hours, minutes, and (optionally) seconds.
- Compute remaining run time from a real-time-clock source with
T_DIFF, then push a formatted string to the HMI.
Each method ships with an SCL function block, an HMI tag wiring table, and a commissioning checklist that can be copied directly into a TIA Portal V17 or V18 project.
2. The TIME Data Type Internals on S7-1200/1500
Per the SIMATIC S7-1200 Programmable Controller System Manual and the SIMATIC S7-1500 System Manual, TIME occupies 4 bytes and is stored as a signed DINT in milliseconds. The range and resolution are summarized below.
| Property | Value |
|---|---|
| Width | 32 bits (DINT) |
| Resolution | 1 ms (sign bit + 31-bit magnitude) |
| Minimum | T#-24d_20h_31m_23s_647ms = -2,147,483,648 ms |
| Maximum | T#+24d_20h_31m_23s_647ms = +2,147,483,647 ms |
| Default literal format | T#<DAYS>d_<HOURS>h_<MINUTES>m_<SECONDS>s_<MS>ms |
| IEC timer output type | TIME (elapsed time until preset reached) |
| Behavior on overflow | Rolls over to T#-24d_20h_31m_23s_647ms |
| Standard | IEC 61131-3:2013, §6.4.2 |
TIME tag in T# syntax with all five components (days/hours/minutes/seconds/ms). The PLC, however, stores the value as a plain 32-bit signed integer. Any HMI tag that points at the TIME variable will receive the raw ms count unless the data is pre-formatted on the PLC side. This is the root cause of the source-reported "Text Box didn't work" symptom: the HMI is faithfully displaying the integer, just not the human-friendly string.3. IEC Timer Instructions: TON, TOF, TP, and TONR
The S7-1200 and S7-1500 instruction sets include the four IEC 61131-3 timers. Each has a PT (preset time) input of type TIME and an ET (elapsed time) output of type TIME. The ET value is exactly what is required to drive a remaining-time string on the HMI. The IEC 61131-3:2013 standard defines the behavior of these four function blocks in §6.4.3 (function block types TP, TON, TOF, and TONR).
| Instruction | Behavior | ET behavior | Typical use case |
|---|---|---|---|
TON (on-delay) |
ET increments while IN=1; Q=1 when ET ≥ PT | Counts up from 0 to PT | Dwell time, batch stage |
TOF (off-delay) |
ET increments after IN falls to 0 | Counts up after falling edge | Cool-down, fan run-down |
TP (pulse) |
ET increments for fixed duration on rising edge | Counts up from 0 to PT | Fixed pulse length |
TONR (retentive on-delay) |
ET accumulates; reset via R input | Accumulates while IN=1 | Total run hours, maintenance timer |
For a process countdown the natural fit is TON: connect a Boolean run signal to IN, the operator-entered duration to PT, and read the elapsed time from ET. The remaining time is simply PT - ET and is a TIME tag that can be passed to the SCL function block in §7. The TONR variant is required when the operator's "20 h" is an accumulated requirement that must survive pause cycles.
For an S7-1200 with firmware below V4.0, the older legacy timer instructions S_PULSE, S_PEXT, S_ODT, S_ODTS, and S_OFFDT remain available. They expose a BI (binary, in seconds) and a BCD output. Use BI and then convert to TIME in SCL before formatting; the BCD output is encoded as BCD digits and is not directly compatible with the methods in this article.
4. Method 1: T_CONV from TIME to DTL
STEP 7 (TIA Portal) provides a set of Date and Time-of-Day extended instructions for the S7-1200 (firmware V4.0 and later) and S7-1500. The T_CONV block converts a TIME value into a DTL structure whose fields can be mapped individually to HMI tags. The full DTL structure is documented in the STEP 7 (TIA Portal) Programming and Operating Manual, chapter on date-and-time functions.
| DTL field | Data type | Range | Meaning |
|---|---|---|---|
| YEAR | UINT | 1970 to 2554 | Year (offset = 1970 for TIME input) |
| MONTH | USINT | 1 to 12 | Month |
| DAY | USINT | 1 to 31 | Day of month |
| WEEKDAY | USINT | 1 to 7 | Day of week (1 = Sunday) |
| HOUR | USINT | 0 to 23 | Hour of day |
| MINUTE | USINT | 0 to 59 | Minute of hour |
| SECOND | USINT | 0 to 59 | Second of minute |
| NANOSECOND | UDINT | 0 to 999,999,999 | Sub-second fraction |
Important caveat: T_CONV treats the TIME input as an offset from 01-01-1970 00:00:00, not as a duration. The YEAR field rolls over after ~89 years, the MONTH rolls over after 30 d, the HOUR field rolls over after 24 h, and so on. The structure is convenient for displaying "5 h 23 m" but does not show a value larger than 24 h cleanly because the HOUR field resets to 0 at 24 h while the DAY field increments. For run times above one day the manual-arithmetic method (§5) is required.
4.1 Adding a Fixed Base Date
To keep the HOUR field at the same numeric value as the operator's set-point (i.e., 20 h rather than 20 h, then 0 h, then 0 h, ...), the cleanest path is to skip T_CONV entirely and use the manual arithmetic in §5. If T_CONV must be used, configure a base DTL constant (e.g., DTL#1970-01-01-00:00:00) and use T_ADD to add the TIME value to it, then read HOUR and MINUTE. This is rarely worth the effort; the arithmetic approach is shorter and faster.
5. Method 2: Manual Millisecond Decomposition in SCL
The most flexible approach is to decompose the millisecond count yourself. This method works on every S7-1200 firmware version (V1.0+) and gives full control over the display format, including values above 24 h and the option to suppress the seconds field entirely. The math is elementary:
-
TotalSeconds = TimeValue / 1000(DINT division truncates) Hours = TotalSeconds / 3600Minutes = (TotalSeconds MOD 3600) / 60Seconds = TotalSeconds MOD 60RemainMs = TimeValue MOD 1000
The SCL implementation, written so that the result is a single concatenated STRING ready to drop into an HMI text field, is shown below.
FUNCTION_BLOCK "FB_TimeToHmiString"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
iTimeMs : TIME; // Raw time value, e.g. PT - ET of a TON
END_VAR
VAR_OUTPUT
sDisplay : STRING[20]; // Output to HMI text field
END_VAR
VAR
siTotalSec : DINT;
siHours : DINT;
siMinutes : DINT;
siSeconds : DINT;
END_VAR
BEGIN
// Convert TIME (ms) to a seconds count
siTotalSec := TIME_TO_DINT(iTimeMs) / 1000;
// Decompose into hours, minutes, seconds
siHours := siTotalSec / 3600;
siMinutes := (siTotalSec MOD 3600) / 60;
siSeconds := siTotalSec MOD 60;
// Build the "HH H MM M SS S" string
sDisplay := INT_TO_STRING(siHours) + 'H ' +
INT_TO_STRING(siMinutes) + 'M ' +
INT_TO_STRING(siSeconds) + 'S';
END_FUNCTION_BLOCK
The function block returns "20H 0M 0S" for a fresh TON with PT = T#20h and decays to "19H 59M 58S" after two seconds, exactly what the operator expects. For a no-seconds view (as in the source request, where seconds are not necessary), drop the seconds field and the trailing 'S'; the output becomes "19H 59M" and the STRING length can shrink to 12 characters.
5.1 Comparison of the Three Methods
| Property | T_CONV to DTL | Manual SCL decomposition | T_DIFF with RTC |
|---|---|---|---|
| Min CPU FW | V4.0 (S7-1200) | V1.0 (S7-1200) | V4.0 (S7-1200) |
| Max display range | 23 h 59 m 59 s | 59,994 h (DINT limit) | 24 d 20 h 31 m |
| Survives power cycle | Yes (with retentive FB) | Yes (with retentive FB) | Yes (if deadline stored) |
| Update accuracy | ±1 ms | ±1 ms | ±1 s (RTC resolution) |
| Code size | 1 call (T_CONV) | ~30 lines SCL | 2 calls (RD_SYS_T + T_DIFF) |
| Edge cases | HOUR saturates at 23 | Handles any value | Negative after deadline |
| Best for | Short countdowns (< 1 day) | Production countdown screens | Shift-end deadlines |
TIME tag can be negative (e.g., when ET > PT on a TON that has already elapsed, or when a T_DIFF deadline has passed). Wrap the result with a clamp if the HMI must not show a minus sign: IF siHours < 0 THEN siHours := 0; END_IF;
6. Method 3: T_DIFF for Real-Time-Clock Countdown
If the dwell time is measured against a real wall-clock deadline rather than a relative counter, use the CPU's real-time clock. The CPU exposes the current date and time as a DTL tag in the system clock byte (e.g., LocalTime from the RD_SYS_T instruction). Compare it against a deadline DTL using T_DIFF:
| Parameter | Declaration | Type | Description |
|---|---|---|---|
| IN1 | Input | DTL | Earlier date/time |
| IN2 | Input | DTL | Later date/time |
| RET_VAL | Return | TIME | IN2 − IN1 as a TIME (ms) value |
Wire the RTCDeadline to IN2 and the current LocalTime to IN1. The return value is the time remaining; feed it to the SCL function block from §5 and you have a wall-clock-based countdown that survives power cycles if the deadline is stored in a non-volatile data block.
// SCL inside FB_DeadlineCountdown
iRemainingTime := T_DIFF(IN1 := "DB_Time".LocalTime,
IN2 := "DB_Time".RTCDeadline);
Caution: T_DIFF returns a signed TIME. Once the deadline passes, the value goes negative; clamp it before passing to the SCL formatter to keep the HMI display tidy. The CPU's RTC drifts typically 1–2 seconds per day without synchronization; for higher accuracy, configure NTP via the CPU's PROFINET interface or use the SET_CLKSYN instruction to slave to a master clock.
7. SCL Function Block: FB_TimeToHmiString
The complete function block for Method 2 is shown below, including a "no-seconds" variant and a "lead-zero padding" option for a fixed-width HMI display.
FUNCTION_BLOCK "FB_TimeToHmiString"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.2
VAR_INPUT
iTimeMs : TIME; // Raw time value
bShowSeconds : BOOL := FALSE; // TRUE = include "SS S" suffix
bZeroPad : BOOL := TRUE; // TRUE = "01H 02M" vs "1H 2M"
END_VAR
VAR_OUTPUT
sDisplay : STRING[20];
END_VAR
VAR
siTotalSec : DINT;
siHours : DINT;
siMinutes : DINT;
siSeconds : DINT;
sHours : STRING[4];
sMinutes : STRING[4];
sSeconds : STRING[4];
END_VAR
BEGIN
siTotalSec := TIME_TO_DINT(iTimeMs) / 1000;
// Clamp negative values to zero
IF siTotalSec < 0 THEN
siTotalSec := 0;
END_IF;
siHours := siTotalSec / 3600;
siMinutes := (siTotalSec MOD 3600) / 60;
siSeconds := siTotalSec MOD 60;
IF bZeroPad THEN
sHours := INT_TO_STRING(siHours);
sMinutes := INT_TO_STRING(siMinutes);
sSeconds := INT_TO_STRING(siSeconds);
WHILE LEN(sHours) < 2 DO sHours := '0' + sHours; END_WHILE;
WHILE LEN(sMinutes) < 2 DO sMinutes := '0' + sMinutes; END_WHILE;
WHILE LEN(sSeconds) < 2 DO sSeconds := '0' + sSeconds; END_WHILE;
ELSE
sHours := INT_TO_STRING(siHours);
sMinutes := INT_TO_STRING(siMinutes);
sSeconds := INT_TO_STRING(siSeconds);
END_IF;
sDisplay := sHours + 'H ' + sMinutes + 'M';
IF bShowSeconds THEN
sDisplay := sDisplay + ' ' + sSeconds + 'S';
END_IF;
END_FUNCTION_BLOCK
The bShowSeconds and bZeroPad inputs give the integrator two common HMI formatting choices without needing a second FB. Place the FB call in a cyclic OB (e.g., OB1 main program) so the output is refreshed every PLC scan. The PLC scan time on a CPU 1214C with this FB is approximately 0.3 ms per call, well within the 1 ms budget of a 1 kHz process image update.
8. HMI Tag Configuration in TIA Portal / WinCC
The function block in §7 outputs a 20-character STRING. Connect that tag to an HMI text field as follows.
- Open the HMI device in the project tree and double-click HMI Tags.
- Add a new tag named
RemainingTimewith the PLC connection set to the S7-1200 and the DB path set to thesDisplayelement of theFB_TimeToHmiStringinstance. - Set Data type to
String[20]and Length to 20 characters. - Set Acquisition mode to Cyclic continuous with a 1-s update cycle.
- Drop a Text field onto the screen, open its properties, and bind the Text property to
RemainingTime. - In the Appearance tab set a monospaced font (e.g., Consolas) so the column alignment stays stable as digits change.
The procedure is identical for the SIMATIC HMI panels KTP700 Basic (6AV2123-2GB03-0AX0), KTP1200 Basic (6AV2123-2MA03-0AX0), Comfort panels TP700/TP1200/TP1500/TP1900 (6AV2 1xx series), and Unified Comfort panels (6AV2 1xx-2xx). For Unified panels, the Text field can be replaced by an Output element with a property binding to the same tag. For panels running WinCC RT V16 or later, the STRING tag is read at the configured cycle; for V14/V15 the maximum STRING length is 16 characters, so reduce the FB output to 16.
9. Output Field and String Formatting Choices
WinCC (TIA Portal) lets you use either a numeric I/O field or a text field. The trade-off is summarized in the table below.
| Approach | PLC tag type | PLC CPU load | HMI flexibility | Best for |
|---|---|---|---|---|
| Raw numeric (ms) | TIME | None | Display "72000000" | Diagnostic only |
| Pre-formatted STRING | STRING[20] | Low (one FB cycle) | Display "20H 0M" | Operator HMI |
| Three numeric I/O fields (HH, MM, SS) | 3× DINT | Low | Display separate fields | Recipe screens |
| Multiplexed symbolic I/O field | DINT | Medium | Bar/indicator with text overlay | Progress display |
For a clean "10H 43M" string the pre-formatted STRING approach is preferred. For screens that need separate spinner inputs (e.g., operator adjusts minutes only), the three-DINT approach is easier to wire to the WinCC I/O field configuration. To minimize the HMI-side update lag, see §11.4 below.
10. Ladder (LAD) and FBD Implementation
If the project does not allow SCL, the same logic is achievable in LADDER using the CALCULATE (CALC) and the String + Concatenate (S+) instructions. The decomposition is implemented as four CALC boxes:
| CALC # | Expression | Output |
|---|---|---|
| 1 | (DINT)iTimeMs / 1000 | TotalSec (DINT) |
| 2 | TotalSec / 3600 | Hours (DINT) |
| 3 | (TotalSec MOD 3600) / 60 | Minutes (DINT) |
| 4 | TotalSec MOD 60 | Seconds (DINT) |
Append three String + Concatenate (S+) boxes that build Hours + 'H ' + Minutes + 'M ' + Seconds + 'S'. The S+ box is documented in the STEP 7 (TIA Portal) Programming Manual and is available on S7-1200 from firmware V4.2 onward; on S7-1500 it is available in all firmware versions.
TotalSec intermediate tag must be declared in a static data block or as a temp variable, not as a local stack variable, otherwise the S+ boxes will read stale data on subsequent networks.11. Commissioning and Verification Procedure
The procedure below assumes TIA Portal V18, an S7-1200 CPU 1214C DC/DC/DC (catalog number 6ES7214-1AG40-0XB0) with firmware V4.4, and a KTP1200 Basic (6AV2123-2MA03-0AX0) HMI panel.
- Compile the SCL function block and download the program to the CPU.
- Open Online & Diagnostics, force the input
iTimeMs := T#20h, and confirm that thesDisplaytag reads"20H 0M 0S". - Set
iTimeMs := T#1h_2m_3s_456msand verify thatsDisplay = "1H 2M 3S". The millisecond component is intentionally dropped. - Force
iTimeMs := T#0msand confirm the output is"0H 0M 0S", not an empty string. (This catches bugs in which the INT_TO_STRING output is padded with leading blanks.) - Force
iTimeMs := T#-1mand confirm the clamp returns"0H 0M 0S". - Force
iTimeMs := T#100hand confirm the output is"100H 0M 0S", not"4H 4M 0S". (This catches theT_CONVsaturation bug if Method 1 was used.) - On the HMI, navigate to the countdown screen, verify that the text field updates at exactly 1 Hz, and confirm the cycle counter in the PLC diagnostic buffer does not exceed +5 ms drift per minute.
- Cycle power to the CPU and confirm the countdown continues from the last value if the
TONinstance is in a retentive data block, or restarts fromPTif it is not. - Disconnect the HMI Ethernet cable and confirm the PLC continues updating
sDisplayin the DB. (This catches a project bug where the FB sits in the HMI's cyclic interrupt OB instead of the PLC's OB1.) - Force the PLC to STOP and back to RUN. The
TONinstance should reset; verify the HMI display returns to the operator's preset value, not to a stale "0". - Enable the
clock_1Hzmemory bit on the CPU and use it to gate the FB call once per second. This drops the PLC CPU load by 90 % when the FB is the only one running every scan.
12. Common Errors, Edge Cases, and Cross-Platform Notes
The errors encountered most often when commissioning the function block are listed below.
| Symptom | Likely cause | Fix |
|---|---|---|
| HMI shows "72000000" instead of "20H 0M" | Tag bound to raw TIME tag, not the SCL output sDisplay
|
Re-bind the HMI text field to the STRING output of the FB |
| HMI shows empty field | STRING length mismatch between PLC and HMI | Match the HMI tag Length to the FB output (e.g., 20 characters) |
| HMI shows the right value for 1 s, then freezes | Acquisition mode set to On change; PLC writes the same STRING repeatedly | Set acquisition to Cyclic continuous with 1-s cycle, or toggle a Boolean the HMI watches |
| Hours reset to 0 at 24 h | Using T_CONV with DTL, HOUR field saturates at 23 |
Use Method 2 (manual arithmetic) |
| Negative numbers on HMI |
TON continues to count after PT, or T_DIFF deadline has passed |
Clamp the result with MAX(0, iTimeMs) before formatting |
| "STRING error" online | Source string longer than declared length (e.g., 1000 h > 12 chars) | Either widen the STRING or use a multiplier field (display "999+ H" if overflow) |
| Display updates but lags by 2 s | HMI update cycle set to 2 s; PLC SCL FB runs every 100 ms | Lower the HMI cycle to 500 ms; or accept the lag and document it |
| HMI display flickers every scan | PLC writes a new STRING every 10 ms; HMI re-renders too often | Gate the FB with a 1-Hz clock bit (e.g., clock_1Hz from the CPU system clock) |
| TONR shows wrong time after power cycle | TONR instance DB not configured as retentive | Set Retentive = true in the DB properties; add ET and IN to the retentive list |
The TIME-to-HMI pattern is portable across SIMATIC controllers. The differences between the most common CPUs are summarized below.
| Controller | TIME width | T_CONV support | S+ concat support | Notes |
|---|---|---|---|---|
| S7-1200 (CPU 1211C … 1217C, FW V4.0+) | 32 bits, signed ms | Yes | Yes (FW V4.2+) | Recommended target |
| S7-1200 (CPU 1212C, FW < 4.0) | 32 bits, signed ms | No | No | Use CALC + manual string build |
| S7-1500 (CPU 1511 … 1518) | 32 bits, signed ms in IEC timers; ns in LTime | All FW | All FW | Higher resolution; HOUR field still saturates at 23 |
| ET 200SP CPU | Same as S7-1500 | All FW | All FW | Identical methodology |
| S7-300 / S7-400 (legacy STEP 7 V5.x) | 32 bits, signed ms | Yes (FC/FB 3, 4, 5) | Yes | Same SCL code works; import via STEP 7 migration tool |
For non-Siemens controllers the algorithm is identical. On Allen-Bradley Logix, use the MOD and DIV instructions on a DINT and concatenate in structured text. On Modicon M340, the DWORD_TO_STRING function plus a similar decomposition works; the HMI side (EcoStruxure Operator Terminal Expert) accepts the same STRING tag.
13. FAQ
Why does the HMI show the raw millisecond integer instead of the formatted string?
Because the HMI tag is bound to the TIME variable (raw ms) rather than the STRING output of the SCL function block. Re-bind the text field to the sDisplay tag of the FB and reload the HMI project.
Can I display times greater than 24 hours without the HOUR field rolling over?
Yes. Do not use the T_CONV instruction for the HOUR field — it saturates at 23. Use the manual SCL decomposition in §5: Hours = TotalSeconds / 3600 returns the correct value up to 59,994 h before the DINT overflows.
What is the maximum value I can store in a TIME tag on an S7-1200?
±2,147,483,647 ms, which is approximately ±24 d 20 h 31 m 23 s. Above that the value overflows. If you need longer run times, store the deadline as a DTL (year-month-day-hour-min-sec) instead of a TIME.
Do I need TIA Portal V18 or is V16 sufficient?
The SCL function block in §5 compiles in TIA Portal V14 SP1 and later. The S+ concatenation box is from FW V4.2 of the S7-1200 (CPU firmware, not TIA Portal version) and STEP 7 V15.1. The S7-1500 S+ box is available in every TIA Portal version from V12 onward.
How do I avoid the HMI display lagging by one update cycle?
Use the Change acquisition mode in WinCC, not Cyclic continuous, and increment a hidden BYTE tag in the same network as the SCL FB. The HMI then re-reads the STRING on every byte change and the lag drops from one second to one PLC scan (1–10 ms).
Why does my TONR show the wrong time after a power cycle?
Because the TONR instance data block is not configured as retentive. In the DB properties, set Retentive = true and add the ET and IN tags to the retentive list. Without this, the timer resets to 0 on every cold start.