S7-200 DCF77 Time Sync and Weekly Scheduler Implementation

David Krause17 min read
S7-200SiemensTutorial / 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 S7-200 family does not ship with a built-in radio-clock decoder, a weekly timer function block, or a dedicated astronomical-time instruction. Anything beyond a one-shot TON/TOF pair must be built by the programmer. This article covers two related tasks on a CPU 224 (typical order number 6ES7 214-1BD23-0XB0, also valid for 221/222/224XP/226):

  1. Decoding a 24 V DC level from an external DCF77 receiver into a 59-bit minute frame and using it to overwrite the PLC's real-time clock (RTC) with SET_RTC.
  2. Using READ_RTC plus a 7-day schedule table in V-memory to drive an output between arbitrary on/off times (for example, "energize Q0.0 Monday through Friday from 10:00 to 10:15"), with optional date-specific overrides for holidays.

The approach uses only standard S7-200 instructions: BGN_ITIME/CAL_ITIME for interval timing, SHRB for the bit table, READ_RTC/SET_RTC for the clock, and a small scheduler subroutine driven from the main scan or from a timed interrupt attached to SMB34.

2. Prerequisites

Item Specification
CPU S7-200 CPU 224 (or 221/222/224XP/226), 24 V DC powered
Firmware CPU 224 REL 02.01 or later recommended for SHRB/BCD performance
Programming tool STEP 7 Micro/WIN V4.0 SP9 (final release for the S7-200 line)
PC interface USB-PPI cable (6ES7 901-3DB30-0XA0) or RS-232 PPI Multi-Master cable
Receiver DCF77 module with 24 V DC logic output, optocoupled, e.g. ELV DCF-77-Empfangsmodul or Reichelt MOD-TC
Free inputs 1 digital input (I0.0-I0.7 high-speed capable) plus 1 output for the scheduled load
Memory budget ~3 KB program, ~1 KB V-memory for frame + 7-day table
Power-quality note: Most third-party DCF77 receivers draw a peak antenna current of ~1-2 mA and tolerate 5-15 V. A 24 V PLC input expects a 13-30 V high level. Use a receiver module with a 24 V open-collector or push-pull output, or add a simple voltage divider + Schmitt trigger (e.g., 74HC14) between 5 V receiver and PLC input.

3. DCF77 Frame Architecture and Bit Map

DCF77 is a 77.5 kHz amplitude-modulated long-wave signal broadcast by Deutsche Funkturm on behalf of the Physikalisch-Technische Bundesanstalt (PTB) from Mainflingen, Germany. Each minute is encoded as 59 amplitude-keyed 1-second intervals. The carrier is reduced by ~25% during the first 100 ms (logical 0) or 200 ms (logical 1) of every second; the remaining 800/700 ms is full carrier. The 60th second carries no reduction, which the decoder uses to detect a clean start-of-minute.

DCF77 59-Bit Minute Frame 0 M 1..14 Reserved 15 R Ant. call 16 A1 DST warn 17..24 P1 25..35 P2 36..58 Bit 59 = start-of-minute marker (no amplitude reduction, 2 s of full carrier) Pulse 0 (bit=0): 100 ms reduction, 900 ms full | Pulse 1 (bit=1): 200 ms reduction, 800 ms full BCD encoding for minute (25..30), hour (36..41), day (42..44 + 45..49), month (50..53), year (54..58)

Encoding rules:

  • Bits 0-14: miscellaneous (minute marker, civil warning bits, transmitter ID).
  • Bit 15: call bit (antenna change-over), normally 0.
  • Bit 16: A1 = announcement of upcoming DST change.
  • Bits 17-24: minutes tens/ones (BCD, bits 21-24 unused/zero), P1 = even parity of bits 17-24.
  • Bits 25-35: hours tens/ones (BCD, bits 29-35 unused/zero), P2 = even parity of bits 25-35.
  • Bits 36-58: day-of-week (3 bits), day tens/ones (BCD, 6 bits), month tens/ones (BCD, 5 bits), year tens/ones (BCD, 8 bits), P3 = even parity of bits 36-58.
  • Bit 59 is the start-of-minute separator (no pulse); the decoder uses the 2 s carrier gap to resynchronize.
Ambiguity check: The bit map above is the PTB-published layout. Some hobbyist modules invert the logic (carrier-present = 1) or report the parity on a different span. The decoder below assumes PTB layout; if you validate against a known module, confirm with the receiver datasheet before committing.

4. Receiver Wiring and Signal Conditioning

DCF77 Receiver to S7-200 Input Wiring DCF77Receiver5-15 VDC Level Shift+ Schmitt74HC14 S7-200CPU 224I0.0 input DATA 24 V pulse Common 0 V return between receiver, level shifter, and PLC M terminal

Pin assignments for a CPU 224 with the standard 35 mm DIN-mounted terminal block:

CPU 224 terminal Signal Connection
1M 0 V reference for inputs 0.0-0.7 Common to receiver GND and 24 V PSU 0 V
I0.0 DCF77 data Open-collector output of level shifter (use I0.0 for HSC compatibility if you later switch to interrupt-driven measurement)
I0.1 Status / lost-signal Optional: RSSI or power-good from receiver
L+ / M 24 V sensor supply 24 V DC for the receiver board if it requires it
1L 24 V for inputs 0.0-0.7 Common +24 V (use the same PSU feeding the PLC inputs)

For CPU 224, inputs 0.0-0.7 are type-1 24 V inputs. A 13-30 V level reads as "1", a -5 to +5 V level reads as "0". The level shifter must therefore convert the receiver's 5 V (or 3.3 V) logic into a 24 V signal that swings clean above 13 V during the carrier-reduction (or non-reduction) window. A simple 74HC14 hex inverter with a pull-up to 24 V and a 2N2222 open-collector driver is a proven arrangement.

5. Pulse Width Measurement in Micro/WIN

Two implementation paths are practical on the S7-200:

  1. Cyclic scan with BGN_ITIME / CAL_ITIME: simplest, runs in the main OB1. Effective up to about 5-10 ms scan time before pulse-edge resolution suffers. For DCF77 (1 Hz nominal) this is more than enough.
  2. Timed interrupt on SMB34 (1-255 ms): recommended if your scan time exceeds 50 ms or if you have other heavy logic. Sample the input at a fixed 10 ms cadence and reconstruct the high/low interval from the sample count.

The subroutine below measures the width of the active-high pulse on I0.0 and classifies it as bit 0 (100 ms) or bit 1 (200 ms). The third case, an interval greater than 1.5 s with no edge, signals the start-of-minute marker.

// Subroutine SBR_0: DCF77 pulse width to bit
// Inputs : I0.0 (DCF77 data, level = carrier present)
// Outputs: V100.0 (bit value 0 or 1), V102 (pulse width ms)
// Globals: VB101 = sample counter, VW103 = last edge timestamp

NETWORK 1    // Detect rising edge of I0.0
LD     I0.0
EU
CALL   SBR_MarkEdge    // store current 10 ms tick count in VW103

NETWORK 2    // Detect falling edge
LD     I0.0
ED
CALL   SBR_Classify    // VW103 -> pulse width VW104

NETWORK 3    // Classify pulse width: 0 if < 150 ms, 1 if 150-300 ms
LDW>=  VW104, 150
AW<   VW104, 300
S      V100.0, 1        // bit = 1

NETWORK 4
LDW<   VW104, 150
R      V100.0, 1        // bit = 0

NETWORK 5    // Start-of-minute: no edge for > 1500 ms
LDW>=  VW106, 1500      // VW106 = ms since last falling edge
S      M0.1, 1           // M0.1 = SOM (start of minute flag)

Tune the 150/300 ms thresholds empirically. PTB specifications allow ±10 ms jitter, so 100-150 ms maps to logical 0 and 180-300 ms maps to logical 1. Anything outside 100-300 ms should be discarded as noise rather than committed to the bit table.

6. Building the 59-Bit Frame Table

Allocate a 60-bit shift register in V-memory starting at V200.0. Use SHRB with a positive count of +59 so each new bit shifts toward the high-order end and bit 58 lands in V207.4 (V200 = bits 0-7, V201 = bits 8-15, ..., V207 = bits 56-59).

// SBR_Frame: shift one classified bit into the 59-bit table on every SOM
NETWORK 1    // Load V100.0 into the SHRB DATA input on every falling edge
LD     I0.0
ED
SHRB   V100.0, V200.0, +59   // shift in 1 bit, oldest bit at V200.0

NETWORK 2    // On start-of-minute, freeze the table for decoding
LD     M0.1            // SOM flag set in pulse-width section
EU
MOVB   59, VB210       // bit counter starts at 59
S      M0.2, 1         // M0.2 = decode enable

The bit map V200.0-V207.4 now holds one complete minute frame. Bit 0 (M = minute marker) is at V200.0; bit 58 (year ones) is at V207.2; bit 59 (always 0) is the implicit SOM separator. Note that the SHRB index for bit n is V(200 + n/8).bit(n%8).

7. Decoding Time and Date from BCD

The minute, hour, day-of-week, day, month, and year fields are BCD-packed across the relevant spans. The decoder below pulls each field into a byte, validates the digit ranges, and stores them in a temporary RTC image starting at VB220.

// SBR_Decode: run when M0.2 is set, freeze frame in V200.0..V207.4
NETWORK 1    // Minutes tens/ones (bits 17..24, valid bits 17..20 = tens, 21..24 = ones)
LD     M0.2
EU
CALL   SBR_BCD        // inputs: VW200 offset, returns byte in VB220
              // minute_tens = BCD(bit 17..19) ; minute_ones = BCD(bit 20..23)
MOVB   VB220, VB221   // minute byte
Field Bit span BCD layout (MSB..LSB) Decode result Byte address
Minute tens 17-19 0 0 0 d2 d1 d0 0 0 0-5 VB221 (high nibble)
Minute ones 20-23 d3 d2 d1 d0 0 0 0 0 0-9 VB221 (low nibble)
Hour tens 25-26 0 0 0 0 0 0 d2 d1 0-2 VB222 (high nibble)
Hour ones 27-28 d3 d2 d1 d0 0 0 0 0 0-9 VB222 (low nibble)
Day-of-week 29-31 0 0 0 0 0 d2 d1 d0 1-7 VB223 (low nibble)
Day tens 32-33 0 0 0 0 0 0 d2 d1 0-3 VB224 (high nibble)
Day ones 34-37 d3 d2 d1 d0 0 0 0 0 0-9 VB224 (low nibble)
Month tens 38-39 0 0 0 0 0 0 0 d1 0-1 VB225 (high nibble)
Month ones 40-43 d3 d2 d1 d0 0 0 0 0 0-9 VB225 (low nibble)
Year tens 44-47 0 0 0 0 0 0 d2 d1 0-9 VB226 (high nibble)
Year ones 48-51 d3 d2 d1 d0 0 0 0 0 0-9 VB226 (low nibble)

A practical decoder uses a small lookup table in a data block rather than 50+ ladder rungs. The block holds a precomputed 256-byte BCD-to-binary conversion or, more compactly, an 11-entry array mapping each 4-bit nibble to its binary value 0-9. Anything above 9 (illegal BCD) is rejected as a frame error and the new RTC write is suppressed for that minute.

8. Parity and Validation

Three even-parity bits protect the three spans. Implement parity with a simple XOR reduction over the bit range:

// Parity check (even parity: XOR of all data bits plus parity bit = 0)
NETWORK 1    // P1: bits 17..24, even parity
LD     M0.2
EU
CALL   SBR_Parity    // computes XOR of V(200+floor(n/8)).bit(n%8) for n=17..24
              // returns 0 in VB230 if parity is even, 1 if odd
AB=    VB230, 0
S      M0.3, 1       // P1 OK
Span Bit range Parity bit Even parity test
P1 (minutes) 17-24 (incl. parity bit 24) V203.0 XOR(V200.b2..V203.b0) = 0
P2 (hours) 25-35 (incl. parity bit 35) V204.3 XOR(V203.b1..V204.b3) = 0
P3 (date) 36-58 (incl. parity bit 58) V207.2 XOR(V204.b4..V207.b2) = 0
Frame rejection policy: If any of P1, P2, P3 fails, or any BCD nibble exceeds 9, drop the frame and let the PLC RTC keep the previous value. Do not partially update. A receiver in fringe reception will produce a few bad frames per hour; rejecting bad frames is more important than continuously updating.

9. Writing the S7-200 Real-Time Clock

On a clean frame (parity OK, BCD OK, day-of-week in 1-7, day in 1-31, month in 1-12), call SET_RTC with the decoded fields. The S7-200 RTC format expected by SET_RTC is a T-format byte: T followed by year, month, day, hour, minute, second, and a reserved zero byte (8 bytes total).

// SBR_SetRTC: write decoded time to PLC
NETWORK 1    // All three parity flags set?
LD     M0.3       // P1 OK
A      M0.4       // P2 OK
A      M0.5       // P3 OK
A      M0.6       // BCD OK
CALL   SBR_PackT  // build T-format buffer at VB250..VB257
SET_RTC VB250      // overwrite S7-200 RTC with decoded time

Important behaviors of SET_RTC on CPU 224:

  • Writes are applied within one PLC scan; the new value is readable with READ_RTC on the next scan.
  • The buffered clock accuracy is typically ±2 min/month at 25 °C, drifting to ±5 min/month at 0-55 °C. With DCF77 sync, the PLC will only accumulate at most a few minutes of drift between good frames.
  • Day-of-week 1 = Sunday in DCF77; S7-200 internal READ_RTC also returns 1 = Sunday, so the value passes through unchanged.

10. Weekly Schedule Data Block

Place a 7-day schedule in a data block (DB1). Each day holds up to 8 on/off pairs. A pair is two bytes: on-time (HH:MM packed as 0xHHMM) and off-time (same format). The block also carries an enable mask, so any day can be globally disabled without erasing the entries.

DB1 offset Symbol Type Description
VB0 SchedEnable BYTE Bit mask: b0=Sun, b1=Mon, ... b6=Sat. 1 = schedule active.
VB1..VB8 SunOn1..SunOff4 WORD x8 4 on/off pairs for Sunday
VB17..VB24 MonOn1..MonOff4 WORD x8 4 on/off pairs for Monday
... ... ... ...
VB57..VB64 SatOn1..SatOff4 WORD x8 4 on/off pairs for Saturday

For a schedule of "Monday through Friday, 10:00 to 10:15", set:

// DB1 initial values (Micro/WIN data block editor)
SchedEnable = 0x3E        // b1..b5 set: Mon..Fri
MonOn1   = 16#0A00        // 10:00
MonOff1  = 16#0A15        // 10:15
TueOn1   = 16#0A00
TueOff1  = 16#0A15
WedOn1   = 16#0A00
WedOff1  = 16#0A15
ThuOn1   = 16#0A00
ThuOff1  = 16#0A15
FriOn1   = 16#0A00
FriOff1  = 16#0A15

11. Date-Specific Schedule Override

To handle "every Monday, except holidays", reserve a second data block (DB2) for exception dates. The PLC reads the current day/month from READ_RTC, scans DB2 for a match, and if found uses the override schedule (or forces the output off for that day).

// SBR_Sched: main weekly scheduler, called once per minute from OB1
NETWORK 1    // Read current RTC into VW300..VW307
READ_RTC VW300          // T-format buffer: year, month, day, hour, min, sec, reserved
DB2 offset Symbol Type Description
VB0 NumExceptions BYTE 0-50 exceptions supported
VB1..VB100 ExDate[1..50] WORD x50 High byte = month, low byte = day
VB101..VB200 ExMode[1..50] BYTE x50 0 = force OFF, 1 = force ON, 2 = use alternate pair

The weekly scheduler evaluates DB1 first, then checks DB2 for a same-month-day match. An exception with mode 0 or 1 overrides the weekly result; mode 2 reads an alternate on/off pair from DB3.

12. STEP 7 Micro/WIN on Windows 10/11

Micro/WIN V4.0 SP9 is the final release for the S7-200 line and was developed against Windows XP/7. On Windows 10 and Windows 11 several symptoms are common: F1 (context help) opens a blank window or returns "Help not found"; the programming software occasionally loses the PPI port after sleep; and large project uploads may fail on first attempt.

Workarounds that do not require an additional tool:

  1. Install Micro/WIN to a non-default path (for example C:\S7200\) so that the help file path is short enough to register cleanly with the Windows help engine.
  2. Launch Micro/WIN as administrator; this restores the F1 lookup into the local .chm file. Windows 10/11 block .chm content from UNC paths or from paths under Program Files without elevation.
  3. Set the launch compatibility to Windows 7 via the executable's Properties > Compatibility tab.
  4. If F1 still fails, use the bundled readme.chm directly: it contains the same instruction reference as the F1 lookup but is opened by Explorer and bypasses the broken help-engine integration.
Long-term note: The S7-200 family is in the Siemens product phase-out lifecycle. For new designs Siemens points users to the S7-200 SMART. The SMART uses a different instruction set and a different programming tool (Micro/WIN SMART), so a DCF77 decoder written for the S7-200 will not compile on the SMART. Treat the code below as legacy-architecture material.

13. Commissioning Procedure

  1. Connect the receiver antenna away from switch-mode PSUs, VFDs, and fluorescent lamps. Aim for a clear line-of-sight to Frankfurt (Mainflingen) and at least 1-2 m of separation from any 24 V cable run.
  2. Power up and verify the receiver LED blinks once per second. A clean blink = carrier present, no blink = carrier reduced (data 0 or 1) and a 2 s gap = start of minute.
  3. Download the project to the CPU 224. Place a breakpoint or single-step on the falling-edge network in SBR_0 and confirm VW104 cycles through 100 and 200 within ±20 ms of the receiver LED.
  4. Force M0.0 to enable decoding. Use a status table to monitor VB200..VB207: the bits should populate from the SOM marker (bit 0) upward to bit 58 over 59 seconds.
  5. Use a watch table to call SBR_Decode and inspect VB220..VB226. Cross-check with a phone app that displays DCF77 frame decode live.
  6. Confirm the three parity bits on three consecutive minutes. If parity is intermittently wrong, increase the 10 ms interrupt to 5 ms to improve edge resolution, or add a 200 ms blanking window after each edge to reject switch-bounce artefacts.
  7. Force a known good frame and confirm SET_RTC updates the PLC clock. Power-cycle the PLC and confirm the clock retains the time (CPU 224 has a super-cap-backed RTC that holds for ~100 hours at 25 °C).
  8. Activate the scheduler, set DB1 to a 1-minute test window ("fire the output for 60 seconds starting now"), and verify Q0.0 energizes at the second mark and drops at the off-time mark.
  9. Run for 24 hours and log parity failures. A clean DCF77 signal at good reception should produce fewer than 2 bad frames per 24 hours.

14. Troubleshooting Matrix

Symptom Likely root cause Diagnostic Fix
VB104 always zero; no pulses decoded Wiring polarity; level shifter inverting the wrong way; input 1M not tied to PSU 0 V Watch I0.0 in status table; LED on input module Re-wire; add 10 kΩ pull-up to 24 V on I0.0; verify 1M is on 0 V
VB104 always one constant (e.g., 1000) SBR_MarkEdge never called; rising-edge detector not firing Force a rising edge manually in Micro/WIN Replace EU with a one-shot built from a flip-flop; check scan time < 50 ms
Pulse widths jitter 80-250 ms on every cycle Receiver picking up noise; antenna misaligned Place a scope on the open-collector output Re-orient antenna; add 100 nF across receiver supply; use shielded cable
Parity always fails on P1 only Bit ordering reversed in SHRB; counted from wrong end Inspect V200.0..V200.7 in status table Confirm SHRB count polarity and start bit; reverse the table if bit 0 is at the MSB
Hour always reads 0-3 even on successful frames BCD decoder pulling wrong nibble; hour tens is on bits 25-26, not 27-28 Compare decoded value to a reference decoder Re-issue bit-map; document the exact 4 bits that carry hour tens
SET_RTC applies the wrong day-of-week Day-of-week bit span (29-31) misinterpreted as a BCD nibble Inspect VB223 (should be 1-7, not 0-6) Convert binary (not BCD) for the day-of-week field; remember 1 = Sunday
Scheduler output Q0.0 never energizes SchedEnable mask is 0; day-of-week from READ_RTC does not match DB1 row index Watch VB300 and DB1 in a status table Set SchedEnable to 0x7F for first test; verify byte alignment of DB1 entries
Scheduler output stays on across midnight On-time > Off-time causes the inequality to be true for the entire 24 h span Force an on/off pair where on > off Swap on/off if the intent is a wrap-around window; or split into two pairs
F1 help does not open Windows 10/11 blocks .chm registration under Program Files Try F1 after right-click > Run as administrator Reinstall to C:\S7200\; run as administrator; open readme.chm directly
RTC drifts more than 1 s per hour CPU super-cap exhausted (typical after > 5 years unpowered) Power down for 5 minutes, power up, check time Replace the super-cap on the CPU board, or move to DCF77-only operation with no RTC retention

Does the S7-200 have a built-in weekly timer instruction?

No. The S7-200 has no native weekly scheduler. Implement it as a data block in V-memory holding on/off pairs per day, plus a routine that calls READ_RTC and compares the current day-of-week, hour, and minute against the active entries. The pattern in Section 10 fits in roughly 1 KB of program memory on a CPU 224.

What is the minimum DCF77 receiver I can wire to a CPU 224?

A module with an open-collector or push-pull output that swings to the receiver's logic level (5 V or 3.3 V typical), plus a level shifter (74HC14 + 2N2222) to present a clean 24 V signal to I0.0. Tie 1M to the 24 V PSU 0 V return, and add a 100 nF decoupling cap across the receiver supply to reject conducted noise.

How accurate will the PLC clock be after DCF77 sync?

Inside reception range the S7-200 RTC tracks DCF77 to within one frame (1 minute). A clean signal produces fewer than 2 bad frames per 24 hours, so the PLC is effectively free-running against the broadcast for at most 1-2 minutes between good syncs. The S7-200 internal RTC itself drifts ±2 min/month at 25 °C, so DCF77 overrides that drift several times per hour.

Why does F1 help not work on Windows 10 or 11?

Micro/WIN V4.0 SP9 uses the Windows .chm help engine, which Windows 10 and Windows 11 block from Program Files and from UNC paths without elevation. Install Micro/WIN to a short path such as C:\S7200\ and launch it as administrator, or open readme.chm from the install directory directly via Explorer.

Can the same project be reused on a S7-200 SMART?

No. The S7-200 SMART uses a different instruction set, different memory map, and the Micro/WIN SMART programming tool. The DCF77 decoder, weekly scheduler, and exception table must be rewritten against the SMART's LAD/FBD/ST editor and the SMART's READ_RTC/SET_RTC equivalents. The hardware-receiver wiring and the 24 V level shifter carry over unchanged.

Back to blog