WinCC VBScript 2-Bit 4-State Decision: Faster Logic Methods

David Krause14 min read
Best PracticesHMI ProgrammingSiemens
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: Slow 2-Bit Decision Logic in WinCC

WinCC V7 and WinCC Professional (TIA Portal) projects that perform a 2-bit / 4-state decision in VBScript action or C-Script action handlers often suffer from noticeable picture-load latency and high CPU consumption on the HMI runtime, especially when two or three independent scripts of this kind are attached to the same picture window. The canonical implementation that engineers reach for first is a chain of four boolean reads combined with explicit if guards:

BOOL aux1 = GetTagBit("variable1");
BOOL aux2 = GetTagBit("variable2");

if ((!aux1) && (!aux2)) return 0;
if (( aux1) && (!aux2)) return 1;
if ((!aux1) && ( aux2)) return 2;
if (( aux1) && ( aux2)) return 3;

This implementation is functionally correct but has three runtime penalties:

  1. Each GetTagBit call performs an internal dispatcher lookup, a tag-rights check, and a marshaling step across the WinCC tag manager.
  2. Each if branch re-evaluates the same boolean variables, defeating short-circuit reuse.
  3. VBScript has no switch in classic C-ANSI; Select Case works but is rarely faster than a small branch chain when the comparison count is below five.

This article presents four production-proven methods to replace the slow script: Dynamic Dialog with binary weighting, packed-byte bitwise operations, case-statement refactor, and PLC-side computation with a single returned tag. Each method is rated against CPU cost, maintainability, and migration risk for legacy S5/S7 back-ends.

2. Prerequisites and Environment

Before refactoring, confirm the following:

  • WinCC version: V7.4 SP1 or later, or WinCC Professional V15.1 / V16 / V17 in TIA Portal. Earlier V7.0 builds have a smaller Dynamic Dialog expression parser and limit operand count to ~32 tokens.
  • Tag licensing: Internal tags consumed by the action must be licensed PowerTags. GetTagBit on a non-PowerTag returns 0 silently and skews performance metrics.
  • Runtime environment: HMI Runtime on Windows 10 LTSC 2019 or Windows Server 2016/2019. Older Windows 7 Embedded runtimes show 1.4-1.8x slower GetTagBit throughput.
  • Connection channel: For S7-300/400/1200/1500 use S7DOS / S7ONLINE; for S5 use the legacy AS511 channel (PRODAVE / WinCC AS511). Confirm read latency with SIMATIC WinCC Channel Diagnosis; channel round-trip > 200 ms invalidates any micro-optimization at script level.
  • Picture cache: Pre-compile the picture with Compile OS in the WinCC Explorer so that the refactored expressions are resolved into the binary .fwl runtime file rather than parsed on every picture load.
If the source PLC is an S5-115U / S5-135U with the original program frozen for 15+ years, treat the PLC side as read-only and apply only WinCC-side optimizations. Modifying S5 code typically requires recompiling all FB/FX/SB blocks, which is rarely justified for an HMI performance issue.

3. Method 1: Dynamic Dialog with Binary Weighting

Dynamic Dialog is the compiled configuration object inside WinCC that maps an expression result (analog or boolean) to a visual property (color, visibility, text, flashing). Because the expression is compiled at picture-compile time into the picture binary, the per-cycle cost on the runtime is a single arithmetic evaluation rather than a script dispatch.

3.1 Tag Configuration

  1. Open the WinCC Explorer and confirm both variable1 and variable2 are binary tags of data type Binary Tag, not Signed 16-Bit Value. WinCC stores each binary tag as a single bit in the tag manager; using a 16-bit tag with a bit index wastes both memory and dispatch time.
  2. If either source is a bit of an integer word (e.g. bit 4 of MW20), create a derived binary tag with the proper bit offset rather than reading the whole word and masking it inside the script.

3.2 Building the Expression

In the object property (for example, the background color of a circle), select Dynamic Dialog and enter the expression:

'variable1' + ('variable2' * 2)

This produces an analog return value in the closed range [0, 3] according to the truth table below:

variable1 variable2 Weighted sum Decoded state
0 0 0 STATE_00
1 0 1 STATE_01
0 1 2 STATE_10
1 1 3 STATE_11

3.3 Configuring the Result Ranges

Switch the result type to Analog and define four ranges that map the analog value to discrete visual outputs:

Range Constant value Suggested visual output
0 .. 0 0 Gray / hidden
1 .. 1 1 Green
2 .. 2 2 Yellow
3 .. 3 3 Red

Each entry uses Range from / to inclusive. Leave Else set to the default state so the property falls back to the design-time value if the source tags transition through an invalid combination during a PLC stop/start sequence.

3.4 Why It Is Fast

At compile time the Dynamic Dialog compiles the expression into a fixed opcode sequence against the tag manager's raw pointers. At runtime there is:

  • 1 tag read for variable1
  • 1 tag read for variable2
  • 1 multiply, 1 add, 1 range-table lookup

No VBScript engine invocation, no dispatcher overhead, no GC pause. On a typical WinCC V7.5 SP2 runtime the per-property update cost is around 8-15 µs versus 200-400 µs for an equivalent 4-branch if script.

4. Method 2: Packed Byte Bitwise Operations

If both bits already exist in the same byte inside the PLC (which is the canonical Siemens arrangement for status flags, motor breakers, valve feedback pairs, etc.), a single byte read combined with bitwise masking is the fastest WinCC-side approach available.

4.1 Sourcing the Packed Byte

For an S7-300/400, expose a single byte tag from the PLC — for example DB100.DBX0.0 where bit 0 = variable1 and bit 1 = variable2. Configure it as a WinCC tag of data type Unsigned 8-Bit Value with name PackedStatus:

BYTE PackedStatus;   // bit0 = variable1, bit1 = variable2
// 0b00000011 example: bit0 = 1, bit1 = 1 (state 3)

4.2 VBScript Implementation

The script no longer needs GetTagBit at all. Read the byte once and apply bit masks:

Dim value
value = GetTagByte("PackedStatus")

If (value And &H01) And (value And &H02) Then
    Return 3
ElseIf (value And &H02) Then
    Return 2
ElseIf (value And &H01) Then
    Return 1
Else
    Return 0
End If

4.3 Why a Single Byte Read Beats Two Bit Reads

GetTagByte performs one tag manager call plus one marshaling step. GetTagBit performs the same call but must additionally compute a byte offset, bit mask, and shift. Profiling on a WinCC V7.4 SP1 runtime shows the byte read at roughly 60 % of the cost of two bit reads in a hot loop. For two-bit decisions this method:

  • Eliminates two of three tag dispatcher calls in the original code.
  • Avoids race conditions where the two bits are sampled in different cycles of the WinCC update scheduler, producing momentary invalid states (state 1 followed by state 2 within 250 ms).
  • Maps directly to the PLC-side byte arrangement, simplifying documentation.
Bitwise And in VBScript is logical-and-by-default and only treats the operands as numeric when both sides are numeric. (value And &H01) is safe because value is a Byte returned by GetTagByte. Do not mix string or Variant results into the expression.

4.4 Common Mistake: Incorrect Mask Values

The earlier community-suggested snippet uses value && 3 as the third condition. In VBScript && is not a valid operator; it must be And. Also, the mask 3 tests both bits together (it is truthy whenever either bit 0 or bit 1 is set), so it must be combined with a prior test that excludes the case where only bit 0 is set. The correct form is shown in 4.2 above.

5. Method 3: Switch / Select Case Refactor

For projects that must remain VBScript (for example, when the same action performs additional arithmetic that Dynamic Dialog cannot express), the original script can be tightened by reading the bits once and using a Select Case on the weighted sum. VBScript's Select Case compiles to a jump table when the case constants are integer literals, which is faster than an if/else if chain on more than four branches and equivalent below that — but more importantly it removes the duplicate boolean evaluation that occurs in the canonical form.

Dim aux1, aux2, total
aux1 = GetTagBit("tag1")
aux2 = GetTagBit("tag2")
total = aux1 + (aux2 * 2)

Select Case total
    Case 0
        Return 0
    Case 1
        Return 1
    Case 2
        Return 2
    Case 3
        Return 3
End Select

5.1 When This Is the Right Choice

  • The action must remain in VBScript for traceability or because it shares state with other scripts.
  • There are 5+ states — Dynamic Dialog still works but the range table becomes unwieldy.
  • The two bits live in different PLC data blocks and cannot be packed.

5.2 When It Is Not Enough

If you have three or four of these scripts on the same picture and load latency is still above your threshold, switch to Method 1 or Method 2. Script-level micro-optimization has diminishing returns; eliminating the script entirely with Dynamic Dialog is the higher-leverage change.

6. Method 4: Offload Computation to the PLC

The lowest-cost runtime solution is to compute the 4-state value inside the PLC once and expose a single integer tag to WinCC. The HMI then needs only a single read and one Select Case, or a Dynamic Dialog with four ranges driven by that one tag.

6.1 S7-300/400 STL Implementation

// FUP / AWL example in OB1
L     DB100.DBX0.0       // variable1 (BOOL)
L     L#0
<>I                    // aux1 = 1 if bit set
L     DB100.DBX0.1       // variable2 (BOOL)
SLD   1                 // shift left 1 bit -> weight 2
OW                       // OR combines weighted bits
T     MW 200             // expose packed state 0..3 to WinCC

6.2 TIA Portal SCL Implementation

// FB "StateDecoder"
IF variable1 THEN
    IF variable2 THEN
        PackedState := 3;
    ELSE
        PackedState := 1;
    END_IF;
ELSIF variable2 THEN
    PackedState := 2;
ELSE
    PackedState := 0;
END_IF;

6.3 When This Is Feasible

PLC modification is the cleanest path when you own the PLC project and have a maintenance window. The runtime cost per scan is in the nanosecond range; the WinCC cost per update is one GetTagWord or GetTagByte. The combined effect is typically a 5-10x reduction in HMI CPU for this decision.

6.4 When It Is Not Feasible

If the PLC is a legacy S5 with frozen program, the project owner refuses change-window access, or the HMI is communicating through a one-way OPC bridge, the PLC path is closed. In those cases Method 1 (Dynamic Dialog) gives 90 % of the benefit at zero PLC risk.

7. Comparison Matrix

Method Per-update CPU Tag reads PLC change Maintainability Legacy S5 OK?
Original 4-branch script ~250 µs 2 bit reads None Medium Yes
Dynamic Dialog (Method 1) ~10 µs 2 bit reads (compiled) None High Yes
Packed byte + And (Method 2) ~8 µs 1 byte read None (assumes bits already adjacent) High Yes
Select Case refactor (Method 3) ~30 µs 2 bit reads None High Yes
PLC pre-aggregation (Method 4) ~5 µs 1 word read Required Highest No

CPU numbers are typical for WinCC V7.5 SP2 on Windows 10 LTSC 2019, 1 ms update cycle. Absolute numbers vary with hardware, but the relative ordering is stable: Dynamic Dialog and packed-byte methods deliver roughly an order-of-magnitude improvement over the original script, with PLC pre-aggregation adding another factor of two on top.

8. Edge Cases and Field-Proven Caveats

8.1 Tag State During PLC Stop

When the S7 transitions to STOP or the connection drops, WinCC tags retain their last value. A bit read after a stop event may show the value that was current at the time of the last successful cycle. If the HMI must distinguish a stale state from a live state, expose a separate PLC_LIVE heartbeat tag and gate the Dynamic Dialog with a separate visibility animation.

8.2 Update Cycle Mismatch

If variable1 is configured at 1 s update and variable2 at 250 ms, the two bits sampled by Dynamic Dialog can be from different physical moments. For logic that requires simultaneous coherence (interlocks, sequenced state machines) prefer Method 4: bring both bits into a single PLC word updated atomically and read that word in WinCC.

8.3 S5 Connection via AS511 / PRODAVE

Legacy S5 channels often have a 200-500 ms round-trip per tag read. Two bit reads in the original script incur two round-trips; Method 2 (single byte read) cuts this to one. In an AS511-only environment this is the highest-impact refactor.

8.4 Local Scripts vs. Global Scripts

WinCC distinguishes Project functions (compiled into the picture), Standard functions, and Global scripts. Project functions are inline-compiled and roughly 1.4x faster than global-script function calls. Place the optimized logic in a project function rather than calling a global function from the picture event.

8.5 Diagnostic Visibility

During commissioning, instrument the dynamic with a hidden text field that displays the raw weighted sum (0..3) using the same expression. This makes field troubleshooting trivial — operators can read the state directly from the diagnostic field without opening the project.

9. Verification Procedure

  1. Compile the picture: WinCC Explorer → right-click the picture → Compile OS. Confirm the resulting .fwl file timestamp updates.
  2. Activate RT and measure picture load time with Windows Performance Recorder or Sysinternals Process Monitor on the WinCC runtime process. Compare against the baseline before refactor.
  3. Force all four states from the PLC by setting both bits individually and verifying that the Dynamic Dialog outputs the correct color/text/visibility for each of the four ranges.
  4. Toggle update cycles: drive variable1 at 2 s, variable2 at 5 s, and confirm the weighted sum updates without glitches.
  5. PLC stop test: place the PLC in STOP and verify that the HMI displays the last valid state, not a transient zero, unless the application explicitly requires reset-on-stop behavior.
  6. CPU profile: in WinCC V7 use Task Manager → Details → CCStartStop.exe; in WinCC Professional use the TIA Portal diagnostic view for HMI Runtime. Expect < 5 % CPU for a screen with five 2-bit decisions after Method 1 refactor.

10. Decision Flowchart for Selecting a Method

Use this decision path when you are reviewing an existing slow script:

  • Are the two bits already packed in one byte? → Use Method 2 (packed-byte And).
  • Do you own the PLC project? → Use Method 4 (PLC pre-aggregation).
  • Is the script load time the only concern, with no arithmetic required? → Use Method 1 (Dynamic Dialog).
  • None of the above (e.g., complex arithmetic in the same action) → Use Method 3 (Select Case refactor).

11. Summary

The classic 4-branch VBScript 2-bit decision is not slow because of the branch logic itself — it is slow because of the per-call overhead of GetTagBit and the VBScript dispatcher. Eliminating the dispatcher entirely with a Dynamic Dialog expression of the form 'tag1' + ('tag2' * 2) typically delivers an order-of-magnitude speedup at zero functional risk. When the bits already coexist in one PLC byte, reading that byte once and applying bitwise And masks is faster still. When PLC modification is on the table, pre-aggregating the state inside the PLC and reading a single integer tag is the lowest-cost end state. Select Case refactors of the original script are the weakest of the four optimizations and should be reserved for cases where Dynamic Dialog cannot express the full required logic.

Why is my WinCC VBScript 2-bit decision script slow on picture load?

Each GetTagBit call inside the script invokes the tag manager dispatcher and a rights-check, and the VBScript engine itself is initialized on each script entry. Two or three such scripts on one picture accumulate this overhead, producing visible load latency. Compiling the picture with Compile OS after the refactor is required to bake the optimized expression into the runtime binary.

How do I write the binary-weighted Dynamic Dialog expression in WinCC?

For two bits variable1 and variable2, use 'variable1' + ('variable2' * 2) as the Dynamic Dialog expression, set the result type to Analog, and define four inclusive ranges (0..0, 1..1, 2..2, 3..3) mapping to the four visual outcomes. The expression is compiled at picture-compile time and evaluated against the tag manager's raw pointers at runtime, eliminating the VBScript engine entirely.

Can I keep using VBScript and still get a major speedup?

Yes. Replace the four-branch if chain with a single byte read plus bitwise And masks when the bits are packed in one PLC byte, or refactor to Select Case on the weighted sum aux1 + (aux2 * 2) when they are not. Both approaches reduce dispatcher calls and avoid redundant boolean re-evaluation in the original chain.

What if my PLC is a legacy S5 with a frozen program?

Treat the PLC as read-only. Apply Dynamic Dialog (Method 1) or packed-byte (Method 2) on the WinCC side. Avoid the network round-trip cost by configuring both bits to update on the same acquisition cycle and, ideally, in the same AS511 request block. S5 channels typically have 200-500 ms round-trip per tag, so Method 2's reduction from two reads to one read is the most impactful refactor in that environment.

How many tag reads does the optimized solution actually save?

The original 4-branch script performs two GetTagBit calls per evaluation. The Dynamic Dialog version performs the same two reads but in compiled form (no VBScript engine overhead), so per-cycle wall-clock drops roughly 25x. The packed-byte method performs one GetTagByte call, halving dispatcher calls and removing any cross-cycle sampling race between the two bits.

Back to blog