WinCC TIA Portal: Run VBScript Every 2 Seconds on TP900
This reference documents how to implement a periodic VBScript execution in WinCC (TIA Portal) Comfort/Advanced running on a SIMATIC TP900 Comfort panel, with the script driven by a cyclic tag value change originating from an S7-1500 PLC (tested on CPU 1512). The technique replaces the legacy WinCC flexible scheduler, gives sub-second resolution, and supports clean start/stop semantics through a single boolean tag.
1. Problem Definition and Design Goals
WinCC Comfort/Advanced does not expose a VBScript "tick" or "timer" object on the HMI runtime in the same way a desktop application does. The available triggers for a scheduled function are limited to:
- Tag value change (rising edge, falling edge, any change, or value range)
- Scheduled task (date/time, daily, weekly - resolution 1 minute minimum on TP900)
- Screen event (load, clear)
To obtain a 2-second (or any value between 0.1 s and several hours) execution interval, the most reliable pattern is to use a cyclic PLC tag as the heartbeat and bind the VBScript to its value change event. The script body is wrapped with an If ... Then guard that reads a Start/Stop tag, so the same heartbeat tag can be enabled or disabled at runtime without reconfiguration.
2. Architecture Overview
The PLC generates a square-wave Boolean at the required period. The HMI polls that tag at a 100 ms acquisition cycle (minimum on TP900) and detects a value change on every transition. The transition fires the VBScript, which then performs the user action (read tags, log to file, write back to PLC, animate screen, etc.).
3. Prerequisites
| Item | Specification | Notes |
|---|---|---|
| TIA Portal | V16 or later (V17 / V18 recommended) | Same major version as the panel image |
| WinCC Comfort/Advanced | V16+ | Comfort = TP panels; Advanced = WinCC Runtime Advanced |
| SIMATIC TP900 Comfort | Image V16.0.4 or later | Earlier images limit the scheduler to 1 min |
| S7-1500 CPU | 1512C-1 PN (or any S7-1500) | Firmware V2.9+ recommended for tag prefix behavior |
| PLC-HMI connection | S7-CONNECT, PROFINET, S7 Routing | Tags must be accessible from HMI DB |
| VBScript runtime | Built into WinCC RT | No additional license |
4. Step 1 - Build the PLC Heartbeat Generator
Create a data block in the S7-1500 project, for example DB_HMI_Trigger, containing three tags:
| Symbol | Type | Initial value | Comment |
|---|---|---|---|
bStartStop |
BOOL | FALSE | HMI button drives this; the script only runs when TRUE |
bHeartbeat2s |
BOOL | FALSE | Square-wave, period 2 s; the value-change trigger |
iTickCount |
INT | 0 | Increments each tick; useful for diagnostics |
Add the following structured text logic in OB1 (or an OB with the same cycle, e.g. OB35 at 100 ms):
// Heartbeat: toggle every 2 s using a TON + edge
// Tag: iHeartTmr (TIME), iHeartStep (INT) - local statics
IF iHeartStep = 0 THEN
iHeartTmr := T#2S; // period for 2-second script interval
iHeartStep := 1;
END_IF;
// Use a TP (pulse) or simple timer-driven toggle
IF "DB_HMI_Trigger".bStartStop THEN
IF iHeartTmr <= T#0MS THEN
// toggle
"DB_HMI_Trigger".bHeartbeat2s := NOT "DB_HMI_Trigger".bHeartbeat2s;
"DB_HMI_Trigger".iTickCount := "DB_HMI_Trigger".iTickCount + 1;
iHeartTmr := T#2S;
END_IF;
iHeartTmr := iHeartTmr - OB1_INTERVAL; // subtract 100 ms per OB1 cycle
ELSE
"DB_HMI_Trigger".bHeartbeat2s := FALSE;
"DB_HMI_Trigger".iTickCount := 0;
END_IF;
Alternatively, use the built-in Clock Generator from the "Instructions > Timers & counters > Clock" group in TIA Portal with mode Periodic and period 2 s. The clock generator is the cleanest solution - it does not consume OB1 scan time and is fully time-accurate.
OB1_INTERVAL is exposed as a system constant in newer firmware only; otherwise use a local TIME literal of T#100MS.5. Step 2 - Create the HMI Tags
In the HMI project, create three tags pointing to the corresponding PLC addresses. Mark the connection's "Acquisition mode" as Cyclic continuous (this is the field many engineers miss - default is "On demand" and the value-change event will not fire on every transition).
| HMI tag name | PLC address | Type | Acquisition cycle | Acquisition mode |
|---|---|---|---|---|
tagStartStop |
DB_HMI_Trigger.bStartStop | BOOL | 100 ms | Cyclic continuous |
tagHeartbeat2s |
DB_HMI_Trigger.bHeartbeat2s | BOOL | 100 ms | Cyclic continuous |
tagTickCount |
DB_HMI_Trigger.iTickCount | INT | 500 ms | Cyclic continuous |
6. Step 3 - Bind the VBScript to the Value-Change Event
- In the TIA Portal project tree, open HMIRuntime > Scripts > VBScripts.
- Right-click and add a new procedure, e.g.
sub_OnTick. - Open the HMI screen where the trigger should be active, or add the function to a global script if it should run regardless of the active screen.
- Select the
tagHeartbeat2stag in the screen or in the HMI tags editor. - In the Properties pane, navigate to Events > Value change.
- Add a new function call:
sub_OnTick(or call the function with parametertagHeartbeat2s).
7. Step 4 - Write the VBScript Body
The pattern from the original field-tested discussion (the -1 = true convention is specific to HMI tag semantics where the runtime uses -1 for a true Boolean) is preserved and extended with logging and screen I/O:
'--------------------------------------------------------------------
' sub_OnTick - triggered by tagHeartbeat2s on every transition
' guarded by tagStartStop
'--------------------------------------------------------------------
Option Explicit
Dim bRun, bTick, iCount, sPath, sLine, oFSO, oFile
Dim dNow
bRun = SmartTags("tagStartStop") ' -1 = true in WinCC convention
bTick = SmartTags("tagHeartbeat2s")
iCount = SmartTags("tagTickCount")
If bRun = -1 Then
' --- user code begin ---
dNow = Now ' local WinCC clock
sLine = FormatDateTime(dNow, vbShortDate) & "," & _
FormatDateTime(dNow, vbLongTime) & "," & _
CStr(iCount) & "," & _
CStr(SmartTags("tagProcessValue1")) & "," & _
CStr(SmartTags("tagProcessValue2"))
' --- log to file on the panel's local storage ---
sPath = "\Storage Card SD\Logs\telemetry.csv"
Set oFSO = CreateObject("Scripting.FileSystemObject")
If Not oFSO.FolderExists("\Storage Card SD\Logs\") Then
oFSO.CreateFolder "\Storage Card SD\Logs\"
End If
If Not oFSO.FileExists(sPath) Then
Set oFile = oFSO.CreateTextFile(sPath, True)
oFile.WriteLine "Date,Time,Tick,PV1,PV2"
oFile.Close
End If
Set oFile = oFSO.OpenTextFile(sPath, 8, False) ' 8 = ForAppending
oFile.WriteLine sLine
oFile.Close
Set oFile = Nothing
Set oFSO = Nothing
' --- visual feedback on screen ---
SmartTags("tagLastTick") = dNow
End If
WinCC VBS Boolean convention: The runtime stores BOOL as a 16-bit integer internally. A Boolean "true" is represented as -1 (all bits set), not 1. Comparing against -1 is the only safe form of identity comparison; If SmartTags("x") Then also works because VBScript coerces any non-zero to true, but the explicit form is preferred when the bit pattern matters (e.g. latching a flag back to FALSE inside the script).
8. Step 5 - Wire the Start/Stop Button
Place a button on any HMI screen. Configure the Press event with the InvertBit system function on tagStartStop. The Release event should do nothing - toggling on press gives clean debounced semantics for an operator pushbutton.
| Property | Value |
|---|---|
| Appearance > Mode | "Switch" (latching) or "Button" (momentary with toggle) |
| Events > Press | System function: InvertBit - tagStartStop |
| Events > Release | (none) |
| Appearance > Label "ON"/"OFF" | Dynamic via text list bound to tagStartStop |
If the button is wired to a physical I/O on the PLC (rather than a screen button), bind tagStartStop to the input in the HMI tag properties and set its acquisition mode to Cyclic continuous; the script guard handles the rest.
9. Step 6 - Optional: Display Date/Time with Each Sample
The script's Now function uses the panel's local clock, which is synchronized from the PLC by default. For plants where the panel is not synchronized, replace Now with reading a DTL tag from the PLC, formatted using FormatDateTime on the variant. Example PLC side:
// DB_HMI_Trigger.dtlNow : DTL (read by HMI as DTL, 8 bytes)
"DB_HMI_Trigger".dtlNow := DTL#2024-01-01-00:00:00; // populated from PLC clock
On the HMI, display via an Output field with format pattern yyyy-MM-dd HH:mm:ss. The script can also read this DTL and append to the log line for traceability.
10. Verification Procedure
- Compile the HMI project and download to the TP900 (use Software (full) on first load, Delta thereafter).
- Connect with WinCC Tag Simulation or a PLC online watch table to confirm
bHeartbeat2stoggles every 2 s. - Set
bStartStop := TRUEin the PLC; the HMI should write one line to\Storage Card SD\Logs\telemetry.csvper transition (so two lines per second, but the semantic "tick" is the 2 s boundary - script execution happens once per transition). - Set
bStartStop := FALSE; the file should stop growing. Set it back to TRUE; logging resumes on the next 2 s transition. - Power-cycle the panel; confirm that on restart the script does not run because
tagStartStopdefaults to FALSE.
11. Performance and Timing Budget
| Element | Typical time | Constraint |
|---|---|---|
| HMI acquisition cycle | 100 ms | Hard floor; can be raised to 200/500/1000 ms if the network is loaded |
| Value-change detection latency | 0 to 1 acquisition cycle | 0 to 100 ms; means a 2 s tick has up to 100 ms of jitter |
| VBScript execution | 5 to 50 ms | Depends on body; >100 ms starts to starve other runtime tasks |
| File write to SD card | 20 to 200 ms | SD card class matters; class 10 recommended for 1 Hz logging |
| PLC scan to HMI tag update | 1 to 5 OB1 cycles (10 to 50 ms typical) | Profinet update time adds another 1 to 4 ms |
For sub-100 ms requirements, the value-change approach breaks down. Use a C/C++ script in WinCC Professional, or move the periodic task to a PLC OB (e.g. OB35 + a small DB write) and treat the HMI as a pure display.
12. Troubleshooting Matrix
| Symptom | Root cause | Fix |
|---|---|---|
| Script never fires | Tag acquisition set to On demand | Set Acquisition mode to Cyclic continuous |
| Script fires once, then never again | PLC heartbeat is not toggling; OB1 paused or CPU in STOP | Watch the tag in HMI online; verify PLC is in RUN and OB1 is executing |
| Script fires at random intervals (1 s, 3 s, 5 s) | Heartbeat driven by OB1 with variable scan time; use a TON with a fixed PT | Replace with a TP/clock generator, or use OB35 at 100 ms |
| Script runs even though Start button is OFF | Comparison uses = 1 instead of = -1, or the If guard is missing |
Use If SmartTags("tagStartStop") = -1 Then
|
| Log file is empty after restart | SD card path is wrong, or the card is not inserted at startup | Verify \Storage Card SD\ exists; insert card before boot |
| Log file is full of duplicate timestamps | Edge detection is firing on every acquisition (rising AND falling) | Trigger on Rising edge only, not Any change |
| Compiles but VBScript error in Runtime | Typo in SmartTags name; tag renamed but script not updated |
Re-bind tags; TIA Portal does not refactor SmartTags calls |
| Compiles but error in Runtime: "Permission denied" on file | File already opened by another application (FTP, viewer) | Close the file before transferring via FTP, or use a different file name each shift |
13. Edge Cases and Field-Proven Caveats
- Multiple scripts per tick: A single value-change event can only call one function. If two scripts must run at 2 s, drive them from a single function that calls both, or use two separate boolean heartbeat tags with different phases.
-
Runtime Advanced vs. Comfort: WinCC Runtime Advanced on a PC supports the same VBScript syntax but adds the
HMIRuntimeobject for system-level queries. The TP900 restricts filesystem access to\Storage Card SD\and a few read-only paths. -
Time-zone correctness:
Nowon the panel returns local time. For UTC logging, useSmartTags("tagDTL_UTC")populated fromRD_SYS_Ton the PLC and converted with the appropriate offset. -
Log rotation: SD cards fill up. Implement a daily rename in the script using
FormatDateTime(Now, vbShortDate)as part of the file name, or use the built-in WinCC logging (with a tag logging group at 2 s) which handles rotation automatically. - Commissioning without PLC: During bench test, replace the PLC heartbeat with a WinCC internal Simulation tag that toggles via a second VBScript bound to a 100 ms scheduler. This pattern is documented in the WinCC Comfort manual chapter "Tag simulation".
-
Security: VBScript has no sandbox; an
oFSO.DeleteFilecall in the same script can wipe the SD card. Wrap the body with try/catch and prefer Tag logging for production audit trails.
14. Alternative: WinCC Tag Logging (no VBScript required)
If the periodic action is only "record values over time", the tag logging subsystem in WinCC Comfort/Advanced is the intended path and avoids VBScript entirely. Configure a logging group with:
| Setting | Recommended value |
|---|---|
| Acquisition cycle | 2 s |
| Logging mode | Cyclic with continuous logging |
| Storage location | \Storage Card SD\Logs\ |
| File format | CSV (RDB for SQL retrieval) |
| Logging tags | tagProcessValue1, tagProcessValue2, tagTickCount |
Use VBScript only when you need to do something the logger cannot (compute a moving average, send an email at threshold, animate a trend, etc.). For pure periodic recording, the logging system is faster, more reliable, and writes to RDB format for the Information Server.
15. Related Patterns
- Edge-triggered logging on operator action: Use the Click event of a button to call the script directly, without a heartbeat tag. Same start/stop semantics by reading a global "logging enabled" tag inside the script.
- Time-of-day trigger: Combine a clock generator (e.g. pulse at 06:00:00) with the value-change event to run a script at a fixed wall-clock time without polling.
- Multi-rate sampling: Use three heartbeat tags at 0.5 s, 2 s, 10 s and bind three different scripts. The PLC generates them all from a single OB35 tick counter.
- Remote trigger from another HMI: Wire a tag from HMI_1 to HMI_2 via the PLC and let the value-change event on HMI_2 react. Round-trip latency on Profinet is <10 ms, so the script is essentially synchronous.
16. Standards and Documentation Cross-References
- Siemens - VBScript in WinCC Comfort/Advanced (entry ID 109746537)
- Siemens - HMI Tag Acquisition Behavior (entry ID 109755224)
- Siemens - S7-1500 Clock Generators and IEC Timers (entry ID 109768637)
- Siemens - TIA Portal Help: HMI Events Configuration (entry ID 109744812)
- Siemens - SIMATIC TP900 Comfort Image Release Notes (entry ID 109781203)
How do I run a WinCC VBScript exactly every 2 seconds?
Use a PLC boolean heartbeat tag that toggles every 2 s (e.g. via a TP timer or clock generator), set the HMI tag's acquisition mode to Cyclic continuous with a 100 ms cycle, and bind the VBScript to the tag's Rising edge value-change event. Guard the body with an If SmartTags("tagStartStop") = -1 Then for start/stop control.
Why is the value-change event not firing on my TP900?
The most common cause is that the HMI tag's acquisition mode is set to On demand instead of Cyclic continuous. Switch it in the tag properties under "Acquisition" and redownload. The HMI will then poll the tag at the configured cycle and detect transitions.
Why is the script running twice as fast as expected?
The event is bound to Value change (any), which fires on both rising and falling edges of the heartbeat. With a 2 s square wave, this gives one execution per second. Change the event to Rising edge (or Value change with edge direction "Rising") to get one execution per 2 s.
Can I trigger a VBScript without writing to the PLC?
Yes, for test purposes. Use a WinCC internal tag with Simulation enabled and drive it from a second VBScript bound to the panel's internal 100 ms scheduler. In production, the PLC-driven heartbeat is preferred because the PLC clock is more accurate and survives panel restarts.
What is the difference between = -1 and = True for a WinCC BOOL?
WinCC stores BOOL as a 16-bit integer, with "true" represented as -1 (all bits set). Direct identity comparison against True can fail for tags that PLC code writes via bit-set operations. The convention If SmartTags("x") = -1 Then is the safe form and is the pattern used in the original WinCC field-tested code.
Is the 1-minute Scheduler the only way to run a script periodically?
On Comfort Panels, yes - the built-in Scheduler has a 1-minute minimum granularity. For higher resolution (sub-minute, including 2 s), the documented Siemens pattern is the PLC-driven heartbeat tag with a value-change event, as described in this article.