Triggering WinCC 7.4 Alarm Sounds from Word Tags via C-Script

David Krause11 min read
SiemensTutorial / How-toWinCC
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

Triggering WinCC 7.4 Alarm Sounds from Word Tags via C-Script

WinCC 7.4 SCADA systems frequently require acoustic notification when an alarm is raised, a process value crosses a threshold, or an operator event occurs. The Horn Editor shipped with WinCC 7.4 accepts only binary tags for horn triggering, which presents a direct limitation: a 16-bit or 32-bit WORD/DWORD tag — the most common structure for alarm status words, error registers, or device fault codes coming out of a PLC — cannot be wired directly into the Horn tab. This article provides a complete procedure to detect changes or value thresholds in a WORD tag and trigger a WAV playback through a WinCC Global Script C action, including handling multi-bit alarm words, debouncing, and assigning different sounds per bit position.

1. Why the Horn Editor Rejects WORD Tags

The Horn Editor is part of the WinCC Explorer (right-click your computer → PropertiesHorn) and is bound to message classes in Alarm Logging. The trigger objects available in the trigger list are restricted to:

  • Binary internal tags (channel: Internal)
  • Binary process tags (channel: e.g. SIMATIC S7-PLC, MODBUS TCP, OPC)
  • Tag bits accessible via the GetTagBit interface (e.g. MyWord_0 for bit 0 of the WORD tag MyWord)

Selecting a raw WORD tag is rejected because the horn evaluation is a Boolean signal path; it expects a single bit transition to start or stop playback. A 16-bit value is treated as a numeric data object that must be decomposed into individual bits before the horn can react. The same restriction applies to DWORD, INT, and REAL tags — they must be reduced to binary representations upstream of the Horn Editor.

Engineering implication: Do not duplicate alarm state in 16 separate binary tags on the PLC side if a single WORD is already in use. Instead, mask and decode the WORD inside WinCC using internal tag aliases or a C-action. This minimizes PLC engineering effort and keeps the alarm dictionary the single source of truth.

2. Two Engineering Approaches

Approach Mechanism Best Used When
A. Bit alias tags + Horn Editor WinCC internal tags reference individual bits of the WORD using MyWord_x syntax. Each bit is wired as a horn trigger. Alarm dictionary is fixed; you want Alarm Logging to drive the horn directly.
B. C-Script Global Action A scheduled C action polls the WORD tag, evaluates bits or value ranges, and calls PlaySound/mciSendString to play a WAV file. Custom mapping logic, multi-level alarms, or sound files that change at runtime.

Approach A is the simplest when the WORD is purely an aggregation of single-bit alarms. Approach B is required when:

  • The same WORD carries encoded alarm classes (e.g. bits 0–3 = severity, bits 4–7 = subsystem).
  • You need to play different WAV files per bit position without creating 16 horn entries.
  • The horn must react to value transitions (e.g. counter > 100) rather than discrete bits.

3. Prerequisites

  1. WinCC 7.4 SP3 or later installed (the project structure described is verified against the WinCC V7.4 SP3 release notes).
  2. The WORD tag (e.g. AlarmWord) is configured in the WinCC Tag Management with the correct channel driver, data type WORD (unsigned 16-bit), and a sensible update cycle (250–1000 ms typical for alarms).
  3. WAV files are placed in a directory the WinCC Runtime can access. The project subfolder <Project>\GraCS\ is the conventional location; the runtime automatically searches \GraCS, the project root, and \ssm.
  4. Sound device enabled on the operator station (Windows Audio Service running, default audio device selected).
  5. Editor access to Global Script C (requires the WinCC Configuration Studio and the Global Script Runtime right on the user).
Sound format: Use 16-bit PCM mono WAV at 22.05 kHz for predictable playback latency. MP3 is not supported by the WinCC PlaySound function. If a beep is required instead of a WAV, use the Windows MessageBeep API (see Section 7).

4. Approach A: Bit Alias Tags (No Scripting)

This method exposes every bit of the source WORD as a virtual internal tag using WinCC's built-in tag bit addressing.

4.1. Create the Internal Bit Aliases

  1. Open WinCC Explorer → Tag Management.
  2. Select the connection (or create an Internal connection if the bit mapping should remain in WinCC).
  3. Right-click → New Tag and create 16 tags named AlarmWord_0 through AlarmWord_15 with data type Binary Tag.
  4. In the tag properties, set the Address field to reference the source WORD plus bit offset. The syntax depends on the channel driver; for an S7-1500 connection using the symbol name "AlarmWord" the addressing would remain a single tag — the bit extraction is performed at tag-creation time using the PLC's bit-access syntax "AlarmWord".X0 only for S7-PLCSIM symbolic access. For MODBUS, the equivalent is 40001.0 through 40001.15 (function code 03, address+bit).

For internal-only evaluation, the simplest reliable method is:

  1. Create 16 internal binary tags.
  2. Create a Global Script Action with a 1 s trigger that reads the source WORD, masks each bit, and writes the result into the internal binary tag:
// Global C action — scheduled every 1000 ms
#include "apdefap.h"
int gscAction(void)
{
    DWORD raw = 0;
    raw = GetTagWord("AlarmWord");  // returns unsigned 16-bit value
    int i;
    for (i = 0; i < 16; i++)
    {
        char tagname[32];
        sprintf(tagname, "AlarmWord_%d", i);
        SetTagBit(tagname, (raw >> i) & 0x0001);
    }
    return 0;
}

The 16 internal tags are then bound to the Horn Editor as ordinary binary triggers.

4.2. Configure the Horn

  1. In WinCC Explorer, right-click your computer → PropertiesHorn.
  2. Click Add…. For each bit, pick the message class (e.g. Alarm, Warning) and select the corresponding internal tag (e.g. AlarmWord_3) in the trigger column.
  3. Assign the WAV file. Click the Sound cell and browse to the WAV in \GraCS\Sound.
  4. Configure the acknowledge behaviour: On acknowledge (sound stops only when the operator clicks Acknowledge) vs. On reset (sound stops as soon as the bit clears).

5. Approach B: C-Script Global Action for Direct WAV Playback

When the Horn Editor is too rigid (custom mapping, conditional horn, runtime sound selection), a Global Script C action drives the audio subsystem directly. The official Siemens FAQ "How do you output a sound via C script in WinCC V7?" is the canonical reference for this technique. The implementation below extends that FAQ with WORD-tag evaluation, latching, and per-bit sound selection.

5.1. Project Layout

  • <Project>\GraCS\Horn\Fault1.wav
  • <Project>\GraCS\Horn\Fault2.wav
  • <Project>\GraCS\Horn\Critical.wav
  • Global Script action WordHornAction — scheduled, trigger = 500 ms.

5.2. The C Action

// Global C action — WordHornAction.prg
// Polls the WORD tag "AlarmWord" and plays a WAV when a bit rises.
// Uses mciSendString from winmm.dll to play the file.

#include "apdefap.h"
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

int gscAction(void)
{
    static DWORD sLastValue = 0xFFFF;   // sentinel: triggers on first call
    DWORD raw = GetTagWord("AlarmWord");
    if (raw == sLastValue) return 0;    // no change → no horn

    DWORD rising = raw & ~sLastValue;  // bits that just turned ON
    sLastValue = raw;

    char cmd[512];
    char file[256];

    // Bit 0  → critical alarm (highest priority)
    if (rising & 0x0001)
    {
        sprintf(file, "%s\\GraCS\\Horn\\Critical.wav", GetProjectPath());
        sprintf(cmd,  "open \"%s\" type waveaudio alias crit", file);
        mciSendString(cmd, NULL, 0, NULL);
        mciSendString("play crit", NULL, 0, NULL);
    }

    // Bit 3  → Fault1
    if (rising & 0x0008)
    {
        sprintf(file, "%s\\GraCS\\Horn\\Fault1.wav", GetProjectPath());
        sprintf(cmd,  "open \"%s\" type waveaudio alias f1", file);
        mciSendString(cmd, NULL, 0, NULL);
        mciSendString("play f1 from 0", NULL, 0, NULL);
    }

    // Bit 7  → Fault2 (loops until bit clears)
    if (rising & 0x0080)
    {
        sprintf(file, "%s\\GraCS\\Horn\\Fault2.wav", GetProjectPath());
        sprintf(cmd,  "open \"%s\" type waveaudio alias f2", file);
        mciSendString(cmd, NULL, 0, NULL);
        mciSendString("play f2 repeat", NULL, 0, NULL);
    }

    // Stop the looping Fault2 when bit 7 clears
    if (!(raw & 0x0080))
        mciSendString("stop f2", NULL, 0, NULL);

    return 0;
}

5.3. Triggering the Action

  1. In WinCC Explorer → Global ScriptC-Editor, open the file above.
  2. Right-click the action function gscActionInformation/TriggerAdd.
  3. Configure a cyclic trigger of 500 ms (do not go below 250 ms on a large project; the action will be a load on the script engine).
  4. Save, then compile (File → Compile or Ctrl+F7). Errors appear in the output window — fix missing #include paths or typos before starting Runtime.
RT licensing note: The C-Editor requires at least the WinCC RT 4096 tag license on the operator station. The action itself consumes a Global Script Runtime seat. See the WinCC V7.4 licensing guide for the latest price-list position.

6. Verification Procedure

  1. Force the source WORD from the PLC (or simulate via an internal tag) to 0x0001Critical.wav must play once and stop.
  2. Set the WORD to 0x0080Fault2.wav must loop continuously.
  3. Set the WORD to 0x0000 → looping must stop within one trigger interval (≤ 500 ms).
  4. Set the WORD to 0xFFFF on startup → all mapped WAVs play once, no double-fire, no missed bit.
  5. Restart WinCC Runtime (simulate power-cycle) with the WORD already at 0x0001 in the PLC. Because the action uses a sentinel 0xFFFF, the first poll detects the rising edge and fires the horn exactly once.

7. Alternative: Beep Instead of WAV

For a one-channel operator-station buzzer you can call the Win32 API directly without a WAV file:

// inside gscAction, instead of mciSendString
if (rising & 0x0001) MessageBeep(MB_ICONHAND);   // critical
if (rising & 0x0008) MessageBeep(MB_ICONEXCLAMATION);

The advantage is zero asset management; the disadvantage is the sound cannot be customized per project and is tied to the Windows sound scheme.

8. Troubleshooting Matrix

Symptom Probable Cause Fix
No sound, no error in GSC output WAV file not in the runtime's search path Place the WAV in <Project>\GraCS\ or pass the absolute path with GetProjectPath()
Horn fires continuously even after bit clears Loop without stop; no falling-edge evaluation Add the stop f2 block from §5.2 or call PlaySound(NULL,NULL,0)
Horn misses bits on the first poll Static last-value initialised to 0 Initialise the static variable to 0xFFFF so the first read is always treated as an edge
"mciSendString returned 263" error Alias name already open from a previous call Issue close f1 / close f2 / close crit at the top of the action, or use unique aliases per call
Action compiles but does not run Trigger configuration not activated Right-click the action → Information/Trigger → verify the trigger is enabled and the project is activated
Sound cuts off on alarm acknowledgement Horn set to "On acknowledge" Switch the message-class property to "On reset" if the bit auto-clears in the PLC
Audio device not available after RDP session Windows audio service not running in the RDP context Configure the operator station as a console session, not a thin-client RDP target, or enable audio redirection

9. Performance and Reliability Considerations

  • Keep the cyclic trigger ≥ 250 ms. Each poll performs a tag read and a small amount of bitwise logic; the cost is negligible, but the MCI open/close per WAV is heavier — 50 ms or more on Windows 10/11.
  • Use GetTagWord / SetTagBit as the synchronous API only for low-frequency polling. For high-frequency updates (> 5 Hz) prefer the asynchronous variant or use Alarm Logging as the data source.
  • Localize the WAV file paths with GetProjectPath(). Hard-coded paths break the moment the project is moved or activated on a different machine.
  • For redundant servers, copy the WAV files in both server projects, or store them on a shared drive and reference the UNC path.
  • Do not put a for-loop over 16 calls to mciSendString — instead precompute the rising mask and branch only on the bits that actually changed, as shown in §5.2.

10. Relationship to Alarm Logging

If the goal is to play a sound on every alarm message of a given class, the recommended route is to let Alarm Logging drive the horn — not the C action. The C action is the correct tool only when the alarm state is encoded in a non-binary tag, or when the WAV must be selected dynamically. To convert Alarm Logging messages to horn triggers, configure the message class's Acknowledgement and Horn properties in WinCC Explorer → Alarm Logging and select the appropriate internal binary or process bit. Detailed step-by-step procedure is in the WinCC Information System under Alarm Logging → Configuring the Horn.

FAQ

Can the Horn Editor in WinCC 7.4 trigger directly from a WORD tag?

No. The Horn Editor accepts only binary tags or single tag bits (e.g. MyWord_0). For a 16-bit WORD you must either expose 16 bit-alias tags or use a C-Script Global Action to play the WAV directly via mciSendString.

Which Siemens document covers sound output via C script in WinCC V7?

Siemens Support entry ID 748844 "How do you output a sound via C script in WinCC V7?" describes the PlaySound / mciSendString approach used in this article.

What WAV format is recommended for WinCC horn playback?

Use 16-bit PCM mono WAV at 22.05 kHz placed under <Project>\GraCS\. MP3 and other compressed formats are not supported by PlaySound or the MCI waveaudio interface.

How do I avoid double-firing the horn on WinCC Runtime startup?

Initialise the static "last value" variable in the C action to 0xFFFF (or any value impossible in normal operation). The first poll will then detect a true rising edge for every active bit and fire each horn exactly once.

Can I use a DWORD or REAL tag with the same script?

Yes. Replace GetTagWord with GetTagDWord or GetTagFloat and adjust the bit-mask constants. For a REAL tag, evaluate value thresholds instead of bit positions (e.g. if (value > 95.0) PlaySound(...);).

Back to blog