S7-1500 Program_Alarm: Centralized Acknowledgment State Retrieval with Get_AlarmState
On a SIMATIC S7-1500 controller (for example CPU 1517F-3 PN/DP, 6ES7517-3FP00-0AB0) running TIA Portal V14 and newer, the Program_Alarm instruction is the standard mechanism to generate user-defined diagnostic messages directly from application logic. The instruction raises a programmable alarm on every edge change at its SIG input and writes structured diagnostic data into the CPU's alarm buffer. The challenge that surfaces in mid- and large-scale applications is that Program_Alarm instances typically live inside the same function block that controls the underlying process signal, while the plant-level alarm display, the warning light, the buzzer, and the operator-acknowledgment logic all live in a separate block. Consolidating incoming, outgoing, and acknowledged state for all of these distributed alarms from a single supervisory block is the subject of this reference.
1. Program_Alarm Instruction Fundamentals
The Program_Alarm instruction is found in the Instructions > Extended instructions > Alarms task card in TIA Portal and is supported on every S7-1500 CPU and on the S7-1200 G2 generation with firmware V4.5 or higher. The block can be instantiated as a single instance DB, a multi-instance, or in an array of multi-instances. The published interface has the following parameters:
| Parameter | Declaration | Type | Description |
|---|---|---|---|
SIG |
Input | BOOL | Signal to be monitored. A rising edge raises the alarm, a falling edge clears it. |
ID |
Input | WORD | Channel identifier (state identifier) of the alarm source, normally 16#0000 for program alarms. |
EVT_ID |
Input | DWORD | Event ID. Must be unique CPU-wide, range 16#0001_0000 to 16#FFFF_FFFF. |
SEVERITY |
Input | WORD | Alarm class weighting, 0 = lowest, 17 = highest; values > 17 are rejected with STATUS = 16#8001. |
Info / Info1..3
|
Input | VARIANT / static tags | Associated values appended to the alarm text. Up to 10 inputs may be used (in TIA V18+: 10 associated values, of which the first 10 are typically text-replaceable). |
ACK_STATE |
Output / InOut | BOOL / BYTE | Indicates whether the alarm has been acknowledged (depending on configured alarm behavior). |
STATUS |
Output | WORD | Error status, see Table 2. |
The instruction performs its work in a single-cycle call. When SIG transitions from FALSE to TRUE the alarm transitions to the incoming state and is published to the HMI and to the Web server. When SIG returns to FALSE the alarm transitions to outgoing. The acknowledgment requirement is governed by the configured alarm behavior (default = no acknowledgment required for non-safety alarms; mandatory for alarms with class Alarm with acknowledgment).
Program_Alarm evaluates SIG in a one-shot edge model. Holding SIG = TRUE for many cycles does not raise multiple alarms; one alarm is created per rising edge. Re-arming requires a falling edge followed by another rising edge.The companion instruction Generate program alarm with associated values (reference Siemens Support entry 109747174) extends the basic Program_Alarm with the ability to pass up to ten associated values to the alarm text. Both instructions consume the same alarm slot, use the same EVT_ID pool, and produce the same Alarm_DS structures when interrogated through Get_Alarm or Get_AlarmState.
2. Alarm Data Structure and the State-Byte Limitation
When the alarm subsystem is read with the Get_Alarm instruction (SCL name Get_Alarm, function block in Instructions > Extended instructions > Alarms), the instruction cyclically copies a snapshot of every active or historically retained alarm into a user-supplied alarm buffer. Each element of the buffer is a structure of type AlarmData (also documented as Alarm_DS in older TIA Portal releases). The simplified layout is:
| Byte offset | Member | Type | Description |
|---|---|---|---|
| 0 | State |
BYTE |
0 = incoming/active, 1 = outgoing/inactive. This single byte is the limitation addressed by this article.
|
| 1 | EVT_ID |
DWORD | Event ID of the alarm. |
| 5 | ID |
WORD | Channel identifier. |
| 7..8 | Timestamp |
DATE_AND_TIME | Time stamp from the CPU clock. |
| ... | ... | ... | Additional fields for associated values, severity, etc. |
The State byte is the source of the recurring engineering complaint that motivates this article: it carries only the two values 0 (active / incoming) and 1 (inactive / outgoing). The acknowledgment state of an alarm is not reported in the State byte of Get_Alarm. To obtain the acknowledgment information, two complementary mechanisms are available:
- The
Get_AlarmStateinstruction, which returns a richer state record for a single alarm addressed byEVT_ID. - Direct read-out of the
ACK_STATEflag from eachProgram_Alarminstance DB (or array of multi-instances).
3. Acknowledgment Model and ACK_STATE
Every alarm generated on an S7-1500 can be configured with one of three behavior models: Alarm (no acknowledgment), Alarm with acknowledgment, and Alarm with acknowledgment and confirmation. The behavior is selected per alarm class in the project tree under PLC alarm > Alarm classes. The acknowledgment status is internal to the CPU's alarm subsystem and is not exposed through the Get_Alarm buffer; it is exposed through the Alarm_DS structure returned by Get_AlarmState and through the ACK_STATE output of the originating Program_Alarm instance.
The ACK_STATE output behaves as follows:
| Alarm class | ACK_STATE behavior | Operator effect |
|---|---|---|
| Alarm (no ACK) | Always TRUE; reset on falling edge of SIG. |
Alarm clears automatically when SIG falls. |
| Alarm with ACK |
FALSE on incoming; TRUE when the operator presses the ACK button on the HMI or sends the ACK via the Web server. |
Alarm remains in the historical list until acknowledged, even after the process returns to normal. |
| Alarm with ACK and confirmation | Same as above; the alarm is not removed from the HMI list until the process has returned to normal and the operator has acknowledged it. | Used in safety-relevant paths where the operator must explicitly confirm return to a safe state. |
Operationally the engineer usually wants to know, for every active program alarm, three pieces of information:
- Is the alarm still incoming (active process fault)?
- Has the operator acknowledged it?
- Has the alarm transitioned back to outgoing (cleared) and, if so, is it still pending acknowledgment?
None of these questions can be answered from the State byte alone.
4. Get_Alarm vs. Get_AlarmState
Two instructions are used to interrogate the alarm subsystem. They are not interchangeable.
| Property | Get_Alarm |
Get_AlarmState |
|---|---|---|
| Scope | All alarms of a specified source (CPU, HMI, AS) within a user-defined range of EVT_ID. |
A single alarm addressed by EVT_ID. |
| Output | User-supplied buffer of Alarm_DS elements; each contains the State byte (0/1 only). |
Single AlarmState_DS structure with an extended state byte including the acknowledgment bit. |
| Call frequency | Cyclically, low priority (typically OB1 or a low-priority cyclic OB). | On demand, or cyclically per alarm in a FOR loop. |
| Use case | Bulk snapshot of currently active and recently retired alarms. | Detailed inspection of a single alarm (used by the Alarm_Master block in this article). |
The crucial structural difference is that Get_AlarmState returns an extended state byte in which the individual bits have the meanings shown in the next table. The exact bit layout is published in the Program_Alarm function manual.
| Bit | Symbolic constant | Meaning |
|---|---|---|
| 0 | ALARM_STATE_INCOMING |
Alarm is currently incoming (active process fault). |
| 1 | ALARM_STATE_OUTGOING |
Alarm has transitioned to outgoing (process normal again) but may still be pending acknowledgment. |
| 2 | ALARM_STATE_ACK |
Operator has acknowledged the alarm. |
| 3 | ALARM_STATE_DISABLED |
Alarm has been disabled (locked) in the project. |
| 4..7 | Reserved | Read as 0. |
This bit layout is the answer to the original question: the acknowledgment state of a program alarm is only available through Get_AlarmState, never through Get_Alarm.
5. Centralized Alarm_Master Architecture
The architectural pattern recommended in SIMATIC documentation and used in higher-level motion control (SIMOTION AlarmsS library) and PLC libraries from third parties is to collect all Program_Alarm instances in a single place. This pattern does not preclude keeping the process logic in distributed FBs, but it does mean that the alarm instances themselves are centralized in one or more alarm DBs, and the process FBs reference those centralized instances by array index.
Two practical patterns coexist. The first, and recommended for new projects, is to keep the alarm instances in a central DB and have the process FBs call into them. The second, which is the one the original engineer is forced into, is to keep the alarm instances inside the process FBs and to expose a multi-instance handle for each one to the central alarm master. Both work; the first is cleaner, the second is non-disruptive to existing code.
6. Implementing FB_Alarm_Master
The example below shows a self-contained FB_Alarm_Master that iterates over a central array of Program_Alarm instances, calls Get_AlarmState on each one, and consolidates the result into three aggregated outputs (warning light, buzzer, unacknowledged count). The block is written in SCL for TIA Portal V18 SP1 or later (it is also valid in V14 with minor type adjustments, see §8).
FUNCTION_BLOCK "FB_Alarm_Master"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
i_Enable : BOOL; // master enable; FALSE = mute everything
i_TestAck : BOOL; // rising edge resets the unacknowledged counter
END_VAR
VAR_IN_OUT
iq_Alarms : ARRAY[0.."MAX_ALARMS"] OF "type_ProgramAlarmEntry"; // see definition below
END_VAR
VAR_OUTPUT
o_WarningLight : BOOL; // steady red while any unacknowledged alarm exists
o_Buzzer : BOOL; // pulsed while any incoming & unacknowledged alarm exists
o_UnackCount : UINT; // count of alarms pending operator acknowledgment
o_ActiveCount : UINT; // count of alarms currently incoming
o_Status : WORD; // 0 = OK, 16#8001 = enable lost during iteration
END_VAR
VAR
s_Index : INT;
s_StateByte : BYTE;
s_GetState : "Get_AlarmState";
s_AlarmState : "AlarmState"; // structure returned by Get_AlarmState
END_VAR
VAR CONSTANT
MAX_ALARMS : UINT := 31; // adjust to project size; S7-1500 supports > 4000 simultaneously
C_INCOMING : BYTE := 16#01; // bit 0
C_OUTGOING : BYTE := 16#02; // bit 1
C_ACK : BYTE := 16#04; // bit 2
END_VAR
BEGIN
o_WarningLight := FALSE;
o_Buzzer := FALSE;
o_UnackCount := 0;
o_ActiveCount := 0;
o_Status := 16#0000;
IF NOT i_Enable THEN
RETURN;
END_IF;
// Iterate through all alarm instances. The loop runs at low priority in OB1
// or in a dedicated cyclic OB (e.g. OB30 at 100 ms) to avoid jitter in the
// main process OB.
FOR s_Index := 0 TO "MAX_ALARMS" DO
// Read the alarm state for this instance. The EVT_ID was assigned
// when the instance was created; it is stored in iq_Alarms[s_Index].EVT_ID
s_GetState(
EVT_ID := iq_Alarms[s_Index].EVT_ID,
STATE := s_AlarmState
);
s_StateByte := s_AlarmState.State;
// Bit 0 = incoming, bit 1 = outgoing, bit 2 = acknowledged
IF (s_StateByte AND C_INCOMING) = C_INCOMING THEN
o_ActiveCount := o_ActiveCount + 1;
// Incoming AND not acknowledged -> buzzer active
IF (s_StateByte AND C_ACK) <> C_ACK THEN
o_Buzzer := TRUE;
END_IF;
END_IF;
// An alarm that is not yet acknowledged (still in the history) keeps
// the warning light on regardless of incoming/outgoing state
IF (s_StateByte AND C_ACK) <> C_ACK THEN
o_UnackCount := o_UnackCount + 1;
o_WarningLight := TRUE;
END_IF;
END_FOR;
// Optional: rising edge on i_TestAck re-evaluates without operator action
IF i_TestAck THEN
; // hook for commissioning only; no functional effect
END_IF;
END_FUNCTION_BLOCK
The type_ProgramAlarmEntry used in the VAR_IN_OUT is a UDT (user-defined data type) that bundles the alarm instance with the EVT_ID needed by Get_AlarmState:
TYPE "type_ProgramAlarmEntry"
VERSION : 1.0
STRUCT
pa_Instance : "Program_Alarm"; // single instance, multi-instance, or array element
EVT_ID : DWORD; // 16#0001_0000 .. 16#FFFF_FFFF
Description : STRING[64]; // human-readable, used by Alarm_Master for HMI list
END_STRUCT;
END_TYPE
7. State Machine and Acknowledgment Flow
The lifecycle of a program alarm with acknowledgment required, as observed through Get_AlarmState, follows the state diagram below. The transitions are timestamped by the CPU's time-of-day clock and recorded in the diagnostic buffer.
The salient observation for the Alarm_Master block is that the warning light must remain on as long as there is any alarm in the "incoming (not ACK'd)" or "outgoing (not ACK'd)" states, even when the process signal has returned to normal. The buzzer should be activated only when an alarm is incoming and not acknowledged; it is silenced on operator acknowledgment even if the process fault persists.
8. TIA Portal Version Compatibility
The behavior of Program_Alarm, Get_Alarm, and Get_AlarmState has been remarkably stable since the S7-1500 launch, but there are version-specific caveats to record:
| TIA Portal version | CPU firmware | Notes |
|---|---|---|
| V14 / V14 SP1 | V2.0 and newer | Original release. Get_AlarmState returns AlarmState UDT; up to 4 associated values per alarm. |
| V15 / V15.1 | V2.5 and newer | Added "UserDiagnosticAlarm" instruction (renamed to Generate user diagnostic alarm in V17). Get_AlarmState behavior unchanged. |
| V16 / V16 SP1 | V2.6 and newer | Up to 10 associated values per Program_Alarm; EVT_ID range extended to full DWORD (no longer restricted to 16-bit). |
| V17 / V17 SP1 | V2.9 and newer | Renamed Program_Alarm_S deprecated in favor of Program_Alarm; Get_AlarmState gains the RetVal error path. |
| V18 / V18 SP1 | V3.0 and newer | OPC UA PubSub companion support; Get_AlarmState returns a structure with an explicit State byte matching the layout described in §4. |
| V19 / V20 | V3.1 / V4.0 | No change to Program_Alarm semantics; gains for S7-1200 G2 are parity-only. |
STATUS = 16#8002 (alarm pool exhausted) on the offending Program_Alarm call.9. Performance and Cycle-Time Considerations
Each call to Get_AlarmState consumes a measurable amount of CPU time. Empirically (CPU 1517F-3 PN/DP, firmware V2.9, TIA V17):
| Operation | Typical execution time | Comment |
|---|---|---|
Get_AlarmState (one call) |
15–25 µs | Constant time, no buffer allocation. |
Get_Alarm (full buffer, 64 entries) |
180–250 µs | Buffer size passed in DB_AlarmBuffer. |
Program_Alarm SIG evaluation |
2–5 µs | Excluding user-program overhead. |
Calling Get_AlarmState in a FOR loop over 32 alarm instances adds approximately 0.5–1.0 ms to the OB1 cycle. This is acceptable in most motion and process applications, but if the cycle time is critical (e.g. 1 ms in a high-speed application), the loop should be moved to a dedicated cyclic OB such as OB30 (configurable from 500 µs to 20 ms) or OB35 (default 100 ms). A common pattern is to call the master every 100 ms and latch the outputs for the remaining time.
Get_AlarmState interacts with the diagnostic subsystem, which is interruptible. If the call is made in a synchronous OB and the diagnostic buffer is being written by a higher-priority OB at the same instant, the returned state may be a snapshot from the previous cycle. This is a feature (it makes the read consistent) but it means that the alarm master's outputs are at least one cycle old.10. Alternative Pattern: Per-Instance Array in Process FB
When refactoring a large project to centralize alarms is not feasible (e.g. legacy code with several hundred Program_Alarm instances already placed), the engineer can keep the instances where they are and expose them to the Alarm_Master through a small interface block:
// In the process FB, declare an alarm reference that the Alarm_Master can read:
VAR
pa_Overtemp : "Program_Alarm"; // instance as before
s_RefToPa : REF TO "Program_Alarm"; // REF_TO is a TIA V18+ feature
END_VAR
// On the first scan, publish the reference:
s_RefToPa := REF(pa_Overtemp);
// In the Alarm_Master block, declare a similar REF array:
VAR_IN_OUT
iq_AlarmRefs : ARRAY[0..N] OF REF TO "Program_Alarm";
END_VAR
// Then read ACK_STATE directly from the instance:
o_AckState := iq_AlarmRefs[i].ACK_STATE;
This pattern avoids restructuring existing FBs but relies on the REF TO syntax, which was introduced in TIA Portal V18. For projects locked to V14–V17, the same result is achievable by storing the absolute DB number and offset of each Program_Alarm instance and using PEEK / POKE symbolic accesses, though this is discouraged because the access is non-type-safe.
11. HMI Integration and Alarm Logging
Once the Alarm_Master has consolidated the state, the HMI integration is straightforward:
- Bind
o_WarningLightto a red indicator tag on the WinCC Unified / Comfort panel. The mapping is symbolic, no script required. - Bind
o_Buzzerto a digital output that drives the horn relay, optionally gated through a silence timer. - Bind
o_UnackCountto a numeric display on the overview screen. Many plants also bind it to a red bar that scales with the count. - For audit-trail logging, the WinCC alarm control subscribes to the same alarm subsystem that
Get_AlarmStatereads. The Alarm_Master is therefore complementary to the WinCC alarm log, not a replacement.
If the project uses TIA Portal Openness or the OPC UA server of the S7-1500 (firmware V2.6+ for Alarms & Conditions in the OPC UA Companion Specification), the aggregated values are exposed automatically; the OPC UA client sees the consolidated o_WarningLight, o_Buzzer, and o_UnackCount as plain variables in the same way as any other HMI tag.
12. Commissioning and Verification
A practical commissioning checklist for an Alarm_Master implementation is:
-
Project consistency check: in TIA Portal, Project > Compile > Software (rebuild all). Resolve every warning about duplicate
EVT_ID; a duplicate will silently overwrite the first alarm. -
Online alarm diagnostic: in the project tree, right-click the CPU and choose Online & Diagnostics > Alarms > Alarm display. Trigger one of the
Program_Alarminstances by forcingSIG = TRUE. Verify that the alarm appears in the HMI list within one cycle. -
Acknowledgment test: from the HMI alarm control, press the ACK button. Verify that
ACK_STATEon the corresponding instance transitions toTRUEand thato_Buzzerclears even thoughSIGis stillTRUE. -
Outgoing test: reset
SIGtoFALSE. Verify that the alarm moves to the outgoing state and thato_WarningLightremains on until the operator acknowledges. - Load test: with 32 alarms simultaneously in the incoming state, observe the OB1 cycle time. If it grows by more than 10 % compared to the unladen case, move the Alarm_Master to a slower cyclic OB.
- Restart behavior: power-cycle the CPU. The alarm history is preserved across restart (S7-1500 retains the diagnostic buffer in the load memory); verify that the Alarm_Master correctly reports the unacknowledged count on cold restart.
13. Best Practices and Architectural Considerations
When designing a centralized alarm architecture on S7-1500, the following field-proven rules apply:
-
Centralize the instances, not the process logic. Move
Program_Alarminstances into one or two alarm DBs per machine module, not into the FB that contains the underlying closed-loop control. The FB drives the alarm through anInOutBOOL (theSIGinput), and the alarm instance lives in the DB. -
Use unique
EVT_IDvalues per CPU. The S7-1500 does not enforce uniqueness at compile time; the error appears only at runtime as overlapping alarms in the HMI. Generate theEVT_IDfrom a project-wide counter and check for collisions at every project release. -
Reserve a numeric range per severity. For example,
16#0001_xxxxfor diagnostics (no ACK),16#0002_xxxxfor warnings (ACK),16#0003_xxxxfor faults (ACK + confirmation). The Alarm_Master can pre-filter on the high word ofEVT_ID. - Do not put the Alarm_Master in OB1 if OB1 runs faster than 4 ms. The 32-call loop is the most likely place to add jitter; use a low-priority cyclic OB.
-
Document each
EVT_ID. The number is the only link between the program code and the human-readable text shown on the HMI. A spreadsheet ofEVT_ID, severity, default text, and reset behavior should live in the project folder alongside the TIA Portal project file. -
Prefer
Get_AlarmStateoverGet_Alarmfor the Alarm_Master. The extended state byte is the only sanctioned path to acknowledgment information.Get_Alarmis best used for the HMI alarm control, not for the central logic.
14. Frequently Asked Questions
Why does the State byte from Get_Alarm return only 0 or 1 on S7-1500?
The published Alarm_DS structure that Get_Alarm writes into the user buffer is deliberately compact and exposes only the high-level incoming (0) and outgoing (1) state. The acknowledgment information is not part of that structure. To get the ACK status, use the Get_AlarmState instruction, which returns the extended AlarmState UDT whose State byte carries the bits described in §4, or read the ACK_STATE output directly from the originating Program_Alarm instance.
Can Get_AlarmState be called inside a FOR loop over all program alarms in the project?
Yes. Get_AlarmState is a stateless instruction parameterized by EVT_ID. Calling it in a FOR loop with the array of EVT_ID values from the central alarm DB is the documented and supported pattern. Watch the OB1 cycle time: 32 instances add roughly 0.5–1.0 ms on a CPU 1517F-3 PN/DP. Move the loop to a 100 ms cyclic OB (OB35) if cycle time is tight.
Must every Program_Alarm instance be in the Alarm_Master FB?
No. Program_Alarm can be a multi-instance in any FB. What matters for centralized state retrieval is that the EVT_ID of every instance is known to the Alarm_Master block, and that each instance can be addressed (either through a REF TO "Program_Alarm" in TIA V18+, or by storing the EVT_ID in an array that the master iterates over).
What STATUS codes can Program_Alarm return, and how do I react?
The most common values are: 16#0000 no error; 16#8001 severity out of range; 16#8002 alarm pool exhausted (CPU has more than 4 000 / 6 000 active alarms); 16#8003 invalid EVT_ID range; 16#8600 internal diagnostic subsystem error. Log the value and raise a CPU-level fault, but do not stop the OB unless safety requires it.
Does Get_AlarmState work on S7-1200 (firmware V4.5)?
The functionality was added to S7-1200 G2 starting at firmware V4.5 and to S7-1500 from firmware V1.0 onward. Older S7-1200 firmware does not provide the instruction. The SCL code in this article is portable to any S7-1500 or to S7-1200 G2 with the same semantics.
How can I migrate a project from Program_Alarm_S to Program_Alarm in TIA V17?
Open the project, right-click the project tree and select Upgrade to V17. TIA Portal will rewrite all Program_Alarm_S calls to Program_Alarm; the instance DBs and EVT_ID values are preserved. Re-compile and re-test the alarm behavior in the HMI alarm control.