Programming Siemens OP37 Date/Time Trigger with S7-300 SFC1

David Krause16 min read
HMI ProgrammingSiemensTutorial / 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

1. Application Overview

The Siemens OP37 operator panel is a text/graphic HMI from the OP7/OP17/OP27/OP37 family designed for S7-300 and S7-400 controllers. A common field requirement is to allow the operator to enter a future calendar date and time on the OP37 and have the controller assert a digital output (or set a bit in a data block) at the exact moment the real-time clock reaches the scheduled value. Typical use cases include batch start times, shift overrides, lighting schedules, lubrication cycles, and one-shot maintenance interlocks.

Because the OP37 communicates over MPI or PROFIBUS and exposes a fixed set of "PLC jobs" to the CPU, the cleanest implementation is to keep all of the scheduling logic inside the S7-300/400 user program. The HMI is reduced to a simple operator entry surface (four to six integer fields) and the actual comparison runs against the value returned by SFC1 (READ_CLK). This article documents the configuration of the OP37, the PLC data block layout, the SFC1 call, the BCD-to-integer conversion of the date/time fields, and the equality comparison that drives the trigger bit.

References used in this article:

2. Prerequisites

Before starting the configuration, confirm the following:

  • Controller: SIMATIC S7-300 (CPU 314/315/317) or S7-400 with firmware that exposes SFC0 and SFC1. Both system functions are part of the standard library and are available on every S7-300/400 CPU from the 314CIFM onward.
  • HMI: OP37 (6AV3 637-1LL00-0AX0 or compatible variant) with ProTool/Pro configuration software matching the panel firmware.
  • Engineering: STEP 7 V5.5 or STEP 7 Professional (TIA Portal migration is possible but the original toolchain for an OP37 is ProTool/Pro V6.x).
  • Connection: MPI cable (6XV1 830-0EH10) or PROFIBUS DP cable, terminated per Siemens guidelines, with a valid bus address for the OP37 (default 1) and the CPU (default 2).
  • Date/time data block: A shared DB (for example DB100) configured with at least 12 bytes of data: 8 bytes for the operator-entered target and 4 bytes of status.
Note on the clock source. The OP37 has its own battery-backed RTC, but the recommended architecture uses the S7 CPU as the master clock. The OP37 should be configured as a slave so the comparison logic always references a single, consistent time source. Refer to the SFC1 documentation in the Siemens Industry Online Support for the precision and resolution of the CPU clock (1-second resolution on standard S7-300, 1 ms on 318 and S7-400).

3. OP37 Date/Time Field Configuration in ProTool

Two viable data-entry strategies are available on the OP37:

  1. Discretized numeric fields. Six separate integer input fields, one each for Year, Month, Day, Hour, Minute, Second. This is the most robust method because ProTool/Pro V6 does not support the modern "Date/Time Picker" widget on the OP37 text platform.
  2. String field with PLC-side parsing. A single ASCII string field on the OP37 in which the operator types the target as YYYY-MM-DD HH:MM:SS. The PLC converts the string using FC 38 (STRING to INT/BCD) and then assembles the eight-byte DT structure. This method is more compact on screen but is fragile if the operator mistypes the delimiters.

The discretized numeric approach is recommended for field installations. Configure six input fields on a screen labeled "Schedule Next Run":

OP37 Field Variable Tag Data Type Range
Year DB100.DBW0 INT 2010 - 2089
Month DB100.DBW2 INT 1 - 12
Day DB100.DBW4 INT 1 - 31
Hour DB100.DBW6 INT 0 - 23
Minute DB100.DBW8 INT 0 - 59
Second DB100.DBW10 INT 0 - 59

In ProTool/Pro, define a new area pointer of type DB pointing at DB100 with a length of 12 bytes, then bind each field to the corresponding word offset. Set the field properties to Input, enable Limits with the minimum/maximum values above, and select the display format 9999 for year and 99 for the other fields. Tick "Apply value on ENTER" rather than "on every change"; this prevents partial entries (for example a momentary 2 for the month) from corrupting the comparison.

4. PLC Job 41 - Reading Date/Time from the OP37

The OP37 exposes a set of predefined PLC jobs to the CPU. The field report correctly identifies Job 41 as the function that requests the current date and time from the operator panel. The job is triggered by writing a specific value to a fixed interface word in the OP37 area pointer; the result is then placed by the OP37 into a configurable return area.

Mechanics of the job:

  1. The CPU writes the job number (41 decimal = 0x29) into the OP37 control word, typically at the offset defined by the area pointer Job mailbox.
  2. The OP37 receives the request, reads its internal RTC, and writes the eight-byte DATE_AND_TIME value into the configured Result mailbox area (a DB or flag range).
  3. The OP37 acknowledges by clearing the job number back to 0. The CPU can poll the job word or use a positive edge on a status bit to know the read is complete.

A typical STL sequence to trigger the read and to wait for acknowledgement:

// Trigger OP37 to read its current date/time
L 41                              // Job number 41 = read date/time
T MW 200                          // Job mailbox area pointer

// Wait for OP37 to clear the job word (acknowledgement)
WAIT: L MW 200
     L 0
     <>I
     JC WAIT                       // Spin until OP37 finishes

// Result is now in DB101 (8 bytes, DT format)

The exact area pointer offsets are defined in the ProTool project under Area Pointers > Job Mailbox and Area Pointers > Result Mailbox; record the offsets you use and replace the MW 200 and DB101 references in the example above accordingly. The detailed step-by-step setup of the job mailbox is documented in the ProTool/Pro V6 manual chapter on communication between the panel and the PLC.

5. SFC1 READ_CLK - Reading the CPU Real-Time Clock

The PLC job in step 4 is only useful when you also want to display the panel clock or synchronize it. The actual scheduling comparison must run against the CPU clock, which is read with SFC1 (READ_CLK). The function fills an eight-byte buffer of type DATE_AND_TIME (DT) at the destination pointer supplied as the CDT input.

Parameter Declaration Type Description
RET_VAL OUTPUT INT Error code (0 = no error). See SFC1 help for the W#16#80xx codes.
CDT OUTPUT DATE_AND_TIME 8 bytes; current CPU date and time in BCD format.

STL call against a temporary variable stored in DB1:

CALL SFC1
     RET_VAL := MW 0
     CDT     := DB1.DBD 0      // Bytes 0..7 of DB1 hold the DT

The eight bytes returned are encoded in BCD according to the IEC 61131-3 DATE_AND_TIME layout:

Offset Content Range (BCD) Encoded Value
Byte 0 Year (decade in high nibble, year within decade in low nibble) 90..89 (= 1990..2089) B#16#10 = 2010
Byte 1 Month 01..12 B#16#12 = December
Byte 2 Day 01..31 B#16#08 = 8th
Byte 3 Hour 00..23 B#16#06 = 06:00
Byte 4 Minute 00..59 B#16#00
Byte 5 Second 00..59 B#16#00
Bytes 6-7 Milliseconds (3 1/2 BCD digits) and day of week (1=Sun..7=Sat) in bits 0-3 of byte 7 000..999, 1..7 varied
Note. The OP37 stores the year in two-digit BCD only, so any value above 2089 wraps. Validate the input range in ProTool/Pro (1990..2089) to avoid silent wrap-around.

6. SFC0 SET_CLK - Optional Master/Slave Clock Selection

If the S7 CPU is to act as a master clock for the OP37, call SFC0 (SET_CLK) in OB1 to write the current time back to the panel via a periodic PLC job. The function signature is:

CALL SFC0
     RET_VAL := MW 2
     PDT     := DB1.DBD 0      // Source DT to push to the panel

RET_VAL codes for SFC0 are listed in the SFC0 documentation. The two most common values are W#16#0000 (success) and W#16#8081 (invalid date/time, typically an out-of-range month or day-of-month). Always evaluate the RET_VAL and latch a fault in the status DB if a write fails - an unsynchronized panel that drifts is a common root cause of "the schedule did not fire" complaints.

7. Converting the DT Structure to Comparable Integers

The SFC1 result is in BCD while the OP37 inputs are typically in decimal INT. Two strategies are available:

7.1 Strategy A - BCD-to-INT using standard library FC 21 (BCD_I)

STEP 7 provides a small library of BCD/INT conversion blocks. The relevant block is FC 21 (BCD_I) in the Standard Library > TI-S7 Converting Blocks. It accepts a BCD word and returns an INT.

// Convert each BCD byte of the DT to INT
CALL FC 21
     BCD   := DB1.DBB 0          // Year decade nibble is in B#16#10 (year 2010)
     RET_VAL := MW 10           // Integer year (2010)

CALL FC 21
     BCD   := DB1.DBB 1
     RET_VAL := MW 12           // Integer month

CALL FC 21
     BCD   := DB1.DBB 2
     RET_VAL := MW 14           // Integer day

CALL FC 21
     BCD   := DB1.DBB 3
     RET_VAL := MW 16           // Integer hour

CALL FC 21
     BCD   := DB1.DBB 4
     RET_VAL := MW 18           // Integer minute

CALL FC 21
     BCD   := DB1.DBB 5
     RET_VAL := MW 20           // Integer second

Caveat: FC 21 expects a full 16-bit BCD word, but the DT layout provides only a single byte for the year decade plus a partially-used byte for the milliseconds. For the year byte (DB1.DBB 0), the high nibble holds the decade and the low nibble holds the year within the decade. Build a temporary BCD word by shifting and combining, for example:

L DB1.DBB 0          // Load year decade/year (e.g. B#16#10 = 2010)
SLW 4                // Shift left 4 bits to align with FC21 word format
T MW 30              // Temporary BCD word

CALL FC 21
     BCD   := MW 30
     RET_VAL := MW 10           // Integer year 2010

Month, day, hour, minute and second are direct single-byte BCD values; they can be converted by loading them into a word that has been pre-filled with zeros in the upper byte (the SFC1 storage guarantees zero in the unused half of the BCD word for these fields).

7.2 Strategy B - Direct byte-wise comparison

If you do not need the integer values for any other purpose (display, arithmetic, logging), the fastest comparison is a direct byte-wise compare of the OP37-supplied BCD with the SFC1-supplied BCD. To do this, store the OP37 inputs in BCD format rather than decimal INT. The ProTool/Pro field property Display format > BCD exists for precisely this reason, and the conversion in the PLC is then a single ==B per field.

L DB100.DBB 0        // OP37-supplied year (BCD, input by the operator)
L DB1.DBB 0          // SFC1 year (BCD, current)
==B
= M 50.0             // Year match

8. Comparison Logic and Trigger Bit

The trigger bit is set when all six fields match. Using a bitwise AND of the individual matches prevents a spurious assertion if, for example, the year and month match but the day differs.

// Individual matches (each is the result of a ==B or ==I compare)
U M 50.0             // Year
U M 50.1             // Month
U M 50.2             // Day
U M 50.3             // Hour
U M 50.4             // Minute
U M 50.5             // Second

= DB100.DBX 20.0     // "Schedule reached" trigger bit

// One-shot edge - fires for exactly one OB1 scan
UN M 51.0            // Previous-cycle state
U DB100.DBX 20.0
= M 51.0             // Latch for next cycle
S DB100.DBX 20.1     // Rising-edge pulse

For a sustained output (for example, a relay that must stay on for the entire minute), replace the one-shot with a self-latching coil that is reset by the operator with a second OP37 button.

Edge case - the leap second. SFC1 has a one-second resolution on most S7-300 CPUs. The OB1 scan time is typically 20-50 ms, so the equality check has a comfortable window. If your machine runs at very high scan rate and you observe a missed trigger, insert a tolerance of ±1 second by OR-ing the match against (second == target-1) AND (minute already advanced) for the second-only case.

9. Complete STL Implementation in OB1

The following is a working snippet that ties the OP37 inputs, SFC1 read, BCD conversion, and trigger logic into a single OB1 block. Paste it into a new STL source and connect to a CPU 315-2 DP for live testing.

// =========================================================
//  OB1 - Schedule trigger for OP37-entered date/time
//  Author : Field Engineering Notes
//  Tested : CPU 315-2 DP / Firmware V3.3 / STEP 7 V5.5
// =========================================================

// --- 1. Read CPU clock ----------------------------------
CALL SFC1
     RET_VAL := MW    0
     CDT     := DB1.DBD 0

// --- 2. Convert BCD to INT ------------------------------
// Year
L   DB1.DBB 0        // BCD year byte
SLW 4                // Align to FC21 input format
T   MW    30
CALL FC 21
     BCD     := MW    30
     RET_VAL := MW   10   // Year as INT (1990..2089)

// Month
L   B#16#0
L   DB1.DBB 1
OW
T   MW    32
CALL FC 21
     BCD     := MW    32
     RET_VAL := MW   12   // Month as INT

// Day
L   B#16#0
L   DB1.DBB 2
OW
T   MW    34
CALL FC 21
     BCD     := MW    34
     RET_VAL := MW   14   // Day as INT

// Hour
L   B#16#0
L   DB1.DBB 3
OW
T   MW    36
CALL FC 21
     BCD     := MW    36
     RET_VAL := MW   16   // Hour as INT

// Minute
L   B#16#0
L   DB1.DBB 4
OW
T   MW    38
CALL FC 21
     BCD     := MW    38
     RET_VAL := MW   18   // Minute as INT

// Second
L   B#16#0
L   DB1.DBB 5
OW
T   MW    40
CALL FC 21
     BCD     := MW    40
     RET_VAL := MW   20   // Second as INT

// --- 3. Compare against OP37 targets --------------------
L   MW   10
L   DB100.DBW 0          // OP37 year (INT, from ProTool field)
==I
=   M  50.0

L   MW   12
L   DB100.DBW 2          // OP37 month
==I
=   M  50.1

L   MW   14
L   DB100.DBW 4          // OP37 day
==I
=   M  50.2

L   MW   16
L   DB100.DBW 6          // OP37 hour
==I
=   M  50.3

L   MW   18
L   DB100.DBW 8          // OP37 minute
==I
=   M  50.4

L   MW   20
L   DB100.DBW 10         // OP37 second
==I
=   M  50.5

// --- 4. Aggregate and edge-detect -----------------------
U   M  50.0
U   M  50.1
U   M  50.2
U   M  50.3
U   M  50.4
U   M  50.5
=   DB100.DBX 20.0       // "Schedule reached" static flag

UN  M  51.0              // Previous-cycle memory
U   DB100.DBX 20.0
S   DB100.DBX 20.1       // One-shot pulse

U   DB100.DBX 20.0
=   M  51.0              // Latch for next cycle

BE

10. Verification and Commissioning

  1. Download and go online. In STEP 7, select PLC > Download, then PLC > Monitor/Modify. Open DB1 and confirm the eight bytes at offset 0 are updating once per OB1 cycle with the current date/time in BCD.
  2. Cross-check against the panel. On the OP37, navigate to the System > Date/Time screen. The displayed values should match DB1 within one second.
  3. Force a near-term schedule. On the OP37, enter a target 60 seconds in the future and confirm via the monitor that the inputs in DB100 update. The trigger flag at DB100.DBX20.0 should rise exactly when the CPU clock crosses the target, and the one-shot pulse at DBX20.1 should be a single OB1 scan wide.
  4. Wire the trigger to a real output. In the project, place a coil on DB100.DBX20.0 driving a digital output module. For safety, put the bit through a normally-closed hardware enable in the field wiring.
  5. Document and back up. Use the Save as function in ProTool/Pro and STEP 7 to commit the project; store the .s7p, the .pdb, and the area-pointer table in the machine's documentation folder.

11. Troubleshooting Matrix

Symptom Likely Root Cause Diagnostic Corrective Action
OP37 displays "—" or "###" for input fields Area pointer not connected, or DB100 missing in the S7 project In ProTool/Pro, open Area Pointers and confirm the DB and length; in STEP 7 confirm DB100 exists with the configured length Recompile the ProTool project, re-download, and power-cycle the OP37
Trigger never asserts SFC1 not called in OB1 (no cyclic read) or RET_VAL nonzero Online > Monitor DB1: byte 0 should be the current year in BCD Add CALL SFC1 in OB1; evaluate MW0 and clear any SFC1 error
Trigger fires on the wrong day OP37 field configured as decimal INT but compared in BCD, or vice versa Use Monitor/Modify to inspect both DB100 and DB1; check the FC21 conversions Standardize on one encoding (INT recommended for the OP37 inputs)
Trigger fires continuously once the schedule is reached Missing one-shot edge detection Trace M51.0; the rising-edge pulse should be a single scan Add the UN M51.0 / U DB100.DBX20.0 / S DBX20.1 sequence from section 9
Time on OP37 drifts from the CPU clock Panel configured as master clock and never resynced Check whether PLC Job 0 (date/time) is being driven by the CPU Switch the OP37 to slave mode and add a periodic SFC0 write from the CPU
SFC0 returns W#16#8081 Invalid date (e.g. Feb 30) fed from a corrupt OP37 string Inspect the source DT bytes; check day > days_in_month Validate the OP37 inputs in ProTool/Pro with the limit tables from section 3
SFC1 returns W#16#80A1 CPU in STOP, or clock not yet synchronized after power-up Check CPU status LED and the diagnostic buffer Wait for the clock battery-backed time to be valid; restart the CPU
Year wraps from 2089 to 1990 unexpectedly BCD storage is two-digit; year value entered as 2090+ Read DB1.DBB0 and check the BCD value Clamp the input range in ProTool to 1990-2089

12. Frequently Asked Questions

Does SFC1 have a one-second resolution on every S7-300 CPU?

The standard S7-300 CPUs (314, 315, 316, 317) return a one-second resolution from SFC1. The 318-2 and all S7-400 CPUs support one-millisecond resolution. If the application requires sub-second scheduling, migrate to a 318-2 or an S7-400.

What is the difference between PLC Job 40 and Job 41 on the OP37?

Job 40 writes the CPU date/time into the panel (set panel clock), and Job 41 reads the panel date/time back into the CPU. The exact job numbers and area-pointer offsets are listed in the OP37 Equipment Manual at Siemens Support entry 1408288.

Can I store the target schedule in a DATE_AND_TIME tag on the OP37?

The OP37 does not expose a true DT picker. Use six discrete integer fields (Year, Month, Day, Hour, Minute, Second) with limit validation. For string-based entry, parse the string on the PLC side using FC 38 from the IEC library.

How do I make the trigger fire for an entire minute rather than a single second?

Replace the one-shot pulse with a self-holding coil. Set the coil on the matching condition and reset it when (a) the operator presses a Reset button on the OP37, or (b) the current minute exceeds the scheduled minute.

What happens if the CPU clock is not yet valid when the OP37 starts up?

SFC1 returns RET_VAL = W#16#80A1 and the CDT buffer is left unchanged. In the user program, gate the comparison logic on a valid clock flag (for example, set the flag the first time RET_VAL = 0) to avoid a spurious trigger at the all-zero initial state.

Back to blog