Overview
WinCC Unified V17 (part of the SIMATIC WinCC Unified PC-based and Unified Comfort Panel HMI system) exposes every faceplate-style screen object — including the IO field — to a tightly integrated tag database. The IO field can be bound to a single HMI tag, a tag from a connected PLC, or a script-driven expression, and it can be configured as an input/output, input only, or output only element. The question most engineers hit during the first commissioning is deceptively simple: "How do I take a tag from my PLC and put it into the IO field, and how do I apply min/max limits to it?"
This reference walks through the entire chain — from declaring the PLC tag, exposing it on the HMI side, binding it to the IO field, and applying value-range clamping. It also addresses the well-known limitation that built-in min/max limit fields in the tag properties are silently rejected for complex data types (arrays, structures, byte strings) and for the elementary 8-bit data type Byte. For those cases, the article details a deterministic script-based clamping pattern using the OnChange of the process value and the OnInputFinished event.
Throughout the article the term PLC tag refers to any tag that originates in the S7-1200, S7-1500, ET 200SP, S7-300/400, or third-party controller that is reachable through the SIMATIC HMI connection, and the term HMI tag refers to the WinCC Unified internal tag that is the binding surface for IO fields, scripts, animations, and logging.
Prerequisites
Before the IO field will accept a PLC tag and respect a value clamp, verify the following engineering baseline:
- TIA Portal V17 Update 4 or later is installed on the engineering station. Unified Comfort Panels require matching firmware (V17.x) to load the project without compatibility downgrade warnings. See the Siemens TIA Portal V17 release notes for the exact build identifiers.
-
WinCC Unified V17 runtime is installed on the panel or on the Unified PC station. The minimum firmware for the MTP700/MTP1000/MTP1200/MTP1500/MTP1900/MTP2200 Unified Comfort Panels is
V17.0.0.0; later feature packs added faceplate improvements that are not strictly required for this workflow. - The HMI connection between the panel and the controller is configured (S7-1200/1500, S7-300/400, Modbus TCP, OPC UA, or a third-party driver). Confirm the connection is online in the TIA project tree under Devices & Networks.
- The PLC tag is declared with a simple, scalar, signed integer or real data type (recommended:
Int,DInt,LInt,Real, orLReal). If the tag is an array or a UDT, the built-in limit is silently ignored — this is the core constraint that drives the script-based solution described below. - The IO field is configured with "Output/Input" mode under Properties > General > Mode if the operator is expected to write back to the controller.
Built-in Tag Limit Configuration (Scalar Tags)
For scalar tags whose data type is in the supported list — Int, DInt, LInt, UInt, UDInt, ULInt, Real, LReal — the IO field limit is configured directly in the HMI tag properties and is enforced by the runtime. The configuration is performed in the TIA Portal HMI tag editor.
- In the project tree, expand HMI > HMI tags and double-click the tag to open its properties.
- Select Properties > Range in the inspector window.
- Enter the low limit and the high limit. The IO field will reject any operator entry outside the range and raise a system alarm
300205("Value outside the limits of the tag"). - Compile and download the HMI. The new range takes effect at the next runtime start.
| HMI tag data type | Built-in min/max accepted? | IO field honors the clamp? | Notes |
|---|---|---|---|
SInt / Int / DInt / LInt
|
Yes | Yes | Default if not configured: full signed range of the type. |
USInt / UInt / UDInt / ULInt
|
Yes | Yes | Range defaults to 0..max-of-type. |
Real / LReal
|
Yes | Yes | Real comparison honors NaN by always failing the bound check. |
Bool |
No | No (use check box) | Use a checkbox or toggle, not an IO field. |
Byte / Word / DWord / LWord
|
Partially | Often ignored |
Byte limits are silently rejected by the HMI tag editor in many V17 builds; use USInt instead. |
String / WString
|
No | No | String length is bounded by tag configuration, not by an arithmetic limit. |
Array of … |
No | No | No "Apply limits" button is shown for arrays; use script or expose element tags. |
| UDT / struct | No | No | No compound limit; use member-level tags or scripts. |
The crucial line in the matrix is the Array of Real row. TIA Portal V17 simply does not render the range fields for array HMI tags — the controls are grayed out — and any attempt to use an array tag as the IO field's Process value without a clamp script allows the operator to write a value of 9.9E+30 directly into the controller's data block. This is the failure mode described in the original engineering report.
Root Cause: Why Complex Tags Reject Built-in Limits
WinCC Unified's tag editor binds the "Range" UI to a single scalar value descriptor in the tag's metadata block. An HMI tag whose data type is Array[0..15] of Real carries a metadata block that is structurally identical to a C array descriptor — a base address, an element type, an element count, and a stride — and the V17 tag property sheet does not have a widget that captures one pair of (low, high) limits for the whole array. Internally, the editor would have to either:
- store one limit per element (which would make the configuration dialog quadratic in the array length and would not survive a tag-type change), or
- store a single (low, high) pair and silently apply it to every element (which would be misleading if the user actually wants per-element ranges).
Siemens chose the conservative path: the range UI is hidden whenever the tag's data type is not a scalar integer or real. The same suppression applies to the Byte type in V17 — a regression carried forward from the early V16 unified builds — even though Byte is conceptually a USInt. The fix in the V17 service pack train was to use USInt explicitly if you need unsigned 8-bit semantics with a range check.
Solution Strategy Overview
Three pragmatic strategies are available to the engineer. They are listed in order of preference.
| Strategy | Where the clamp lives | Best use case | Downsides |
|---|---|---|---|
| 1. Expose array element tags | HMI tag (per element) | Small fixed-size arrays, stable structure | Many tags to maintain; renaming the array breaks the bindings. |
| 2. Script on the IO field | JavaScript in the screen | Variable-length arrays, derived bounds, alarms to the operator | More code to maintain; clamp is not enforced at the HMI tag level. |
| 3. Clamp in the PLC | S7-1500 SCL or ladder | Hard process limits (e.g. 0..10 bar on a pressure transmitter) |
Operator does not see why an entry was rejected unless the PLC also raises an alarm. |
For most production cells, strategy 1 (expose element tags) is the most maintainable: bind the IO field to a single Real element tag that already has a built-in range, and let the array simply stay a passive buffer in the controller. If the array is large and the IO field needs to walk through it (an indexed recipe, a tuning array, a multi-point setpoint table), strategy 2 (script-based clamping) is the right answer. Strategy 3 should be reserved for the cases where the clamp is a hard process safety limit and not a UI convenience.
Strategy 1: Expose Array Element Tags
Suppose the controller exposes a data block DB_Recipe with an array:
// S7-1500 SCL
DATA_BLOCK "DB_Recipe"
STRUCT
Temperature : ARRAY[1..10] OF REAL; // °C, 0..250
Pressure : ARRAY[1..10] OF REAL; // bar, 0..10
END_STRUCT;
END_DATA_BLOCK
In the TIA Portal HMI tag editor, create ten HMI tags HMI_Recipe_Temp_01 through HMI_Recipe_Temp_10 with PLC address %DB17.DBX0.0 (Real) for index 1, then +4 bytes for each subsequent element. Configure the range on the HMI tag as 0..250.0. Bind the IO field to HMI_Recipe_Temp_01 directly. The runtime will reject any out-of-range entry and the IO field will stay within the safe window.
Strategy 2: Script-Based Clamping (Array of Real)
When the array is large, when the bounds are derived, or when the IO field index changes dynamically, the cleanest solution is to add a JavaScript to the IO field that clamps the entered value. The recommended events are "Input finished" for an operator-driven clamp, and "Process value change" for a controller-driven clamp.
Step-by-step: Bind the IO field to the array element
- Open the screen in the WinCC Unified editor.
- Drag an IO field from the toolbox onto the canvas.
- In Properties > General > Process value, bind the IO field to the HMI tag of the array element. If you do not have a per-element tag, bind to the array itself — the array is read/write in V17 even though it cannot carry a built-in clamp.
- Set the mode to "Output/Input".
- Switch to the Events tab in the property sheet.
Event 1 — "Input finished" (operator commit)
This is the right place to validate what the operator typed before the value is written to the controller. The event fires when the operator leaves the IO field (Tab, Enter, focus loss, or screen change). The script receives the entered value as a parameter.
// WinCC Unified — JavaScript on the IO field "Input finished" event
// Clamp the entered Real value to the range [MIN, MAX] and re-display the result.
// 'item' is the IO field screen object, 'value' is the operator-entered value.
var MIN = 0.0; // °C, lower process limit
var MAX = 250.0; // °C, upper process limit
var rounded = Math.round(value * 10) / 10; // 0.1 °C display resolution
if (isNaN(rounded)) {
HMIRuntime.Trace("IO field rejected NaN entry");
item.OutputValue = MIN;
return;
}
if (rounded < MIN) {
HMIRuntime.Trace("IO field below MIN: " + rounded);
item.OutputValue = MIN;
return;
}
if (rounded > MAX) {
HMIRuntime.Trace("IO field above MAX: " + rounded);
item.OutputValue = MAX;
return;
}
// Value is in range — accept it
item.OutputValue = rounded;
The key line is item.OutputValue = …. Writing back to OutputValue forces the IO field to display the clamped value, which the operator will see as an automatic correction. If you also need to write the corrected value into the controller tag, follow this with Tags("HMI_Recipe_Temp_NN").Write(rounded);.
Event 2 — "Process value change" (controller side)
If the controller is the source of the value (a sensor, a calculated setpoint, a parameter that the PLC updates periodically), the clamp must run on every read cycle. Attach a script to Process value change of the IO field:
// WinCC Unified — JavaScript on the IO field "Process value change" event
// Reject out-of-range values coming from the controller and re-display the clamped one.
var MIN = 0.0;
var MAX = 250.0;
var v = Tags("HMI_Recipe_Temp_NN").Read(); // current value from the controller
if (v < MIN) v = MIN;
if (v > MAX) v = MAX;
item.OutputValue = v;
This pattern is deterministic: the script runs on every acquisition cycle, the IO field shows the clamped value, and the operator can never see a transient that violates the range. The downside is that it makes the screen busier than necessary if the controller is already well-behaved — in that case, do not attach a script to "Process value change" and rely on the controller-side clamp instead.
Optional: Surface the violation as an alarm
When the operator has typed a value outside the range, silently rewriting it to the limit can be confusing. A common improvement is to raise a system alarm so the operator understands what happened:
// inside the "Input finished" script, after detecting an out-of-range entry
var now = new Date();
HMIRuntime.Alarming.CreateSystemInformation(
"IO field clamp",
"Entered value " + rounded + " was clamped to [" + MIN + ", " + MAX + "] at "
+ now.toLocaleTimeString()
);
The CreateSystemInformation function adds a single-line entry in the alarm log without triggering an audible horn, which is the right escalation level for a UI-side correction.
Strategy 3: Clamp in the PLC
For process safety limits (for example, a hydraulic pressure that must never exceed the relief-valve setpoint), the clamp belongs in the PLC, not in the HMI. In an S7-1500 SCL block, the pattern is:
// S7-1500 SCL — write-side clamp for an array of Real
FUNCTION_BLOCK "FB_RecipeClamp"
VAR
i : INT;
END_VAR
BEGIN
FOR i := 1 TO 10 DO
IF "DB_Recipe".Temperature[i] < 0.0 THEN
"DB_Recipe".Temperature[i] := 0.0;
ELSIF "DB_Recipe".Temperature[i] > 250.0 THEN
"DB_Recipe".Temperature[i] := 250.0;
END_IF;
END_FOR;
END_FUNCTION_BLOCK
Call FB_RecipeClamp in a cyclic OB (typically OB1 or OB35) so the array is always bounded. The HMI's IO field then becomes a passive display — the operator can still type whatever, but the controller will overwrite it within one cycle. This is the safest pattern for limit values that have a real process consequence.
Verification Procedure
After the configuration is downloaded, run the following verification steps on the panel (or in the Unified PC simulation):
-
Scalar tag with built-in range. In the IO field, type a value above the configured high limit. The runtime must reject the entry, leave the previous value displayed, and raise system alarm
300205in the alarm log. - Scalar tag with built-in range, low side. Type a value below the configured low limit. The runtime must reject the entry.
-
Array element with no built-in range, script clamp on "Input finished". Type a value above the script's MAX. The IO field must immediately show MAX. Inspect the alarm log for the
CreateSystemInformationentry. - Array element with no built-in range, script clamp on "Process value change". Force the controller tag to an out-of-range value (use the watch table). The IO field must show the clamped value within one acquisition cycle.
- Boundary values. Enter exactly MIN, exactly MAX, MIN+0.1, MAX-0.1. All four must be accepted.
- NaN / empty string. Clear the IO field, leave it empty, then leave focus. The script must substitute MIN and not crash.
Troubleshooting Matrix
| Symptom | Likely root cause | Fix |
|---|---|---|
| Range fields in tag properties are grayed out | Tag is an array, UDT, or Byte
|
Use scalar member tag or attach a clamp script |
| Out-of-range entry is accepted | HMI tag has no built-in range and the IO field has no "Input finished" script | Add the script in Properties > Events > Input finished |
| Script fires but the value still goes through | Script writes to item.OutputValue but the IO field is bound to a different tag than the one being clamped |
Confirm Process value binding matches the tag referenced in Tags(...).Read/Write
|
Alarm 300205 fires constantly |
Controller is writing out-of-range values faster than the operator can correct them | Move the clamp into the PLC, or attach a script on Process value change as well |
| NaN appears in the IO field | Controller wrote an uninitialized real; IO field displays NaN
|
Add an isNaN check in the script and substitute MIN |
| Tag not visible in the IO field tag picker | Tag has not been compiled into the HMI, or the connection is offline | Recompile the HMI; check Devices & Networks for the connection status |
| IO field accepts the value but the controller shows the old value | Acquisition cycle is too long, or the controller's optimized block access prevents the write | Reduce the acquisition cycle; ensure the PLC tag is declared "Accessible from HMI" or that the DB is non-optimized for S7-1200/1500 with absolute addressing |
| Faceplate shows the IO field without a clamp | The faceplate is using a typed wrapper that swallows the Input finished event | Use strategy 3 (PLC-side clamp) for faceplate-bound fields, or rebuild the faceplate to expose the event |
Engineering Notes and Field Caveats
Real number comparison. Never compare two Real values with == in the JavaScript; use a tolerance (e.g. Math.abs(a - b) < 1e-6). This is especially relevant when the IO field's display format is rounded to one decimal place but the underlying Real is at full precision.
Acquisition cycle vs. operator write. A write to a PLC tag from the IO field is event-driven; a read is cycle-driven. If the acquisition cycle is 2 s and the operator enters a clamped value, the next read may briefly show the old controller value before the new one settles. The fix is to also write the clamped value to the tag in the script, so the next read returns the same value the operator sees.
Locales and decimal separators. The IO field respects the project's configured decimal separator. In a German project the separator is , and the script's Math.round(value * 10) / 10 will still work because it operates on the numeric value, not the string. If the script is doing string manipulation, force parseFloat(value.replace(',', '.')) first.
Bulk tags from third-party controllers. When the controller is a non-Siemens PLC (Allen-Bradley, Beckhoff, Codesys, Modbus), the HMI tag is often created as a "raw" tag without a data type. The Acquisition mode in the tag properties must be set to Cyclic continuous (not On demand) for the IO field's "Process value change" event to fire predictably. See the Siemens SIMATIC HMI connection manual for driver-specific guidance.
Optimized block access on S7-1500. An optimized DB hides the absolute addresses that the HMI tag editor wants to use. Either uncheck Optimized block access on the DB, or use the symbolic address (the data block name and tag name) in the HMI tag's PLC address field. Optimized DBs are the recommended pattern in TIA Portal V17, so prefer the symbolic approach.
Audit trail. The Input finished script runs in the Unified runtime, not in the controller, and therefore is not part of the S7-1500 audit trail. If the recipe values are regulated (e.g. pharmaceutical batch records), use strategy 3 (PLC-side clamp and PLC-side audit log) instead of an HMI script.
Quick Reference: Tag Data Type and Limit Support
| PLC tag type | Bound to IO field directly? | Built-in range usable? | Recommended approach |
|---|---|---|---|
Bool |
Yes (use checkbox) | No | Toggle / checkbox |
Int, DInt, LInt
|
Yes | Yes | Set range in tag properties |
Real, LReal
|
Yes | Yes | Set range in tag properties |
Byte |
Yes | Often ignored | Use USInt for clamping |
Array of Real |
Yes (whole array) | No | Per-element tag or script clamp |
| UDT/struct | Yes (whole struct) | No | Per-member tag or script clamp |
String |
Yes | No (length only) | Set string length in tag properties |
Summary
Putting a PLC tag into a WinCC Unified V17 IO field is a one-line binding under Properties > General > Process value. Applying a min/max clamp to that tag depends entirely on the tag's data type: scalar integer and real tags accept the built-in range fields and reject out-of-range entries with system alarm 300205; arrays, UDTs, and Byte tags do not. For arrays, the pragmatic answers are to expose per-element HMI tags (and use the built-in range), to attach a JavaScript to the IO field's Input finished or Process value change event that clamps to the desired window, or to push the clamp into the PLC and treat the IO field as a passive display. Whichever strategy is chosen, the verification procedure above must be executed on the live panel before the screen is released to operations.
Why is the "Range" section in my HMI tag properties grayed out?
The tag's data type is not a scalar integer or real. WinCC Unified V17 hides the range fields for Array, UDT, String, and the Byte type. Use a per-element HMI tag, an USInt-typed tag, or a clamp script attached to the IO field event.
How do I apply a min/max limit to an IO field bound to a Real tag?
Open the HMI tag's Properties > Range and enter the low and high values. Compile and download the HMI. The runtime will reject any out-of-range operator entry and raise system alarm 300205. For Array of Real tags, attach a JavaScript to the IO field's Input finished event that clamps value to the desired window and writes the result back via item.OutputValue = ….
Why does the operator-entered out-of-range value get written to the controller anyway?
The HMI tag carries no built-in clamp (because it is a complex type or a Byte) and the IO field has no Input finished script. Add the clamp script shown above, or move the clamp into the PLC. Confirm with a deliberately invalid entry in the watch table that the value is rejected before going on-machine.
Can the IO field's clamp be enforced from the controller side?
Yes. In an S7-1500 SCL function block, run a FOR loop over the array and overwrite out-of-range elements on every cycle (or on every write). The IO field then becomes a passive display. This is the recommended pattern for process safety limits and for regulated audit trails.
Where can I find the official documentation for the "Input finished" event and item.OutputValue?
The WinCC Unified V17 scripting reference is included in the TIA Portal Help under WinCC Unified > Programming Reference > JavaScript API > Screen items > IO field. The full system manual is also available on the Siemens Industry Online Support portal under the WinCC Unified V17 product page.