WinCC VBScript Cyclic Conversion Fails at 100ms Root Cause

David Krause13 min read
SiemensTroubleshootingWinCC
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

1. Problem Statement

Engineers integrating SIMATIC WinCC V7 with an external RTU commonly scale process variables before retransmission. One recurring field report is a cyclic VBScript in the Graphics Designer that performs a divide-by-1000 conversion (kV to MV, kA to MA, kW to MW) and writes the result to an OPC tag, triggered every 100 ms through a timer or trigger tag. The script is intended to mirror the conversion the HMI shows to the user.

The failure pattern is consistent and diagnostic:

  • The trend/log display shows the converted (MV) value continuously, but the OPC output to the RTU periodically reverts to the original 1000x value for one or more scan cycles.
  • The reverted value appears for less than one second, then the script catches up and the converted value returns.
  • Increasing the picture refresh to 2 s masks the symptom but does not eliminate the underlying race condition.
  • The data flow chain is: Field -> PLC (S7-300/400/1200/1500) -> WinCC Named Connection (S7 Protocol Suite) -> WinCC internal tag -> VBS division -> OPC tag -> RTU.

Why the value reverts, why 100 ms is the threshold of failure, and how to make the conversion rock-solid on WinCC V7.2 through V7.5 SP2 is the focus of this article.

2. Affected Versions and Platforms

Product Version Status
SIMATIC WinCC V7 7.2 / 7.3 / 7.4 / 7.4 SP1 / 7.5 / 7.5 SP1 / 7.5 SP2 VBScript cyclic execution limited by runtime scheduler
SIMATIC WinCC Professional (TIA Portal) V15 / V16 / V17 / V18 / V19 Same VBScript scheduler constraints
WinCC Runtime / RT All editions VBScript execution throttled under load
WinCC OA (Open Architecture) 3.16+ Not affected (uses CTRL scripting, different model)

All WinCC V7 variants share the same VBScript engine described in the WinCC Information System under Working with WinCC > VBScript for Actions. The behavior is consistent across Service Packs.

3. Root Cause Analysis

Three independent mechanisms combine to make a 100 ms cyclic VBScript unreliable in WinCC. None of them are bugs in the conventional sense; they are documented design choices of the runtime.

3.1 VBScript Scheduler Slices and Execution Slips

WinCC V7 runs VBScript actions on a single shared scripting thread that is preempted by the picture update, tag logging, and alarm logging threads. When the VBScript triggers on a standard cycle of 100 ms, the actual execution window is non-deterministic. If the runtime is busy with a picture redraw, an archive segment switch, or an alarm-acknowledgement event, the VBS trigger is marked as expired and the next script invocation catches up. From an external OPC/RTU consumer, the divide step is therefore skipped for that tick and the unconverted tag is forwarded.

The trigger mechanism itself (configured in the action properties dialog) offers the options Standard cycle, Window cycle, Tag trigger, and Event. Only the Tag trigger mode guarantees one execution per qualifying tag change; the Standard cycle mode allows silent drops under load.

3.2 Why Linear Scaling Was Rejected in the Original Design

The WinCC Information System documents a Linear Scaling property on every WinCC tag (right-click tag > Properties > Linear Scaling). It allows a Y = mX + b transformation to be applied transparently to the value retrieved from the PLC. Engineers new to WinCC typically propose this as the fix. In the field case under discussion, however, linear scaling was explicitly rejected because:

  1. The HMI must display the original (kV) value to the operator, while the RTU must receive the scaled (MV) value.
  2. Linear scaling in the tag properties modifies the value that WinCC presents to all consumers. The OPC tag, the trend, the alarm, and the faceplate all see the same scaled number.
  3. The OPC tag that feeds the RTU cannot be the same tag used for the HMI display, because the HMI needs the raw value.

This rules out a naive single-tag linear-scaling solution, but it does not rule out the correct two-tag topology described in Section 4.

3.3 Thread-Starvation Compounding Effect

When a cyclic VBScript is placed in a picture (Picture-Scope action), it competes with the picture's own redraw. On a project with many VBS actions, multiple picture windows, and aggressive trend refresh, the cumulative demand exceeds the scheduler's budget. The result is the script runs but late symptom that presents as a value-flicker. The VBScript runtime in WinCC is documented as a single-threaded apartment model; concurrent execution is not supported. The cumulative effect of ten scripts at 100 ms is roughly equivalent to one script at 10 ms, which the scheduler will silently downgrade.

4. Recommended Solutions (In Order of Preference)

4.1 Solution A - Move the Division into the PLC (Best Practice)

This is the only option that removes WinCC from the critical path entirely. The PLC owns the engineering units and is the only deterministic participant in the system.

  1. Add a new tag in the PLC, e.g. DB100.DBD0 REAL "Voltage_MV", with the conversion performed in the cyclic OB:
// SCL in OB35 / cyclic task, 100 ms example
"Voltage_MV" := "Voltage_kV" / 1000.0;
// Or in ladder: DIV_R with 1000.0 as divisor
  1. Add the new tag to the WinCC tag list (S7 Protocol Suite, Named Connection) alongside the existing Voltage_kV tag.
  2. Use the original tag for the HMI display and the new scaled tag for the OPC output to the RTU.
  3. Delete the VBScript action and its trigger entirely.

This approach is the Siemens-recommended pattern for any scaling or unit conversion. It survives SCADA restart, runtime redundancy failover, and loss of picture focus. Reference: WinCC Information System, Tags > S7 Protocol Suite > Tag Properties.

4.2 Solution B - Linear Scaling on a Second Internal Tag

Where a PLC change is not possible (existing system, signed-off PLC program, OEM-locked PLC code), create a second WinCC tag on the same S7 address and apply linear scaling only to that tag.

  1. In WinCC Explorer, open the S7 Protocol Suite > Named Connection > tags list.
  2. Add a new tag Voltage_MV_Display pointing to the same S7 address (e.g. DB100,DD0).
  3. Open the new tag's Properties dialog and select Linear Scaling.
  4. Configure:
Field Value
Process value range (PLC) 0 ... 500000
Tag value range (WinCC) 0 ... 500
Linear scaling Enabled

The internal arithmetic is Y = (X - PLC_min) * (WinCC_max - WinCC_min) / (PLC_max - PLC_min) + WinCC_min. With the values above this collapses to Y = X / 1000. WinCC performs this in native C++ code, not in the VBScript scheduler, so the result is always available at every cycle.

Note: The HMI faceplate must be bound to the scaled tag (Voltage_MV_Display), and the OPC output to the RTU must be bound to the same scaled tag. The unscaled tag Voltage_kV is then no longer needed for this display path. If the operator genuinely must see the unscaled kV value in a different view, expose both tags on the same address.

4.3 Solution C - Increase VBScript Cycle to 1000 ms or Greater

If the division must stay in VBScript, the cycle must be raised to a value at which the scheduler can deliver every trigger. Empirically and as documented in WinCC performance notes:

Cycle Reliability Comment
100 ms Unreliable under any meaningful load Avoid
250 ms Marginal Acceptable for single-script systems only
500 ms Acceptable for low-load systems Documented in WinCC performance guide
1000 ms (1 s) Reliable Recommended minimum for cyclic conversions
2000 ms (2 s) Recommended Default in many reference projects
Tag trigger Most reliable Reacts to value change, not wall clock

The user observation that the failure happens in less than 1 second is consistent with the 100 ms cycle being collapsed to a roughly 1 s effective period under scheduler pressure. Raising the cycle to 2 s resolves the symptom because the scheduler has time to service all queued triggers.

4.4 Solution D - Move the Action to Global Script (Background)

Picture-scoped actions compete with picture redraws. Moving the action to Global Script > VBS Editor > Action running in the background releases the picture thread. The action is then associated with a trigger (tag change or standard cycle) that runs on the background scheduling thread.

  1. Open WinCC Explorer > Global Script > VBS Editor.
  2. Create a new action: New Action > Trigger on Tag Change.
  3. Configure the trigger tag (e.g. Voltage_kV).
  4. Implement the division:
Dim rawValue
Dim scaledValue

rawValue = HMIRuntime.Tags("Voltage_kV").Read
If IsNumeric(rawValue) Then
    scaledValue = CDbl(rawValue) / 1000.0
    HMIRuntime.Tags("Voltage_MV_OPC").Write scaledValue
End If
  1. Save the action. WinCC stores the compiled code in the project directory.
  2. Open Computer > Properties > Startup and verify the action is registered to autostart.

Tag-triggered actions are not bound to a wall-clock cycle, so they do not suffer from the dropped-trigger problem of standard-cycle actions. This is the preferred VBScript-only solution when the PLC cannot be modified.

5. Why the OPC Consumer Sees the Raw Value When the VBS Skips

The WinCC internal data model does not remember a prior scaled value. If the VBScript fails to execute, the OPC tag retains its last successfully written value, but the next successful execution overwrites it with the new scaled value. In the meantime, if any other write to that OPC tag (such as a manual test in the tag simulator) writes the raw value, or if the OPC tag is configured with initial value equal to the raw process tag, the unscaled value is observed externally.

The remedy is to disable the OPC tag's Update on Tag Change behavior and rely exclusively on the VBS write. Alternatively, ensure the OPC tag's initial value is a clearly invalid sentinel (e.g. -9999) so a missed VBS tick is immediately visible to the RTU rather than silently substituted.

6. Step-by-Step: Implementing Solution A (PLC-Side Conversion)

  1. Identify the source tag in the PLC. In STEP 7 / TIA Portal, find the data block address of the kV value, e.g. DB100.DBD0 (REAL).
  2. Add the scaled tag. In a new data block (e.g. DB101), add Voltage_MV REAL.
  3. Insert the scaling code in a cyclic OB (OB1, OB35, or OB30 depending on the desired update rate). For 100 ms refresh, use OB35 with a 100 ms cycle time in the CPU properties.
  4. Compile and download the PLC program. Verify the new tag updates in a watch table.
  5. Update the WinCC tag list. In the S7 Protocol Suite, add Voltage_MV mapped to DB101.DBD0. Keep Voltage_kV mapped to DB100.DBD0 if the operator display still requires it.
  6. Update the OPC mapping. The OPC server (WinCC OPC-DA, WinCC OPC UA) exposes Voltage_MV as a separate item. Point the RTU to this new item.
  7. Delete the VBScript action from the picture and from Global Scripts. Save and recompile the OS.
  8. Activate the WinCC project and verify with an OPC client (e.g. OPC Scout V10, UaExpert) that the value scales correctly at every tick.

7. Verification Procedure

  1. Static test: Force a constant value in the PLC. Watch the OPC tag for at least 5 minutes. Confirm zero deviations.
  2. Dynamic test: Apply a step change in the PLC. Confirm the OPC tag responds within one PLC cycle and stays at the scaled value.
  3. Load test: Open every picture in the project, force a tag storm (write the same value to 1000 tags via S7 PUT), and watch the OPC tag. It must remain at the scaled value continuously.
  4. RTU confirmation: Have the RTU log both the raw and the scaled value over a 24-hour window. Confirm zero crossings of the scaled value back to the unscaled value.
  5. Restart test: Restart the WinCC Runtime. Confirm the OPC tag recovers to the correct scaled value within the configured startup delay.

8. Performance Best Practices for WinCC VBScript

  • Never run more than ten VBScript actions on a 100 ms cycle in a single project.
  • Prefer tag-triggered actions over time-triggered ones; tag triggers are event-driven and do not collapse under load.
  • Move heavy logic out of picture actions into Global Script background actions.
  • Use HMIRuntime.Tags(...).Read and .Write in batched form, not in a loop inside one action.
  • Avoid HMIRuntime.Screens access from background actions; it is not thread-safe.
  • Cache tag handles outside the action body. Each HMIRuntime.Tags("name") call allocates a new object.
  • For data exchange with external systems, use the OPC DA/UA server directly rather than intermediate WinCC tags whenever feasible.

9. Alternative: WinCC Calculations (Calc Tag Type)

For pure arithmetic that must remain in WinCC, WinCC V7.3+ supports a Calculation tag type that executes a C-like expression on a fixed scheduler. Unlike a VBScript action, a calculation tag runs in the tag manager, which has higher priority and predictable timing. The expression (rawValue / 1000.0) is valid. Configure in WinCC Explorer > Tag Management > Add Tag > Type: Calculation. This is documented in the WinCC Information System under Tags > Internal Tags > Calculation Tags.

10. Diagnostic Steps When the Symptom Persists

  1. Open the WinCC Diagnosis window: Start > SIMATIC > WinCC > Diagnosis. Inspect the Performance tab. Look for action overrun counters.
  2. Open the GDI and USER object usage via Task Manager > Details > WinCCExplorerManager.exe. GDI objects > 1000 per process indicates a picture-related issue independent of VBScript.
  3. Enable the VBScript trace in Computer > Properties > Graphics Runtime > Debug > Trace. Look for Action ... not executed messages.
  4. Check the Windows Application event log for VBScript error events from the WinCC source.
  5. Use the WinCC ApDiag tool to inspect the action queue depth and individual action runtimes.

A generic VBScript runtime (such as the script host described in public Microsoft Learn discussions about VB projects that terminate after 15 seconds of inactivity) is a different scenario from WinCC Runtime. The 15-second termination in those discussions applies to the standalone VB6 IDE / VSTA host and does not affect the WinCC VBScript engine. The WinCC scheduler does not have a 15-second idle timeout; it uses the trigger mechanism described in Section 3.

11. Summary and Decision Matrix

Solution Determinism PLC Effort SCADA Effort Recommended For
A. PLC-side conversion Highest Low (one SCL line) None (delete script) All new projects, OEM-locked PLCs, redundant systems
B. Linear scaling on duplicate tag High None Low Existing projects where PLC is frozen
C. 2 s VBScript cycle Medium None None Diagnostic only, not production
D. Tag-triggered Global Script High None Medium Projects that must keep logic in WinCC
E. Calculation tag (V7.3+) High None Low Pure arithmetic, single tag mapping

FAQ

Why does my 100 ms VBScript in WinCC sometimes not execute?

The WinCC V7 VBScript scheduler uses a single shared thread that competes with picture redraw, tag logging, and alarm processing. Under load, 100 ms trigger ticks are silently dropped and the script catches up later, which is observed externally as the unconverted value being forwarded to OPC/RTU. Raise the cycle to 1000-2000 ms, switch to a tag-triggered action, or move the division into the PLC.

Can I use linear scaling in WinCC tag properties for kV to MV conversion?

Yes, if the conversion target is the HMI display only. Linear scaling modifies the value every consumer of the tag sees, so the HMI and the RTU must read from different tags. Map two WinCC tags to the same PLC address, leave the first unscaled, and apply linear scaling (PLC 0-500000 to WinCC 0-500) to the second. WinCC performs the arithmetic in native code, bypassing the VBScript scheduler.

What is the minimum reliable VBScript cycle in WinCC V7?

1000 ms is the documented reliable minimum for cyclic VBScript actions. 500 ms is acceptable in low-load systems. 100 ms is only safe when the action is the only VBScript in the project. For all conversion logic, prefer tag-triggered actions or PLC-side conversion.

How do I keep the original kV value on the HMI but send MV to the RTU?

Create two WinCC tags on the same PLC address. Bind the unscaled tag to the HMI faceplate. Apply linear scaling to the second tag and bind it to the OPC output that feeds the RTU. This is the cleanest two-consumer topology and removes the VBScript from the critical path entirely.

What is the difference between a picture-scoped VBScript and a Global Script action?

A picture-scoped action lives in the Graphics Designer and competes with picture redraws. A Global Script action runs in the background scheduler and is not affected by picture focus or redraw. For cyclic conversions that must stay in VBScript, Global Script with a tag trigger is significantly more reliable than a picture action on a 100 ms cycle.

Back to blog