Running WinCC C Scripts Cyclically with Global Actions in PCS7
Engineers deploying SIMATIC WinCC Operator Station (OS) projects for PCS 7 commonly write C scripts inside an I/O field on a picture to add several process tags, perform a calculation, and write the result back to an internal tag for display. The script tests fine in Graphics Designer, and the screen shows the expected result. After commissioning, however, the calculation freezes whenever the operator navigates to another picture. The summed value stops updating until the original screen is reopened, and any downstream tag (whether internal, archive, or written back into the AS via the PCS 7 APL block interface) is left stale. This article explains the root cause, the runtime architecture that causes the behavior, and the field-proven migration path: moving the script from a picture-local C action into a WinCC Global Script Action triggered by a cyclic event so that the calculation runs continuously regardless of which picture is active.
1. Problem Statement: Page-Local C Scripts Stop on Screen Change
Consider a typical PCS 7 OS picture with an I/O field configured with the following C action on the Output/Input property:
// C action attached to an I/O field Output Value
event void OutputValue_OnOutput(char* pszValue)
{
float v1 = GetTagFloat("Process_Value_1");
float v2 = GetTagFloat("Process_Value_2");
float v3 = GetTagFloat("Process_Value_3");
float v4 = GetTagFloat("Process_Value_4");
float sum = v1 + v2 + v3 + v4;
SetTagFloat("Total_Sum", sum);
sprintf(pszValue, "%8.2f", sum);
return;
}
The script uses GetTagFloat and SetTagFloat from the WinCC C API to read four tags, sum them, and write the result to an internal tag. The pszValue parameter renders the result directly in the I/O field. The script functions correctly while the picture is open in WinCC Runtime. After the operator navigates to a second picture, the sum tag holds its last value, and the underlying AS block (for example a PCS 7 MOT_SPEED or ADD block) never receives the updated value.
This symptom is not a bug; it is the documented behavior of picture-triggered C actions in WinCC Graphics Designer. Picture-local C actions are evaluated only when the picture is loaded, when a configured trigger tag changes, or on a periodic refresh of the picture object. When the picture is unloaded (because the operator pressed a screen-change button), the action object is destroyed along with its evaluation timer.
2. Root Cause: WinCC Runtime Architecture
WinCC Runtime is built on three cooperating processes that handle picture objects, data management, and scripting. Understanding the separation clarifies why a picture-bound C action cannot be relied upon for continuous processing.
| Process | Executable | Responsibility | Lifetime |
|---|---|---|---|
| Picture Manager | PDLRT.exe | Loads/unloads pictures, instantiates Smart Objects, dispatches C/VB actions on picture events | Picture open/close |
| Data Manager | DM.exe | Owns the process tag image, archive connections, AS-OS link (S7DOS / S7 Protocol Suite) | Runtime startup/shutdown |
| Global Script Runtime | GSRT.exe | Hosts Global Script Actions (C and VBS), executes project functions, handles cyclic and event triggers independent of any picture | Runtime startup/shutdown |
The Picture Manager destroys its action objects when the picture closes. Even if the action had a 1-second internal cycle, that cycle ends with the picture. The Data Manager continues to update tag values from the AS via S7 Protocol Suite, but no C action is left to read them. The Global Script Runtime is the only component that keeps running for the entire OS session, which is exactly the host required for continuous calculations.
This separation is reinforced by the WinCC design tool: actions attached to picture events are stored in the .pdl_<server>.@<picture>.pcc compiled binary and are reconstructed only when the picture loads. Global Actions are compiled into Actions.dll and loaded once at Runtime start.
3. Why Engineers Use Picture-Local Scripts Anyway
Picture-local C actions are convenient for the following use cases, all of which have an implicit "picture must be open" assumption:
- Direct visual feedback in an I/O field (the calculation drives the displayed value).
- Conditional color, flashing, or visibility of an object.
- Operator input validation, where the action fires on property change events.
- Layout-bound formatting (for example converting raw counts to engineering units with a unit string).
The moment the result is also written to a tag (via SetTagFloat, SetTagWord, etc.) and downstream logic, archives, or other pictures consume that tag, the implicit assumption breaks. Engineers often do not realize the assumption is implicit because the screen is open during factory acceptance testing (FAT) for most of the time. The behavior change is observed only after a few days of production, when operators cycle through pictures and the archive reports frozen values.
4. Solution: Move to a Global Script Action with a Cyclic Trigger
Global Script Actions live in the WinCC Global Script editor and execute under GSRT.exe. They support several trigger types, the most relevant being:
| Trigger Type | Use Case | Typical Cycle |
|---|---|---|
| Cyclic (Standard cycle) | Calculations that need to update at a fixed rate (totalizers, averages, sums) | 250 ms, 500 ms, 1 s, 2 s, 5 s, 10 s, 1 min, 5 min, 10 min, 1 h, user-defined |
| Tag Trigger | Calculations that should run only when an input tag changes | Event-driven (per change) |
| Time-of-Day Trigger | Shift reports, daily rollups, end-of-shift calculations | One-shot or repeating |
| Hotkey / Mouse / Picture events | Operator-initiated actions | Event-driven |
For a continuous summation, a standard cyclic trigger between 1 s and 5 s is the field-proven choice. The 250 ms cycle is the fastest standard cycle and should be reserved for closed-loop or fast alarm processing; a 4-tag sum does not justify that load. The PCS 7 OS can host thousands of Global Actions with 1 s cycles, but the sum of all action runtimes should remain well below 50% of the cycle budget on the worst-case server.
5. Prerequisites
Before creating the Global Action, ensure the following items are present and tested:
- WinCC V7.4 SP1 or later, or WinCC V8.0/8.1, installed on the engineering station (ES) and OS servers. For PCS 7 V9.0 SP2 / V9.1 the supported WinCC is V8.0.x. The Global Script editor is enabled under the WinCC installation custom setup and is part of every OS server image by default.
- PCS 7 OS project opened in the WinCC Explorer on the ES, with the corresponding OS server reachable (or local on the same station for single-station setups).
- The four input tags already exist as WinCC process tags in the Tag Management, mapped to the AS via the PCS 7 AS-OS link (typically via S7 Protocol Suite, named connections generated by the PCS 7 plant view). Confirm a green quality code in the tag diagnosis before scripting.
- The internal result tag created as an internal tag in WinCC Tag Management (data type FLOAT, length 4 bytes), or an external tag pointing to a DB word/DWORD in the AS that the operator's block can read. Internal tags are recommended for purely OS-side calculations; external tags are required when the result must drive AS logic (for example, a PCS 7 CTRL_PID SP or a summing block in the CFC).
- Authoring rights in the OS project: open WinCC Explorer as a user with project author or higher rights. Runtime editing of global scripts is not supported on a production server unless the project is in "configuration mode"; configuration changes are made on the ES and downloaded.
- Diagnostic GSC Diagnostics and GSC Runtime windows enabled for verification: WinCC Explorer → Tools → GSC Diagnostics, and GSC Runtime for live state inspection.
6. Step-by-Step Migration to a Global Action
Step 6.1 — Create a New Global Action
Open the WinCC Explorer and navigate to Global Script → Actions. Right-click and select New → C-Action. Name the action clearly, for example Sum_Four_Tags_1s. The editor opens the C source file Sum_Four_Tags_1s.c in the project subfolder <OS project>\library\<servername>\Sum_Four_Tags_1s.c.
Step 6.2 — Add the Calculation Code
Replace the default stub with a self-contained function that reads, sums, and writes the tag set. A clean, idempotent body for a 1 s cycle action looks like this:
// Global Script Action: Sum_Four_Tags_1s
// Trigger: standard cycle 1 s
// Purpose: Sum four process tags and write to internal/external result tag.
// Runtime host: GSRT.exe (process "Global Script Runtime")
#include "apdefap.h"
int gsc_action(void)
{
static DWORD dwLastRun = 0;
DWORD dwNow = GetTickCount();
/* Optional: enforce a 1 s minimum interval even if trigger is faster. */
if ((dwNow - dwLastRun) < 1000L) {
return 0;
}
dwLastRun = dwNow;
float v1 = 0.0f, v2 = 0.0f, v3 = 0.0f, v4 = 0.0f;
float sum = 0.0f;
DWORD qc = 0x00000000L;
qc = GetTagQuality("Process_Value_1");
if ((qc & 0x00000080L) == 0) { /* quality is "good" */
v1 = GetTagFloat("Process_Value_1");
} else {
v1 = 0.0f;
}
qc = GetTagQuality("Process_Value_2");
if ((qc & 0x00000080L) == 0) { v2 = GetTagFloat("Process_Value_2"); } else { v2 = 0.0f; }
qc = GetTagQuality("Process_Value_3");
if ((qc & 0x00000080L) == 0) { v3 = GetTagFloat("Process_Value_3"); } else { v3 = 0.0f; }
qc = GetTagQuality("Process_Value_4");
if ((qc & 0x00000080L) == 0) { v4 = GetTagFloat("Process_Value_4"); } else { v4 = 0.0f; }
sum = v1 + v2 + v3 + v4;
/* Clamp the result to the configured tag range to avoid archive saturation. */
if (sum > 1.0e9f) { sum = 1.0e9f; }
if (sum < -1.0e9f){ sum = -1.0e9f;}
SetTagFloat("Total_Sum", sum);
/* Optional: write the same value to an AS tag if downstream logic needs it. */
/* SetTagFloat("AS_Block_Input_Total", sum); */
return 0;
}
Key design points:
- The action does not depend on
pszValue(no picture object). It writes directly to a tag, which is the correct interface between Global Actions and the rest of WinCC. - Quality-code checks via
GetTagQualityprevent bogus values during AS-CPU restart, S7 link loss, or replacement-object operations. - A defensive clamp prevents an archive overflow on a process upset; a 1.0e9 clamp is far below the 3.4e38 range of a WinCC FLOAT tag but well above the 1.0e6 range used for most engineering values.
- The static
dwLastRuntimestamp provides an additional safety net if the trigger cycle is changed after commissioning.
Step 6.3 — Configure the Cyclic Trigger
In the Global Script editor, open the action's Properties dialog and select the Trigger tab. Click Add and choose Standard cycle. Configure the cycle to 1 s (value: 1000 ms). Optional: add a tag trigger on any of the four input tags to re-evaluate the sum immediately after a fast process change rather than waiting for the next 1 s tick.
Recommended trigger configuration for a continuous sum:
| Trigger | Value | Rationale |
|---|---|---|
| Standard cycle 1 | 1000 ms | Ensures continuous evaluation even when all inputs are stable |
| Tag trigger (optional) | Process_Value_1 | Fast process response on the largest contributor |
| Standard cycle 2 (optional) | 10000 ms | Slow sanity check / clamp reapplication |
Step 6.4 — Compile the Action
Press F7 or click the Compile button. A successful compile produces the line Number of generated actions: 1 in the output window. If errors are shown, the most common cause is a missing semicolon or an undefined tag in Tag Management; both are flagged in the Output pane with the offending line number. Correct and recompile until clean.
Step 6.5 — Bind the I/O Field to the New Tag
Return to the picture, open the I/O field that previously held the C action, and bind its Output Value property to the new tag Total_Sum. Remove the C action from the Output Value event. The picture will now display the running sum because the I/O field receives fresh values from the Data Manager, which receives writes from the Global Action.
Data flow after the migration:
AS (S7) -> S7DOS/S7 Protocol Suite -> DM.exe (tag image) -> GSRT.exe (Global Action reads/sums)
\-> DM.exe writes back "Total_Sum" -> PDLRT.exe (I/O field rendering)
7. Trigger Configuration Reference
| Standard Cycle | Value (ms) | Recommended Use |
|---|---|---|
| 250 ms | 250 | Closed-loop / fast alarm pre-processing only |
| 500 ms | 500 | Fast process calculations, totalizers |
| 1 s | 1000 | Standard continuous calculation (recommended default) |
| 2 s | 2000 | Slow process totals, comfort calculations |
| 5 s | 5000 | Energy totals, batch totals, KPI calculations |
| 10 s | 10000 | Hourly accumulation, slow averages |
| 1 min | 60000 | Shift rollups, end-of-batch calculations |
| 10 min | 600000 | Long-term averages |
| 1 h | 3600000 | Daily total corrections |
These values are defined in the WinCC Global Script configuration and are not user-extendable without editing the registry key HKLM\SOFTWARE\Siemens\Automation\WinCC\RT\GSC\StandardTrigger. The values above are the standard set shipped with every WinCC installation.
8. PCS 7-Specific Integration Considerations
PCS 7 OS projects layer additional constraints on top of plain WinCC that the engineer must observe when porting scripts to Global Actions.
8.1 OS Server vs OS Client Behavior
In a multi-station PCS 7 project, Global Actions are compiled and loaded on each OS server in the project, but they are NOT loaded on the OS clients by default. To run the action on a client (for example, on a client-only tag that drives a plant overview total), enable Run on OS Client in the action properties and distribute the action through the OS project editor. A typical setup is:
| Station | Action Runs | Tag Writes |
|---|---|---|
| OS Server (preferred) | Yes, single source of truth | Server-side tag image, replicated to clients |
| OS Server with redundant partner | Yes, both servers run; writes go to local server tag image only | Tag image replicated via redundancy sync |
| OS Client (only if no server exists for that data) | Optional | Local client tag image only |
For the canonical four-tag sum, run the action on the OS server. The replicated tag is then visible to all clients automatically.
8.2 Redundancy Behavior
In a redundant OS server pair, both servers run the Global Action. The Data Manager on each server receives the S7 link independently, so both servers compute the same sum. On failover, the new preferred server continues to update the result tag without interruption. The only caveat is that the script should not rely on local-station time (use GetSystemTime from the Win32 API consistently) and should not use static variables that store persistent state without a pairing mechanism.
8.3 Interaction with PCS 7 APL Blocks
If the summed value is written back to the AS (for example into the SP input of a CTRL_PID block), use a PCS 7-conformant naming convention for the AS-side tag. The CFC block interconnection is updated through the PCS 7 plant view download, not through a free WinCC tag. The recommended pattern is:
- Declare the operator input tag in the PCS 7 plant view as
OperatorControl_<area>_Totalwith the standard data type (REAL). - Compile the OS, which generates the corresponding WinCC tag automatically with the S7 connection and update policy.
- Use
SetTagFloat("OperatorControl_<area>_Total", sum)in the Global Action. - Bind the CFC interlock and operator authorization in the same way as any other APL operator input.
9. Verification
After deploying the Global Action, run a structured verification before declaring the change ready for production.
-
Trigger confirmation: Open GSC Diagnostics on the OS server. Locate the action
Sum_Four_Tags_1sand confirm the trigger cycle is the configured value (e.g. 1000 ms) and the last-run timestamp updates each cycle. The increment of the "Trigger count" column per second is the visible proof. -
Tag live update: Open the OS runtime and start Tag Diagnosis (WinCC Explorer → Tools → Tag Diagnosis). Add the tag
Total_Sumand verify the value changes when the input tags are manipulated from the AS (or with the WinCC tag simulator). - Picture-independence test: From the WinCC Runtime, open the picture with the I/O field, confirm the sum updates, then navigate to two other pictures and leave the system idle for 60 seconds. Return to the original picture and confirm the sum has continued to update. This is the canonical test that the migration succeeded.
- Archive continuity test: Open the Tag Logging archive configuration for the result tag (compressed or not, depending on site policy) and run a 5-minute archive. Confirm continuous rows in the archive with monotonically increasing timestamps; gaps indicate the action stopped.
- AS round-trip test (if writing back to AS): Use the AS-side online monitor on the consuming block to confirm the operator input reflects the latest OS-side value, with the expected AS scan delay (typically 100-500 ms on PROFIBUS/PROFINET).
- Failover test (redundant OS only): Stop the preferred server and verify the standby server continues to update the tag and the archive without a gap greater than one cycle (1 s for a 1 s action).
10. Performance and Capacity Planning
The Global Script Runtime is single-threaded per server; all actions share one C execution thread by default. Long-running actions or excessive cycles can starve other actions and delay picture rendering on the same server. Apply the following rules of thumb:
- Total action runtime across all Global Actions on a server should stay below 200 ms per 1 s cycle budget on a typical 4-core OS server with 8 GB RAM.
- For high-frequency calculations, prefer 250 ms or 500 ms cycles combined with internal throttling (as shown in the example) to avoid hammering the tag image.
- Minimize the number of
GetTagcalls by reading multi-dimensional tags (text arrays, raw structures) when the AS exposes them. - For 50+ tag totals, prefer a periodic AS-side CFC summation block and read the result through a single WinCC tag rather than summing 50 tags in the Global Action.
- Do not call Windows dialogs, file I/O, or external COM objects from a Global Action unless the action is configured with a long cycle and isolated to a dedicated OS server; side effects can hang the Runtime.
11. Common Errors and Field-Proven Diagnostics
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Action never fires | Action created on ES only, not compiled to the OS server | Open the OS project on the server, recompile, or use OS Project Editor "Download Changes" |
| Action fires but value stays at 0 | Input tag name typo or tag not declared in Tag Management | Use GSC Diagnostics to view runtime errors; confirm tag exists with tagname = Process_Value_1
|
| Archive gaps during picture changes | Old picture-bound action still present in the project | Search Graphics Designer for the old I/O field and remove the C action; the picture-bound evaluation was the gap source |
| Runtime message "Function not found" | Custom project function not registered | Confirm Project Functions container in Global Script contains the function, then recompile all actions |
| Server CPU at 100% after enabling 250 ms cycle | Action contains blocking calls (file I/O, network, dialogs) | Profile with GSC Diagnostics runtimes; reduce cycle to 1 s or remove blocking calls |
| AS-side value is stale even though OS tag updates | S7 connection has wrong update policy or no operator authorization on the block | Check CFC block operator authorization; confirm S7 connection is set to "Read/Write" for the tag |
| Sum drifts negative unexpectedly | Quality code not checked; AS restart returns stale value | Add GetTagQuality check and default to 0 on bad quality (as in the example) |
| Redundant failover produces duplicate archive entries | Both servers wrote to the archive before the swap-over | Use WinCC Redundancy tag for archive owner identification; enable archive backup on the preferred server only |
12. Migration Checklist for Legacy Picture-Local Scripts
For sites that have accumulated picture-bound C actions over many years of PCS 7 upgrades, the following checklist helps a structured migration:
- Open Graphics Designer and search for the I/O field or object that contains the C action; document its tag dependencies and triggers.
- For each C action, determine whether the action's only consumer is the picture object itself (in which case it can stay) or whether any tag is written for cross-picture, archive, or AS-side consumption (in which case it must migrate).
- Create a Global Action with an appropriate cyclic trigger (1 s default) and the same calculation body.
- Replace the picture-bound C action with a tag binding to the new result tag.
- Compile and distribute the OS project; verify the tag is updating continuously in the runtime and the archive.
- Update the site engineering documentation and the project backup to reflect the new action location.
- Run a regression FAT on the picture to confirm the visual output is identical to the pre-migration behavior.
13. Reference: WinCC C API Functions Used in Continuous Actions
| Function | Header | Purpose |
|---|---|---|
| GetTagFloat / SetTagFloat | apdefap.h | Read/write 32-bit float tags |
| GetTagDouble / SetTagDouble | apdefap.h | Read/write 64-bit double tags |
| GetTagSWord / SetTagSWord | apdefap.h | Read/write 16-bit signed word tags |
| GetTagDWord / SetTagDWord | apdefap.h | Read/write 32-bit unsigned tags |
| GetTagQuality | apdefap.h | Return tag quality code (0x80 = good) |
| GetTickCount | windows.h | Wall-clock millisecond counter for throttling |
| sysFunction | apdefap.h | Calls into a project function with dynamic argument list |
For the comprehensive list, refer to the WinCC V8.0 "ANSI-C for Creating Functions and Actions" manual, included with every WinCC installation under Start → Siemens Automation → Documentation, and to the PCS 7 V9.1 add-on for PCS 7-specific block conventions.
14. Frequently Asked Questions
Why does my WinCC C script stop updating when I close the picture?
Because C actions attached to picture objects are evaluated by the Picture Manager (PDLRT.exe), which unloads the action when the picture closes. To run continuously, the action must be created as a Global Script Action in the Global Script editor and assigned a cyclic trigger, where it is hosted by the Global Script Runtime (GSRT.exe) for the entire Runtime session.
Which cycle should I use for a four-tag sum in a PCS 7 OS?
A 1 s standard cycle is the field-proven default for a sum of a handful of process tags. It is fast enough for operator visibility and slow enough to leave capacity for hundreds of other actions on the same OS server. Use 500 ms only if the sum drives a fast interlock or fast archive, and 250 ms only for closed-loop pre-processing.
Do Global Actions run on PCS 7 OS clients?
By default no. A Global Action is loaded only on the OS server. To run the same action on a client (for example, when no server holds the data), enable the "Run on OS Client" option in the action properties and distribute the action through the OS Project Editor. The same trigger cycle and code apply.
How can I tell whether my Global Action is actually firing on the OS server?
Open the WinCC GSC Diagnostics tool on the server, locate the action by name, and observe the trigger count and last execution timestamp. The trigger count should increase by the number of configured cycles that have elapsed (for a 1 s cycle, about 60 per minute). If the count is zero, the action is not loaded on that server.
Can I use a VBScript Global Action instead of C for the same task?
Yes, for most simple tag-arithmetic VBScript is functionally equivalent and is often easier to read. C is preferred when the calculation is performance-sensitive (sub-100 ms target), needs Win32 API calls, or interacts with binary buffers. VBScript is interpreted at execution time and is roughly 3-10x slower than compiled C for the same tag-arithmetic workload.
My tag value updates in the OS but the AS-side block does not see it; what is wrong?
Verify three items in order: (1) the WinCC tag is configured as an external tag with the correct S7 connection and read/write policy; (2) the PCS 7 plant view generated the tag with operator authorization on the consuming block; (3) the CFC block interconnection was compiled and downloaded. The S7 link is not the cause if the OS tag value is visible in Tag Diagnosis.
What happens to Global Actions when an OS server fails over to its redundant partner?
Both servers run the action independently because each holds its own S7 connection and tag image. The values written to the result tag are identical (assuming deterministic inputs). On failover, the standby becomes preferred and continues the calculation without a gap; the archive is owned by the preferred server, so no duplicate entries are created. The only practical caveat is to avoid static variables in the C action that store persistent state across failovers.