Overview
Alarm Architecture and Block Selection
An alarm flow on an S7-417 is end-to-end from a Boolean or threshold condition in the PLC scan to a discrete message row in WinCC Runtime. The principal components are:
- Source condition: a bit in I/O area, a flag, or a calculated comparison (analog threshold).
- Trigger FB: an SCL-coded Function Block (FB) that detects the condition, performs edge detection, and calls a message system function (SFC).
- Message system function: SFC 17 ALARM_S, SFC 18 ALARM_SQ, SFC 107 ALARM_8P, or SFC 108 ALARM_8. The SFC writes the event to the CPU diagnostic buffer and pushes it onto the AS-OS communication path.
- EV_ID: a 32-bit message number (DWORD at the FB input) that uniquely identifies the message text in the STEP 7 message configuration dialog.
- Associated values: up to 10 process values (SFC 17/18) or 8 (SFC 107) attached as raw 32-bit words to the message; WinCC formats them into the visible message text using @n%...@ placeholders.
- WinCC message database: receives events via the S7 protocol suite (WinCC channel "SIMATIC S7 PROTOCOL SUITE"), mapping each EV_ID to a message class, severity, and tag format.
| SFC | Name | Events per call | Associated values per event | Requires Ack? | Typical use |
|---|---|---|---|---|---|
| 17 | ALARM_S | 1 | 1 - 10 | Yes | Single limit-switch alarm, edge-triggered |
| 18 | ALARM_SQ | 1 (always-on while condition true) | 1 - 10 | Yes | State-driven alarms (e.g., valve open > 30 s) |
| 107 | ALARM_8P | 1 - 8 in one call | Up to 10 | Yes | Batch event delivery, 8 messages per scan |
| 108 | ALARM_8 | 1 - 8 in one call | — | No | Status-only, no ack required |
| 19 | ACK_OP | — | — | — | Operator acknowledgment of an alarm |
For the limit-switch case (200 individual signals, edge-triggered), the cleanest pattern is to instantiate one limit-switch FB per switch and call SFC 17 (ALARM_S) inside it. SFC 107 (ALARM_8P) only helps if you can guarantee at most eight events fire in a single OB1 scan — impractical for a 200-point array. For the analog case (100 inputs, warning plus alarm), the same instance strategy applies but with two EV_IDs per analog point.
EV_ID Numbering Strategy for 300+ Tags
Every configured message in STEP 7 has a unique EV_ID. STEP 7 reserves certain ranges for system messages; user-defined message numbers typically start at 1 within each message class. For 200 limit-switch messages plus 200 analog threshold messages (100 warning + 100 alarm) the total is 500 EV_IDs. Lay them out in contiguous blocks for clarity in the message dialog and in any imported WinCC CSV exports:
| EV_ID range (decimal) | Class | Source | Count |
|---|---|---|---|
| 1 - 200 | Alarm, requires acknowledgment | Limit switch 1 - 200 | 200 |
| 201 - 300 | Warning, no ack | Analog 1 - 100 (warning threshold) | 100 |
| 301 - 400 | Alarm, requires acknowledgment | Analog 1 - 100 (alarm threshold) | 100 |
iIdx * 2 for warning and alarm pairs) and add the base offset. This keeps EV_ID allocation out of the FB's static interface and makes the mapping self-documenting: instance 17, index 17, EV_ID 17.Designing the Limit-Switch FB in SCL
The following FB assumes a Boolean input i_bSignal, a configured EV_ID input i_dwEvId, an acknowledgment-expected flag i_bAckExpected, and an instance-level edge-memory bit s_bTrigMem. The FB calls SFC 17 (ALARM_S) on a rising edge of i_bSignal and supplies associated values describing the event.
FUNCTION_BLOCK FB_LimitSwitchAlarm
VAR_INPUT
i_bSignal : BOOL; // raw limit-switch bit
i_dwEvId : DWORD; // configured EV_ID for this point
i_bAckExpected : BOOL := TRUE;
i_wSigState : WORD; // associated value: 0=ok, 1=alarm
i_dwPointId : DWORD; // associated value: tag identifier
END_VAR
VAR
s_bTrigMem : BOOL; // edge memory
END_VAR
VAR_TEMP
tAssocValues : ARRAY[1..10] OF DWORD;
tRetVal : INT;
END_VAR
BEGIN
// Edge detection: fire once per rising edge
IF i_bSignal AND NOT s_bTrigMem THEN
s_bTrigMem := TRUE;
tAssocValues[1] := WORD_TO_DWORD(i_wSigState);
tAssocValues[2] := i_dwPointId;
tAssocValues[3] := DWORD#0; // pad remaining slots
tAssocValues[4] := DWORD#0;
tAssocValues[5] := DWORD#0;
tAssocValues[6] := DWORD#0;
tAssocValues[7] := DWORD#0;
tAssocValues[8] := DWORD#0;
tAssocValues[9] := DWORD#0;
tAssocValues[10] := DWORD#0;
tRetVal := ALARM_S(
SIG := TRUE,
ID := W#16#0,
EV_ID := i_dwEvId,
SEVERITY := W#16#0001,
ACK_STATE := i_bAckExpected,
MSG_FILTER := FALSE,
ASSOC_VAL := tAssocValues
);
// tRetVal holds the SFC return code; W#16#0000 = OK
END_IF;
// Reset trigger memory on signal clear
IF NOT i_bSignal THEN
s_bTrigMem := FALSE;
END_IF;
END_FUNCTION_BLOCK
ARRAY[1..10] OF DWORD temporary, populate every element, and pass the array base name. The compiler emits an inline call to SFC 17 at the FB's background DB. Uninitialized array elements yield DWORD#0 but will still be transmitted; always populate all 10 slots to keep the message frame deterministic.For 200 limit switches, instantiate the FB once per switch by manually dropping 200 FB calls in OB1, or by using a multi-instance DB approach. The cleaner alternative is to call the FB inside a FOR loop over a typed array of input points:
// OB1 - cyclic
FOR i := 1 TO 200 DO
iFB_Limit[i] ( // multi-instance array of FB_LimitSwitchAlarm
i_bSignal := "DB_I".ixLimit[i],
i_dwEvId := DWORD#16#00000001 + DINT_TO_DWORD(i - 1),
i_wSigState := "DB_I".iwState[i],
i_dwPointId := DWORD#16#000A0000 + DINT_TO_DWORD(i)
);
END_FOR;
The i_dwEvId expression maps instance 1 to EV_ID 1, instance 200 to EV_ID 200. STEP 7 message configuration must declare exactly those message numbers, or the CPU rejects the SFC 17 call with return code W#16#8081 (EV_ID not configured).
Analog Threshold Monitoring with Hysteresis
For the 100 analog inputs, define a parallel FB that does its own scaling, threshold comparison, and message generation. The associated values carry both the live reading and the threshold so the HMI can display the self-documenting alarm text without further tag reads.
FUNCTION_BLOCK FB_AnalogAlarm
VAR_INPUT
i_rRawValue : REAL; // engineering-units reading
i_rWarnLimit : REAL; // warning threshold (e.g., 80% of span)
i_rAlarmLimit : REAL; // alarm threshold (e.g., 95% of span)
i_dwEvIdWarn : DWORD; // 201..300
i_dwEvIdAlm : DWORD; // 301..400
i_dwPointId : DWORD; // tag identifier
i_bEnable : BOOL := TRUE;
END_VAR
VAR
s_rLastValue : REAL;
s_bWarnMem : BOOL;
s_bAlmMem : BOOL;
END_VAR
VAR_TEMP
tAssocValues : ARRAY[1..10] OF DWORD;
tRetVal : INT;
t_dwValue : DWORD;
t_dwLimit : DWORD;
END_VAR
BEGIN
IF NOT i_bEnable THEN
RETURN;
END_IF;
// ---- Warning (rising edge only, with hysteresis) ----
IF i_rRawValue >= i_rWarnLimit AND NOT s_bWarnMem THEN
s_bWarnMem := TRUE;
t_dwValue := REAL_TO_DWORD(i_rRawValue);
t_dwLimit := REAL_TO_DWORD(i_rWarnLimit);
tAssocValues[1] := t_dwValue;
tAssocValues[2] := t_dwLimit;
tAssocValues[3] := i_dwPointId;
tAssocValues[4] := DWORD#0;
tAssocValues[5] := DWORD#0;
tAssocValues[6] := DWORD#0;
tAssocValues[7] := DWORD#0;
tAssocValues[8] := DWORD#0;
tAssocValues[9] := DWORD#0;
tAssocValues[10] := DWORD#0;
tRetVal := ALARM_S(
SIG := TRUE,
ID := W#16#0,
EV_ID := i_dwEvIdWarn,
SEVERITY := W#16#0010, // 16 = warning class
ACK_STATE := FALSE,
MSG_FILTER := FALSE,
ASSOC_VAL := tAssocValues
);
ELSIF i_rRawValue < (i_rWarnLimit - 0.5) THEN
s_bWarnMem := FALSE; // clear with 0.5 EU hysteresis
END_IF;
// ---- Alarm (rising edge only, with hysteresis) ----
IF i_rRawValue >= i_rAlarmLimit AND NOT s_bAlmMem THEN
s_bAlmMem := TRUE;
t_dwValue := REAL_TO_DWORD(i_rRawValue);
t_dwLimit := REAL_TO_DWORD(i_rAlarmLimit);
tAssocValues[1] := t_dwValue;
tAssocValues[2] := t_dwLimit;
tAssocValues[3] := i_dwPointId;
tAssocValues[4] := DWORD#0;
tAssocValues[5] := DWORD#0;
tAssocValues[6] := DWORD#0;
tAssocValues[7] := DWORD#0;
tAssocValues[8] := DWORD#0;
tAssocValues[9] := DWORD#0;
tAssocValues[10] := DWORD#0;
tRetVal := ALARM_S(
SIG := TRUE,
ID := W#16#0,
EV_ID := i_dwEvIdAlm,
SEVERITY := W#16#0001, // 1 = highest severity
ACK_STATE := TRUE,
MSG_FILTER := FALSE,
ASSOC_VAL := tAssocValues
);
ELSIF i_rRawValue < (i_rAlarmLimit - 0.5) THEN
s_bAlmMem := FALSE;
END_IF;
s_rLastValue := i_rRawValue;
END_FUNCTION_BLOCK
Notice the hysteresis bands (0.5 engineering units) on the "clear" side. Without hysteresis, a noisy signal hovering at the threshold will chatter the alarm on every scan and flood the message buffer. STEP 7 message buffers in the S7-417 are sized for sustained bursts but alarm flooding remains a common commissioning defect. See the STEP 7 V5.x documentation index on the Siemens Industry Online Support portal for the complete ALARM_S parameter reference.
Programmatic Message Text Generation
The original question asked whether the message text can be set in the SCL code rather than per EV_ID in the message configuration dialog. The honest answer is: only the message number (EV_ID) is fixed in code; the message text is set in the configuration dialog. However, you can pass up to 10 associated values per alarm, and WinCC can format them into the visible message text using tag-formatting placeholders.
Configure the message text once with placeholders:
"Analog input <TagName> value = @1%6.2f@ exceeds warning limit @2%6.2f@"
When the alarm fires, associated value [1] (cast of the current reading as REAL, then DWORD) and associated value [2] (the warning limit) are substituted at runtime. The TagName placeholder cannot be passed as an associated value because STRINGs are not valid associated-value types — the name is fixed by which EV_ID fires. Practical consequence: you cannot have a single "generic" alarm with a dynamic tag name coming from inside the PLC. You must configure one message row per analog point.
STEP 7 Message Configuration
With the FBs compiled and downloaded, open the message configuration dialog in SIMATIC Manager:
- Right-click the FB (or the symbol) and select Special Object Properties > Message.
- In the message configuration dialog, click New to add a message row.
- Set the Message Number to match the EV_ID used in the FB call. The first message row you add gets message number 1 by default; subsequent rows increment automatically.
- Choose the message class (Alarm, Warning, Fault) and acknowledge behavior.
- Define up to 10 associated values; for the limit-switch FB, set values 1, 2, and 3 to
ixLimit[i](state),i_dwPointId(tag ID), and a pad. - Enter the message text in the format-string field. Use the
@1%...@placeholder syntax for associated-value formatting. - Save and download to the PLC. Without a download, the CPU does not know the message text.
For projects with 500 messages, consider using the STEP 7 Message Configuration CSV import/export. Export the dialog after manually configuring the first row, edit the CSV in Excel for the remaining 499 rows, and re-import. This reduces configuration time from hours to minutes.
WinCC Message Configuration
WinCC receives alarm events over the S7 protocol suite. Configure the channel and message mapping as follows:
- In WinCC Explorer, open Tag Management > SIMATIC S7 PROTOCOL SUITE.
- Add a connection to the S7-417. Use the MPI / PROFIBUS / Industrial Ethernet driver depending on the physical layer. For S7-417H redundant pairs, select the H-CPU-specific driver profile.
- Open Alarm Logging. The wizard prompts to import the message configuration from STEP 7; this imports all configured messages, classes, and associated-value formats.
- Confirm the import shows 500 rows (200 limit switches + 100 warnings + 100 alarms + any system messages). If the row count is short, STEP 7 did not download the full message configuration, or WinCC lost the connection mid-import.
- Configure the message view in the WinCC graphics designer. The default Alarm Control displays columns for Date, Time, Status, Class, Tag, Message Text, and Acknowledgment. The associated values render into the Message Text column at runtime via the placeholder substitution defined in STEP 7.
- Set the user authorization level required to acknowledge. STEP 7 default is Operator (level 2); change to Maintenance (level 5) if operators should not silence production-critical alarms.
The WinCC V7.x manual is the canonical reference for alarm configuration; specifically chapter 7 ("Configuring the Alarm Logging") and chapter 11 ("Operating the Alarm Control in Runtime"). See the SIMATIC WinCC V7.x manual set.
Alternative: HMI-Side Alarm Handling
The original poster asked whether alarm logic could live entirely on the HMI side. Partial answer:
- Yes, WinCC can be configured to generate an alarm when a polled tag crosses a configured limit, using the Alarm Logging limits on the tag itself. This avoids the EV_ID configuration in the PLC entirely.
- No, WinCC-side limits do not write to the PLC diagnostic buffer, do not appear in the CPU's Web server / diagnostic overview, and cannot be acknowledged back to the PLC. They are display-only.
For most industrial applications, the PLC-side alarm architecture is required for compliance with standards such as ISA-18.2 ("Management of Alarm Systems for the Process Industries") and IEC 62682, which prescribe that the alarm source of authority is the control system, not the operator interface. The PLC-side SFC path is therefore preferred.
Step-by-Step Commissioning Procedure
- Compile all blocks in STEP 7. Resolve any SCL warnings — pay attention to "uninitialized variable" warnings because SFC 17/18 will silently reject calls with garbage in associated values.
- Download hardware configuration first, then blocks, then message configuration as a separate download. The message configuration is a system data object that lives outside the S7 program.
- Verify CPU version: SFC 107 (ALARM_8P) and SFC 108 (ALARM_8) require S7-400 CPU firmware V3.0 or later. SFC 17/18 require V2.0 or later. The S7-417-4 (6ES7417-4XT05-0AB0) ships with V4.x firmware and supports all four SFCs. Confirm in PLC > Module Information.
- Test one message: hardwire one EV_ID in OB1 with a toggle, fire it, and confirm WinCC receives the event. Once one message works, scale up.
- Run a soak test: cycle all 200 limit switches and verify all 200 messages appear. Do the same for analog inputs across the operating range, including both warning and alarm thresholds.
- Load test: force all 200 switches to alarm at once. Observe CPU scan time and message buffer occupancy in PLC > Diagnostic Buffer. The S7-417 buffers up to 1000 pending messages; sustained over-run indicates you are calling SFC 17 more than your event rate allows.
-
Acknowledge round-trip: from WinCC, acknowledge the message. Confirm the
ACK_STATEflag returns to zero in the PLC diagnostic buffer. - Power-cycle test: restart the CPU. The retained message buffer should replay pending unacknowledged alarms in WinCC on reconnect.
Verification Checklist
| Check | Expected | Tool |
|---|---|---|
| All 500 EV_IDs configured | No W#16#8081 in diagnostic buffer | Module Information |
| WinCC receives events | Row count in Alarm Logging equals 500 | WinCC Alarm Control |
| Associated values populate | Reading + limit displayed in message text | WinCC Runtime message line |
| Acknowledge round-trip | WinCC ack clears the in-PLC state | Alarm Control + diagnostic buffer |
| Hysteresis active | No chatter on noisy signal | Plot historical alarm log |
| CPU scan time impact | < 5 ms additional OB1 time at 500 alarms/min | Module Information |
| Buffer does not overrun | < 800 pending after 1-hour soak | Diagnostic Buffer Statistics |
| HMI ack authorization enforced | Operator cannot silence maintenance alarms | User Administration |
Troubleshooting Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| Alarm never appears in WinCC | EV_ID not configured in STEP 7 message dialog | Open message dialog, add the EV_ID row, re-download |
| W#16#8081 in diagnostic buffer | EV_ID mismatch between SFC call and configuration | Cross-check i_dwEvId in each FB call against configured EV_IDs |
| W#16#8082 in diagnostic buffer | Number of associated values declared exceeds configured | Match array length to message configuration; pad unused with DWORD#0 |
| W#16#8084 in diagnostic buffer | SFC called outside OB1/OB40 (no alarm-capable OB) | Move SFC call to OB1, OB40, or OB1 with priority class 1-26 |
| W#16#8085 in diagnostic buffer | No further alarms possible (signal overflow) | Reduce alarm frequency; acknowledge backlog |
| Alarm appears but value field is empty | Associated value not passed correctly | Confirm array base passed to ALARM_S, not a copy; check REAL_TO_DWORD alignment |
| Alarm floods (every scan) | Missing edge detection / hysteresis | Add s_bTrigMem and hysteresis as shown in the analog FB |
| WinCC ack has no effect on PLC | Wrong message class / ack disabled | Set ACK_STATE := TRUE in configuration and FB call |
| CPU scan time jumps 50+ ms | Calling ALARM_S 200 times per scan even when idle | Gate SFC call behind edge detection; avoid OB40 call if not needed |
| Buffer overruns after 1 hour | Operator not acknowledging; rate > acknowledgment rate | Review operator workflow; raise alarm class severity; reduce flood rate |
| Associated value shows garbage | REAL passed without REAL_TO_DWORD conversion | Wrap every REAL associated value in REAL_TO_DWORD |
| Tag name in message text is wrong | EV_ID points to a different message row than expected | Re-export message config from STEP 7 and re-import in WinCC |
FAQ
Do I need PCS 7 to configure alarm messages on the S7-417?
No. PCS 7, STEP 7 V5.x with WinCC, and TIA Portal with WinCC Professional all support the same underlying message-capable SFCs (SFC 17, 18, 107, 108). The configuration dialog differs but the FB code in SCL is essentially the same. PCS 7 adds plant-level message classes and Operator Station routing, which is helpful for large plants but not required for a single-CPU single-HMI project.
Can I have one generic alarm message that displays the tag name dynamically?
No. Message text is bound to a configured EV_ID in STEP 7, and the tag name is fixed in that message row. Associated values can carry numeric values but not variable strings. For a "generic" feel, configure 100 messages with the same template and only the tag-name placeholder varying; this is fast in the message dialog because rows can be copy/pasted and the EV_ID is generated sequentially.
Why is my alarm flooding the message buffer?
You are calling SFC 17 on every OB1 cycle because the alarm condition is still true. Add edge detection (a memory bit that latches only on a 0-to-1 transition) and hysteresis (a clear threshold lower than the set threshold) so each alarm fires once per event. The S7-417 buffers up to 1000 pending messages; sustained overflow indicates an alarm-management design defect, not a buffer size issue, and the SFC returns W#16#8085 when no further alarms are possible.
What is the maximum number of messages an S7-417 can generate?
There is no published hard maximum number of EV_IDs, but practical limits come from CPU scan time and message-buffer throughput. For 500 configured messages with sporadic activation (less than 10 per second), the S7-417 is comfortable. For high-frequency alarms, batch them through SFC 107 (ALARM_8P) to send up to eight events per call. The S7-400 diagnostic buffer holds up to 1000 pending message entries.
Should I use ALARM_8P or ALARM_S for 200 limit switches?
ALARM_S (SFC 17) one call per switch is simpler to implement and reason about, and the FB-instance-per-signal pattern scales cleanly to 200 points. ALARM_8P (SFC 107) saves CPU time only if you can guarantee eight events are ready to send at the moment the FB runs; for limit switches spread across the scan cycle, that is rarely true. For the analog case with 200 events (100 warning + 100 alarm), ALARM_8P can help if you scan the analog inputs in batches of eight per FB call.
How does WinCC acknowledge an alarm back to the PLC?
WinCC Operator Station sends an acknowledgment packet over the S7 protocol using SFC 19 (ACK_OP) on the OS side, mapped through the channel to the configured EV_ID on the AS. The PLC then clears the in-CPU acknowledgment flag for that EV_ID. If acknowledgment does not propagate, verify the message class in STEP 7 has ACK_STATE := TRUE and that the WinCC user has the required authorization level.