Logging Heater On/Off Events with Siemens MP370 HMI and S7 PLC

David Krause13 min read
HMI / SCADASiemensTutorial / How-to
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

Problem Overview

Recording every transition of a heater contactor on an extruder supervised by a Siemens MP370 12-key HMI is a recurring field requirement: operators want to know when the heater was turned on, when it was turned off, and how many such events occurred between two product batches. A naive approach using an S7 run-time meter does not produce a time-stamped event list, and a naive alarm configuration emits duplicate alarms because the alarm bit is level-triggered rather than edge-triggered.

The proper technique combines three standard SIMATIC building blocks:

  1. SFC 1 READ_CLK to read the PLC's wall-clock (DATE_AND_TIME) at the exact instant a state transition is detected.
  2. Edge detection (R_TRIG / P_TRIG, or the legacy FP bit logic) so that a single on-transition produces a single log entry instead of being retriggered every OB1 scan.
  3. A FIFO buffer stored in a data block as an array of DATE_AND_TIME tags, shifted each time the buffer overflows.

The MP370 panel (Multi Panel family, xP170/xP270/MP370 series) is engineered for ProTool and WinCC flexible 2004 through 2008 SP5; it is not supported by TIA Portal. All coding in this article targets STEP 7 V5.5 / V5.6 with S7-300 or S7-400 firmware, which is the native pairing for the MP370.

Note on platform: If your controller is S7-1200/S7-1500, SFC1 is replaced by RD_SYS_T (read system time, returns DTL) and the FIFO array element type changes to DTL. The MP370 cannot talk to S7-1200/1500 controllers over the older PPI/MPI/Profibus protocols and requires at least an S7-300/400-class CPU.

Architecture and Prerequisites

Minimum hardware/software stack for a working implementation:

Component Required Version Notes
Operator panel MP370 12-key (6AV6545-0BA15-2AX0 or similar) 12 function-key variant, color TFT
PLC CPU SIMATIC S7-31x or S7-41x, FW ≥ V2.0 recommended Integrated real-time clock on board
STEP 7 V5.5 + SP2 or V5.6 Classic, not TIA Portal
HMI configuration ProTool V6.0 SP3 or WinCC flexible 2008 SP5 WinCC flexible is preferred for 12-key projects
Cabling MPI or PROFIBUS DP, 1.5 Mbps default PROFIBUS recommended for tag throughput
OB1 cycle time ≤ 50 ms Faster than the heater PLC control scan

The MP370 supports the SIMATIC S7 MPI/DP protocol driver, which exposes DB tags directly. Each DATE_AND_TIME (8 bytes BCD) is read by the panel as a raw 8-byte field; the panel's own date/time display fields convert the bytes via the standard S7 decoding.

Reading the System Clock with SFC 1 (READ_CLK)

SFC 1 READ_CLK reads the CPU's internal real-time clock and returns it as a DATE_AND_TIME value. The function has no input parameter; the output is written to a temporary variable of type DATE_AND_TIME.

Parameter Declaration Data Type Description
RET_VAL OUTPUT INT Error code: W#16#0000 = OK; W#16#8081 = clock not set or defective
CDT OUTPUT DATE_AND_TIME Current date and time, 8 bytes BCD

Reference: SFC 1 / SFC 0 — READ_CLK / SET_CLK — SIMATIC S7-300/400 Standard and System Functions manual (entry ID 109751706).

The DATE_AND_TIME data type is a fixed 8-byte (64-bit) BCD structure:

Byte Field Range Encoding
0 Year 1990 – 2089 BCD, e.g. 23 = year 2023
1 Month 01 – 12 BCD
2 Day 01 – 31 BCD
3 Hour 00 – 23 BCD
4 Minute 00 – 59 BCD
5 Second 00 – 59 BCD
6,7 ms + weekday 000 – 999 / 1–7 BCD; bits 7-4 of byte 7 = weekday (1=Sun)

This format is what the MP370 expects when a tag of type Date/Time is configured to point at a DB byte offset that is byte-aligned. Always keep the offset to an even byte; mis-aligned offsets produce W#16#80Bx decode errors on the panel.

Edge Detection: Why Duplicate Alarms Occur

The original poster reports that two alarms are generated when the heater turns on and two when it turns off. This is the classic symptom of level-triggered alarm logic. Each alarm has two states (inactive / active) and is re-evaluated every cycle. As long as the trigger bit is "1", the alarm remains "active"; when the trigger bit returns to "0", the alarm raises a "cleared" event. The panel then displays:

  • Heater ON alarm — appears (rising edge of trigger)
  • Heater ON alarm — cleared (falling edge, almost immediate if trigger is short)

If both "on" and "off" alarms share the same trigger (the heater bit), the HMI also fires the off-alarm when the bit drops, producing a "two on, two off" pattern. The fix is to:

  1. Evaluate the heater bit in edge-triggered mode so that a transition is detected exactly once.
  2. Use separate on-edge and off-edge bits that latch for one OB1 scan.

The two standard edge detectors are:

Mechanism IEC FB STL legacy Use
Rising edge R_TRIG (FB definition in STEP 7 standard library) FP / "--|P|--" One-shot on FALSE → TRUE
Falling edge F_TRIG FN / "--|N|--" One-shot on TRUE → FALSE

Reference for edge FBs: R_TRIG / F_TRIG — SIMATIC S7-300/400 Standard Library Bit Logic Functions (entry ID 12154079).

FIFO Buffer Implementation in S7

A FIFO (first-in / first-out) is required because each new event must push the oldest entry out. The simplest, code-efficient implementation for S7-300/400 is an array-shift FIFO: an ARRAY[1..N] of DATE_AND_TIME, an integer counter, and a FOR loop that shifts all entries one slot down when the buffer is full.

Step 1 — Data Block

DATA_BLOCK DB_HeaterLog
TITLE = 'Heater On/Off Event Log'
  STRUCT
    evt : ARRAY[1..100] OF DATE_AND_TIME;  // 800 bytes
    cnt : INT;                              // number of valid entries
    heater_evt_on  : BOOL;                  // one-shot rising edge flag
    heater_evt_off : BOOL;                  // one-shot falling edge flag
  END_STRUCT
END_DATA_BLOCK

With 100 entries the DB is roughly 802 bytes. S7-300 CPUs handle this comfortably in the work area; for S7-314 with 96 KB of work memory, keep the array ≤ 200 entries.

Step 2 — SCL Logic in OB1

FUNCTION_BLOCK FB_HeaterLogger
VAR
    Heater       : BOOL;     // I-input: heater contactor feedback
    LastHeater   : BOOL;     // static: previous scan state
    EdgeOn       : BOOL;     // rising-edge pulse
    EdgeOff      : BOOL;     // falling-edge pulse
    CDT_now      : DATE_AND_TIME;
    i            : INT;
    R_TRIG_On    : R_TRIG;
    F_TRIG_Off   : F_TRIG;
END_VAR

BEGIN
    // ---- edge detection ----
    R_TRIG_On(CLK := Heater, Q => EdgeOn);
    F_TRIG_Off(CLK := Heater, Q => EdgeOff);

    // ---- timestamp and shift ----
    IF EdgeOn OR EdgeOff THEN
        SFC1(CDT := CDT_now);

        // overflow handling: shift older entries down
        IF "DB_HeaterLog".cnt >= 100 THEN
            FOR i := 1 TO 99 DO
                "DB_HeaterLog".evt[i] := "DB_HeaterLog".evt[i+1];
            END_FOR;
            "DB_HeaterLog".cnt := 99;
        END_IF;

        "DB_HeaterLog".cnt := "DB_HeaterLog".cnt + 1;
        "DB_HeaterLog".evt["DB_HeaterLog".cnt] := CDT_now;
        "DB_HeaterLog".heater_evt_on  := EdgeOn;
        "DB_HeaterLog".heater_evt_off := EdgeOff;
    END_IF;
END_FUNCTION_BLOCK

Step 3 — STL Equivalent (no SCL required)

// Heater = I 0.0   (input bit)
// DB20   = DB_HeaterLog
// EdgeMem = M 10.0 (static memory for edge bit)

NETWORK 1  // Rising edge of Heater
  A   "Heater"
  FP   "EdgeMem_Heater"
  =    "DB_HeaterLog".heater_evt_on

NETWORK 2  // Falling edge of Heater
  AN   "Heater"
  FN   "EdgeMem_Heater"
  =    "DB_HeaterLog".heater_evt_off

NETWORK 3  // Read clock and store
  A    "DB_HeaterLog".heater_evt_on
  O    "DB_HeaterLog".heater_evt_off
  JCN  END3
  CALL SFC1
        CDT   := #CDT_now
        RET_VAL := #ret

  // shift if full
  L     "DB_HeaterLog".cnt
  L     100
  >=I
  JC    SHIFT
  JU    STORE

SHIFT:
  L     1
T_LOOP: T   #i
  L     #i
  L     1
  -I
  SLD   3
  LAR1
  L     DBW [AR1,P#0.0]
  T     #temp_word
  L     #temp_word
  // ... (omit: shift loop body — see SCL version)
  L     #i
  L     99
  <I
  JC    T_LOOP
  L     99
  T     "DB_HeaterLog".cnt

STORE:
  L     "DB_HeaterLog".cnt
  +    1
  T     "DB_HeaterLog".cnt
  // copy CDT_now into evt[cnt]
  LAR1 P##CDT_now
  L     DBB [AR1,P#0.0]
  T     DBB [AR1,P#0.0]   // (illustrative; proper AR2 usage required)

END3:  NOP 0

The SCL version is strongly preferred for clarity. The STL excerpt is shown to confirm that the algorithm ports to STEP 7 installations without an SCL license.

MP370 HMI Configuration in WinCC flexible

  1. Connection: In the WinCC flexible project tree, open Communication → Connections. Add a SIMATIC S7 MPI/DP connection. Set MPI address 2 for the panel, 2 for the CPU, and bus profile 1.5 Mbps.
  2. Tags: Create area pointers and process tags:
    • Tag HeaterState — BOOL — DB20.DBX0.0 (in practice, point at the live heater bit, not the edge bit).
    • Tag HeaterOnPulse — BOOL — DB_HeaterLog.heater_evt_on
    • Tag HeaterOffPulse — BOOL — DB_HeaterLog.heater_evt_off
    • Tag EvtCnt — INT — DB_HeaterLog.cnt
    • Tag EvtArray[0..99] — DATE_AND_TIME — DB_HeaterLog.evt[1..100]
  3. Alarm configuration: In Alarms → Discrete Alarms, create two alarms:
    Alarm Text Trigger Tag Trigger Edge
    "Heater ON — logged" HeaterOnPulse Rising
    "Heater OFF — logged" HeaterOffPulse Rising
    Setting trigger edge to rising ensures exactly one event per OB1 pulse, regardless of how long the heater remains on.
  4. Alarm view: Place an Alarm View object on a screen, configured to display the alarm buffer with date/time stamp. The MP370 inserts the panel's own timestamp; for an authoritative PLC-side timestamp, configure an additional Output field with the EvtArray[EvtCnt-1] tag formatted as Date/Time.
  5. Export: Connect the alarm buffer to the Alarm Logging persistent storage on the MP370 (CF card slot at the rear of the unit). Set the buffer size to ≥ 512 entries and the retention to ring buffer.
Cyclic acquisition vs. change-driven: The DATE_AND_TIME array must be acquired on change by the panel. With 100 entries, polling each tag every 1 s costs 100 acquisition cycles/s — acceptable on PROFIBUS at 1.5 Mbps but wasteful on MPI. Use Cyclic continuous with a 2 s poll only for the live tag HeaterState; configure all log entries with On change acquisition mode.

Sample SCL Function Block (drop-in)

The complete drop-in FB that can be inserted into an SCL source file in STEP 7 V5.5+:

FUNCTION_BLOCK FB_500 "HeaterEventLogger"
VERSION : 1.0
VAR_INPUT
    HeaterInput : BOOL;     // TRUE = heater contactor closed
END_VAR
VAR_OUTPUT
    NewEvent : BOOL;        // TRUE for one OB1 scan after a log entry
END_VAR
VAR
    sLastHeater : BOOL;
    sRTrig : R_TRIG;
    sCDT  : DATE_AND_TIME;
    sFbk  : INT;
    sI    : INT;
END_VAR
BEGIN
    sRTrig(CLK := HeaterInput, Q => NewEvent);
    IF NewEvent THEN
        SFC1(CDT := sCDT, RET_VAL := sFbk);
        IF sFbk <> 0 THEN
            // clock read failure; abort
            RETURN;
        END_IF;
        IF "DB_HeaterLog".cnt >= 100 THEN
            FOR sI := 1 TO 99 DO
                "DB_HeaterLog".evt[sI] := "DB_HeaterLog".evt[sI+1];
            END_FOR;
            "DB_HeaterLog".cnt := 99;
        END_IF;
        "DB_HeaterLog".cnt := "DB_HeaterLog".cnt + 1;
        "DB_HeaterLog".evt["DB_HeaterLog".cnt] := sCDT;
    END_IF;
    sLastHeater := HeaterInput;
END_FUNCTION_BLOCK

Call in OB1:

CALL FB 500 , DB 500
     HeaterInput := "DB_Heater".contactor_closed
     NewEvent    := "DB_HeaterLog".evt_pulse

Troubleshooting Matrix

Symptom Likely Root Cause Corrective Action
Two alarms per on/off transition Trigger tag is level-triggered and shares the heater bit Use R_TRIG on the heater input; raise alarms only on edge bits heater_evt_on / heater_evt_off
Run-time meter does not increment Run-time meter requires a separate instance DB and a continuous TRUE input; it does not record timestamps Replace with FB 500 logger; run-time meter is for total ON-seconds, not for discrete events
Timestamp always shows 00:00:00 1990-01-01 CPU clock not set; SFC1 returned W#16#8081 Run SFC 0 SET_CLK once from the panel or from STEP 7; verify CPU has a battery or buffered RTC
HMI shows raw hex bytes instead of date Tag declared as BYTE/WORD instead of DATE_AND_TIME, or offset mis-aligned Change tag data type to Date/Time (8 bytes); ensure even-byte DB offset
FIFO "does not write to DB" Pointer arithmetic error in STL; shift loop never executes; cnt initialized to 0 not retained Switch to the SCL version above; verify DB is non-optimized (classic S7-300/400 DB, not S7-1500 optimized DB)
Only the last 100 events visible; older lost FIFO overflow behavior — expected Increase array size to 500 or enable persistent alarm logging on the MP370 CF card
Date jumps by 1 day backwards at midnight CPU clock not synchronized; PLC loses power without battery Install/replace CPU battery; enable time sync via PROFIBUS master if available
MP370 cannot reach the S7-300 CPU Wrong MPI address or PROFIBUS termination missing Set panel MPI=2, CPU MPI=2; verify bus terminator ON at both end nodes; baudrate 1.5 Mbps

Verification and Commissioning

  1. Offline simulation: In STEP 7, run PLCSIM with the project. Force the heater bit TRUE/FALSE repeatedly and watch DB_HeaterLog.cnt increment by exactly 1 per transition. Inspect evt[i] in DB view; the date must be the PLCSIM clock date.
  2. Online panel test: On the MP370, navigate to the alarm view screen. Trigger the heater manually from the panel's own I/O area. Confirm a single "Heater ON — logged" entry and a single "Heater OFF — logged" entry per physical transition.
  3. Time-stamp sanity: Record a transition; the panel's timestamp and the PLC's DATE_AND_TIME should agree to within ±1 second (PROFIBUS acquisition latency). If the panel time diverges by minutes, the panel's internal clock has never been synchronized; enable Time Synchronization under Device Settings → Date/Time.
  4. Overflow test: Force DB_HeaterLog.cnt to 100 in STEP 7 and trigger one more event. Confirm cnt remains 100 and the array has shifted down by one slot, with the new timestamp at index 100.
  5. Power-cycle test: Power off the CPU for 5 minutes and back on. Verify the buffer contents are retained (the DB is retentive by default if configured Non-retentive: no for cnt and evt[]).

Edge Cases and Field-Proven Caveats

  • Chattering contact: A faulty contactor can produce multiple on/off transitions within a single OB1 scan. Add a debounce: only log if the new state has been stable for ≥ 200 ms. Implement with a TON timer whose ET bit gates the edge detector.
  • Clock drift on power-up: S7-300 CPUs without a battery lose the time after a power cycle of more than ~30 days (capacitor backup). Always install a fresh battery (e.g. 6ES7971-1AA00-0AA0 for CPU 31x).
  • Time zone / DST: DATE_AND_TIME has no time-zone field. If the plant operates across DST boundaries, store the raw PLC time and convert to local time on the HMI.
  • Lossy semantics of "off" event: If the PLC loses power while the heater is on, the off-event is missed. To capture this, add an OB100 startup routine that detects the contactor feedback at startup and logs an "off event" if it is unexpectedly TRUE.
  • Multi-heater extruders: For machines with 4–8 heater zones, allocate one FB_500 instance per zone and a 2-D array evt[1..8][1..100]; the index to the Alarm View on the MP370 is then driven by a zone-selection key on the panel.

Alternative Implementations

  • Pointer-based FIFO using the indirect addressing of the STEP 7 ANY-pointer is faster for very large buffers but harder to maintain; not recommended unless you have already mastered ANY-pointers.
  • S7-1500 with DTL: replace DATE_AND_TIME with DTL and SFC1 with the IEC standard RD_SYS_T; the FB is otherwise identical. See SIMATIC S7-1500 Time Functions (entry ID 109751706).
  • Direct logging to the panel CF card: configure Logging tags in WinCC flexible with the EvtArray tags set to Logging on change; the panel produces a CSV file on the CF card, no PLC-side array required. This consumes no PLC work memory but ties log retrieval to the panel.

Why does SFC1 sometimes return error W#16#8081 and what does it mean?

W#16#8081 means the CPU clock is not set or the hardware clock is defective. After a long power-off without a battery the RTC reverts to 1990-01-01 00:00:00 and SFC1 returns this error. Run SFC 0 SET_CLK once with the current date/time, install a battery, or enable PROFIBUS time-master synchronization.

Can I use a run-time meter (SFB 3 / IEC_TIM) instead of a FIFO event log?

No. Run-time meters accumulate ON-seconds for a single bit; they do not record discrete events or timestamps. Use FB 500 above when you need a list of individual transitions. Use the run-time meter only when you need a total accumulated ON-time figure for maintenance scheduling.

Why does the MP370 show two alarms per on/off transition with my original code?

Because the trigger tag was the live heater bit, which is level-triggered. The panel fires the alarm on the rising edge of the trigger and a "cleared" event on the falling edge. Replace the trigger with the edge bit produced by R_TRIG (rising) and F_TRIG (falling) so that each transition is a single-shot pulse, exactly one alarm per pulse.

How many events can I store and what happens on overflow?

The DB_HeaterLog array is dimensioned at 100 entries (800 bytes). When the buffer is full, the FB shifts all entries one slot down (FIFO eviction) and writes the new event at index 100. For longer retention, increase the array size to 500 or add MP370-side persistent alarm logging on the CF card.

Does this solution work with TIA Portal and S7-1200/S7-1500?

No. The MP370 is a classic Multi Panel and is not supported by TIA Portal. For S7-1200/1500 use a Comfort Panel (TP/MTP) or a WinCC Unified runtime, replace SFC1 with the IEC standard RD_SYS_T (DTL data type), and apply the same R_TRIG + FIFO pattern. The MP370 cannot establish a usable connection to an S7-1200/1500 controller.

Back to blog