Toggling PLC Bits on Button Click in WinCC 7 with C and VBS

David Krause17 min read
HMI ProgrammingSiemensTutorial / How-to
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

Overview: Why Toggle a Bit in WinCC 7?

In Siemens WinCC V7 (the PC-based SCADA/HMI runtime that replaced WinCC Flexible for operator stations), the operator frequently needs a "press once to turn ON, press again to turn OFF" interaction model - the classic toggle. Unlike WinCC Flexible, where this could be wired through a single property without scripting, WinCC 7 requires either an ANSI-C action bound to a button event or a VBScript action using the HMIRuntime object model. Both approaches are stable and supported; choosing between them comes down to legacy project standards, performance budget, and tag data type.

The fundamental operation is identical in both languages: read the current value of the word, byte, or dword tag, XOR it with a single-bit mask (2^n), and write the result back. The XOR operation is the canonical "flip this bit" primitive in PLC data words because it leaves every other bit untouched. This article provides the field-ready implementation for both scripting languages, the exact WinCC Explorer navigation steps, the tag-naming conventions used with S7 PLC connections, and a verification matrix that catches the common mistakes before runtime.

Scope: This reference covers WinCC V7.0 through V7.5 SP2 (current at writing). The C script API is identical across these versions. The VBScript HMIRuntime object model has been stable since V7.0 and remains the recommended scripting path in current installations. See the SIMATIC WinCC V7.5 SP2 documentation for the official scripting reference.

Prerequisites and Project Preparation

Before binding a toggle action to a button, confirm the following prerequisites:

  • WinCC V7.x Runtime or WinCC V7.x RT/RC installed on the engineering station. Confirm in SIMATIC WinCC Explorer > Help > About. The minimum version that supports the VBS HMIRuntime object shown in this article is V7.0; SP2 or later is recommended for current TLS-based S7 connections.
  • A configured logical device with an active S7-1200, S7-1500, S7-300, or S7-400 connection. Tags must already be defined in the Tag Management editor and must be of type Binary Tag, Signed 16-bit, Unsigned 16-bit, Signed 32-bit, or Unsigned 32-bit depending on the underlying PLC area.
  • Authoring license: WinCC RT 128, RT 512, RT 2k, RT 4k, or RC. Configuration-only engineering is permitted on the same license.
  • Graphics Designer must be opened with edit permission. Pressing F5 while another engineer has the picture open in write mode produces the familiar "Picture is being edited" warning - close the picture first.
  • C Editor licensing: the ANSI-C compiler is included with every WinCC V7 installation - no extra license is required. However, the editor only appears in WinCC Explorer once a project has been opened and at least one picture has been touched.

Selecting the Right Tag Type for the Toggle

WinCC reads each PLC address either as a binary bit, a byte, a 16-bit word, or a 32-bit double word. The choice determines how the toggle is implemented:

PLC Address WinCC Tag Type Bit Toggle Mask Typical Use
DBx.DBXy.z (single bit) Binary Tag Direct invert via SetTagBit/GetTagBit Single hand/foot switch
DBx.DBBy (byte) Unsigned 8-bit XOR with 2^0 through 2^7 Status word packed flags
DBx.DBWy (word) Unsigned 16-bit XOR with 2^0 through 2^15 Recipe control word
DBx.DBDy (double word) Unsigned 32-bit XOR with 2^0 through 2^31 32-bit packed status
Why XOR instead of read-modify-write with a single bit? On a multi-task PLC scan, a naive value = read(); value = value & ~mask | (new_state ? mask : 0); write(); pattern races with the PLC: the PLC could update an adjacent bit between the read and the write, and that adjacent bit would be lost. XOR is preferred because it touches only the target bit, and a single read followed by a single write is the standard pattern when no other writer is competing. For applications where multiple HMI stations write to the same tag simultaneously, a PLC-side handshake or a direct bit toggle in the PLC is preferable.

Method 1: C Script with Reusable Word_bits Function

The classic WinCC 7 solution is a single ANSI-C project function called Word_bits that accepts the tag name and the bit number, then performs the toggle. The advantage is that the function lives once in the project library and is reused by every toggle button on every picture - changing the function (e.g., adding logging) updates every call site at once.

Function Logic (Pseudocode)

void Word_bits(char* tagName, int bitNo)
{
    DWORD value = 0;
    DWORD mask  = (DWORD)(1 << bitNo);

    /* 1. Read the current tag value */
    if (GetTagDWord(tagName, &value) == FALSE) {
        printf("Word_bits: GetTagDWord failed for %s\r\n", tagName);
        return;
    }

    /* 2. Toggle the target bit */
    value ^= mask;

    /* 3. Write the new value back */
    if (SetTagDWord(tagName, value) == FALSE) {
        printf("Word_bits: SetTagDWord failed for %s\r\n", tagName);
    }
}

The GetTagDWord/SetTagDWord API works for byte, word, and dword tag types because WinCC performs the data-width conversion internally. If your tag is binary, replace both calls with GetTagBit and SetTagBit and remove the XOR step (just write the inverted bit value directly). For the full C scripting reference see the SIMATIC WinCC V7 C scripting manual.

Step-by-Step: Importing Word_bits into the Project Library

  1. Open WinCC Explorer and select your project.
  2. Locate the project library folder in the Windows file system. The default path is C:\Program Files (x86)\Siemens\Automation\WinCC\WinCCProjects\<ProjectName>\Library. If the Library subfolder does not exist, create it manually before continuing.
  3. Copy Word_bits.fct into that folder. WinCC stores project functions as Pascal-style text files; the content is editable in any text editor for inspection but must be re-generated through the C Editor for the function to be registered with the runtime.
  4. Open the C Editor via the WinCC Explorer tree: right-click C-Editor > Open. If the editor is greyed out, close the project and reopen it from Start > All Programs > Siemens Automation > SIMATIC > WinCC > WinCC Explorer.
  5. Generate the header by clicking the Generate Header toolbar button (or pressing Ctrl+G). This compiles apdefap.h and the per-project header Project_Functions.h.
  6. Close the C Editor when prompted to save, accept. If the dialog asks about rebuilding the project, click Yes - this recompiles every C function and updates the runtime DLL cache.

Step-by-Step: Binding the Function to a Button Mouse-Click Event

  1. Open Graphics Designer and open the target picture.
  2. Select the button object that should perform the toggle. If you do not yet have a button, insert one from the Standard object palette: Smart Objects > Button or Windows Objects > Button.
  3. Open the object's property dialog (right-click > Properties or double-click the button).
  4. Navigate to Events > Mouse > Mouse Click in the left-hand tree.
  5. Right-click the right-hand value cell for Mouse Click and choose C Action. A dialog titled Edit C Action opens.
  6. Click the "..." button (or press Ctrl+Space) to open the function browser. The browser shows every function in the project library; double-click Word_bits to insert it.
  7. Fill in the parameters:
    • Tag: type or paste the WinCC tag name (e.g., DB41_DW15 for a 16-bit tag, MotorGroup_Status for a 32-bit tag). Use the internal tag name, not the display name. The internal name is shown in Tag Management > Tag name column.
    • Bit No: enter the bit position. For LSB use 0; for bit 7 use 7. Bit numbering is zero-based, where bit 0 = least significant bit (value 1) and bit 15 = most significant bit of a 16-bit word (value 32768).
  8. Click OK to close the parameter dialog and OK again to close the action editor. A small lightning-bolt icon appears next to Mouse Click indicating that the event is scripted.
  9. Save the picture (Ctrl+S) and close Graphics Designer.
  10. Activate the project in WinCC Explorer (right-click the project root > Activate).
Password-protected project functions? If the C Editor asks for a password when you attempt to open Word_bits, the function author has encrypted it. That is a deliberate choice to prevent unauthorised edits. The function itself still executes at runtime - encryption prevents viewing or modifying the source, not calling the function. To deploy an unencrypted copy, ask the project owner to remove the password via File > Properties > Password in the C Editor.

Method 2: VBScript XOR Inline Toggle

Modern WinCC 7 projects use VBScript exclusively. VBS actions are easier to read, easier to debug, and can be pasted directly into the field of an event without a separate library import. The trade-off is that the toggle logic is duplicated in every button event. For full VBScript syntax reference see the WinCC V7 VBScript reference.

Toggle Bit Inside a Word (16-bit tag)

'**** Toggle bit 0 in a 16-bit word tag ****
Dim curVal
curVal = HMIRuntime.Tags("DB41_DW15").Read
HMIRuntime.Tags("DB41_DW15").Write curVal Xor (2 ^ 0)

Toggle a Higher Bit in a Word

'**** Toggle bit 7 in a 16-bit status word ****
Dim curVal
curVal = HMIRuntime.Tags("DB41_DW15").Read
HMIRuntime.Tags("DB41_DW15").Write curVal Xor (2 ^ 7)

Toggle Bit Inside a Double Word (32-bit tag)

'**** Toggle bit 7 in a 32-bit status word ****
Dim curVal
curVal = HMIRuntime.Tags("DB42_DBD20").Read
HMIRuntime.Tags("DB42_DBD20").Write curVal Xor (2 ^ 7)

Toggle a Binary Bit Tag

'**** Toggle a single-bit tag ****
Dim curBit
curBit = HMIRuntime.Tags("DB41_DBX15_1").Read
HMIRuntime.Tags("DB41_DBX15_1").Write curBit Xor True

For a binary tag, the XOR mask is True (which VBScript treats as 1). Use the syntax Xor True rather than Xor (2^0); WinCC will reject the integer form with a type-mismatch error because the Boolean comparison expects a Boolean operand.

Computing Bit-Mask Values Up Front

For convenience, here is the complete mask table for the most common tag widths. Paste this into a comment header at the top of any picture's C-script action to document which bit number maps to which mask.

Bit No. Mask (decimal) Mask (hex) Position Within 16-bit Word
0 1 0x0001 LSB of low byte
1 2 0x0002 low byte
2 4 0x0004 low byte
3 8 0x0008 low byte
4 16 0x0010 low byte
5 32 0x0020 low byte
6 64 0x0040 low byte
7 128 0x0080 MSB of low byte
8 256 0x0100 LSB of high byte
9 512 0x0200 high byte
10 1024 0x0400 high byte
11 2048 0x0800 high byte
12 4096 0x1000 high byte
13 8192 0x2000 high byte
14 16384 0x4000 high byte
15 32768 0x8000 MSB of high byte / MSB of word

Tag Naming Conventions for S7 PLC Connections

The tag names used in the scripts must match the WinCC internal tag name, which is the left-most column in Tag Management. The display name is for the HMI only and is ignored by the scripting API. The following conventions match what the standard WinCC S7 channel produces when tags are created from STEP 7 or TIA Portal symbol tables:

PLC Address Auto-Generated Tag Name Width Example Script Use
DB41.DBX15.1 DB41_DBX15_1 1 bit Xor True
DB41.DBB15 DB41_DBB15 8 bits Xor (2^0) ... Xor (2^7)
DB41.DBW15 DB41_DBW15 16 bits Xor (2^0) ... Xor (2^15)
DB41.DBD15 DB41_DBD15 32 bits Xor (2^0) ... Xor (2^31)

If your project was hand-built or imported from TIA Portal via the symbol table, tag names may follow the symbol name instead (e.g., MotorStart_Cmd). Open Tag Management in WinCC Explorer and read the first column - that is the string you pass to HMIRuntime.Tags(...) in VBS or to GetTagDWord/SetTagDWord in C. See the WinCC V7 tag management manual for additional naming rules and symbol-table import workflow.

Step-by-Step Implementation Guide (End-to-End)

The fastest reliable deployment is the VBS path. Use this checklist when wiring a brand-new toggle button from scratch.

Phase 1: PLC-Side Preparation

  1. Reserve a status word in the PLC data block for HMI-controlled flags. Avoid reusing an existing control word that the PLC writes to - the toggle will race with the PLC scan and produce flickering values.
  2. Document the bit meaning in a symbol comment so that the HMI engineer and the PLC programmer use the same bit numbers.
// DB41 "HMI_Status"
//   DBW15 "HMI_Ctrl_Word"
//     bit 0  : Pump_1_Run
//     bit 1  : Pump_2_Run
//     bit 2  : Agitator_Run
//     bit 3  : Heater_Run
//     bit 4  : Light_On
//     bit 5..15 : reserved

Phase 2: WinCC Tag Configuration

  1. Open Tag Management in WinCC Explorer.
  2. Right-click your S7 connection > New Tag.
  3. Set Name to HMI_Ctrl_Word (this becomes the tag passed to the script).
  4. Set Data Type to Unsigned 16-bit value.
  5. Set Address to DB41.DBW15 or use the symbol-table lookup button if you imported a TIA Portal symbol.
  6. Click Apply and verify the tag's quality indicator turns green in Tag Simulator.

Phase 3: Button Wiring with VBS

  1. Insert a button on your picture and open its properties.
  2. Navigate to Events > Mouse > Mouse Click.
  3. Click the value cell on the right and choose VBScript Action.
  4. Paste the toggle script, substituting your tag and bit number:
    Dim v
    v = HMIRuntime.Tags("HMI_Ctrl_Word").Read
    HMIRuntime.Tags("HMI_Ctrl_Word").Write v Xor (2 ^ 0)
    
  5. Click OK and save the picture.

Phase 4: Runtime Verification

  1. Activate the WinCC project.
  2. Open the picture and click the button.
  3. In WinCC Tag Simulator (or in the PLC's VAT/online view), confirm that bit 0 of HMI_Ctrl_Word flips state on every press.
  4. Confirm that no other bit changes (the XOR mask must only affect the target bit).

Bit Numbering Reference and Endianness

WinCC follows the convention that bit 0 is the least significant bit (LSB) and bit N is the N-th power of two. This matches STEP 7 and TIA Portal symbol definitions and is the opposite of older "bit 1 = LSB" notation found in legacy HMIs. When in doubt, write a quick test: write 2^0 to the tag and observe which bit lights in the PLC's online view - that is bit 0.

For S7-1500 and S7-1200, the byte order in a word is little-endian: DBW15 occupies bytes DBW15 (low) and DBW16 (high). Bit 8 therefore lives in the high byte of DBW15, not the low byte of DBW16. This is purely informational - the Xor (2^8) operation handles it correctly regardless.

Verification and Runtime Commissioning

A toggle is correct only if every bit other than the target bit is preserved. A simple field test sequence:

  1. Initial state: read the tag value in WinCC Tag Simulator. Record the value.
  2. First press: click the toggle button. Read the tag again. The XOR mask should appear added (if bit was 0) or subtracted (if bit was 1) from the previous value. All other bits must be identical.
  3. Second press: click again. The tag must return to its initial value.
  4. Stress test: hold the keyboard focus on the button and press space repeatedly. The tag should toggle at every press with no missed events. If a press is missed, the script is throwing an exception - check the WinCC diagnostics window ApDiag.exe for the error log.
  5. Concurrent-write test: write a known value to the tag from the PLC (e.g., from a VAT table) while clicking the toggle. The PLC's write should always win if it happens after the HMI write; if the HMI write happens after the PLC write, the HMI should pick up the new PLC value on the next read cycle. If the PLC's other bits get clobbered, the script is doing a read-modify-write that races with the PLC - switch to a direct PLC-side toggle instead.

Troubleshooting Matrix

Symptom Likely Cause Fix
Button does nothing at runtime C Editor not generated or function not compiled Re-open C Editor, click Generate Header, save, reactivate project
"Function not found" error in diagnostics Function file not in the project Library folder, or extension mismatch Confirm the file is named exactly Word_bits.fct and lives in <ProjectName>\Library
"Password" dialog when opening the function Project owner encrypted the function source Function still executes; ask the project owner for an unencrypted copy if you need to modify it
VBS error: "Object doesn't support this property or method" Wrong tag name passed to HMIRuntime.Tags(...) Open Tag Management and copy the exact internal name (first column)
VBS error: "Type mismatch" on Xor (2^0) for a binary tag Tried to use integer mask on a binary tag Replace Xor (2^0) with Xor True for binary tags
All bits clear on first press instead of one bit Wrote a 32-bit value to a 16-bit tag (or vice versa) Match the Get/Set API width in C, or use the correct VBS read/write type
Toggle works in Graphics Designer test mode but not in Runtime Project not activated, or runtime is on a different station Activate project on the runtime station; verify license is RT not RC for client/server
Click event fires twice per click Action was assigned to both Mouse Click and Mouse Down Remove the duplicate action; use only Mouse Click for toggle-style actions
"Quality: Bad" indicator on the tag PLC connection down or wrong address Verify in Channel Diagnosis; correct the DB number or offset
Bit value visible in the PLC is the inverse of what the button toggles Connected to a negated coil in the PLC, or to an inverted input image Trace the rung in the PLC program; either remove the negation or invert the mask behaviour
Toggle works for the first click, then "stuck" Event set to trigger once on picture change, not on every click Re-bind to Mouse Click event specifically; remove any "On Picture Open" toggling

Performance and Security Considerations

For projects with hundreds of toggle buttons, the C function approach is preferred because the function is loaded once and reused. For projects with a few dozen toggles, VBScript actions are easier to maintain because there is no central function to keep in sync. Neither approach has a measurable performance penalty at typical update rates (1 Hz is well within WinCC's scripting budget).

Two caveats for production systems:

  • Authorisation: an operator toggle should respect the area-specific authorisation configured in User Administrator. Configure Operator Permission directly on the button's Properties > Miscellaneous > Operation - WinCC will grey out the button for unauthorised users automatically. Use the script only to perform the actual write, never as the sole authorisation gate.
  • Audit trail: for GMP or 21 CFR Part 11 environments, every toggle should write an audit record. Extend the script to call HMIRuntime.Trace (VBS) or to write a structured line to a CSV audit log before the write. The PLC's own audit block is the more authoritative record because it cannot be bypassed by an HMI crash.

Frequently Asked Questions

Why does my button toggle two or more bits instead of one?

The XOR mask you are using is wrong for the tag width. For a 16-bit tag use Xor (2^0) through Xor (2^15); values above 32768 will set bit 15 again because of integer overflow. For a 32-bit tag use Xor (2^0) through Xor (2^31). If the value you want to toggle is in the range 16-31 but the tag is configured as 16-bit, change the tag type to Unsigned 32-bit or move the toggle to a different bit.

Can I use a single C function to toggle any tag without recompiling?

Yes. The Word_bits(tagName, bitNo) pattern accepts the tag name as a string and the bit number as an integer at runtime. The C Editor only needs to regenerate the header once when the function signature changes; after that, every call site uses the same compiled function. The same applies if you extend the function with logging or authorisation logic - one change updates every toggle button on every picture.

My C function is password-protected. Can I still use it?

Yes. Encryption prevents viewing or editing the source code but does not prevent the function from being called. The runtime executes the compiled p-code regardless. If you need to change the function, ask the project owner to remove the password via File > Properties > Password in the C Editor. Until then, deploy the function as-is and document its behaviour in your project notes.

How do I toggle a bit in a TIA Portal symbol like "Motor_Cmd.Start"?

WinCC treats TIA symbols as flat tag names with underscores replacing dots. The WinCC tag is created as Motor_Cmd_Start automatically by the symbol importer. Pass that exact string to HMIRuntime.Tags(...). If the symbol contains a structure, you must select an individual member - WinCC cannot pass an entire UDT to a script.

Is there a way to toggle a bit without writing any script?

Yes, for binary tags only. Configure the button's Properties > Output/Input > Toggle with Type = Switch with text or Switch. WinCC 7 will perform the toggle internally without any script. This option only works for binary tags; word and dword packed flags still require the XOR script described above because WinCC cannot natively mask individual bits in a word tag.

Back to blog