Implementing 7, 8, and 30-Day Timers on Siemens S7-300 PLCs

David Krause20 min read
S7-300SiemensTutorial / 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

Implementing 7-, 8-, and 30-Day Timers on Siemens S7-300 CPU315-2PN/DP

Long-duration timing requirements are routine in water/wastewater, HVAC, and process plants. A pump that must rotate duties every 30 days, a filter that must backwash 7 days after a high-high level event, or a sterilisation cycle that triggers 8 days after a tank fill all push past the practical limits of any single IEC timer block. This reference covers three production-grade implementations for the S7-300 platform running STEP 7 V5.x (SIMATIC Manager) on a CPU 315-2PN/DP (6ES7 315-2EH14-0AB0 or compatible firmware), explains why the typical first attempts fail, and shows the commissioning checks that prove the design before deployment.

Problem Definition

The target application is a small pumping station controlled by a CPU 315-2PN/DP. Three timing requirements must be met simultaneously, each with independent trigger, reset, and action:

Function Trigger Preset Action on expiry Reset source
Pump duty rotation Pump-1 motor contactor closed 30 days (720 h) Stop Pump-1, start Pump-2 Pump-2 confirmed running
Process-1 auto-start Tank level = LHH (high-high) 7 days (168 h) Start Process-1 (e.g., transfer pump) Operator acknowledge
Process-2 auto-start Tank level = LHH (high-high) 8 days (192 h) Start Process-2 (e.g., backwash) Operator acknowledge

All three timers must operate independently, must be resettable on command from the HMI, and must optionally survive a CPU STOP/RUN transition or loss of power without losing their accumulated value. The first two requirements drive the code structure; the third determines whether the values live in retentive M-markers or retentive DB words. The reference S7-300 CPU 31xC and CPU 31x Manual documents the IEC timer data type limits that bound the problem.

Why a Single IEC Timer Cannot Reach 30 Days

The S7-300/400 family offers three IEC timer function blocks: SFB 3 / TP (pulse), SFB 4 / TON (on-delay), and SFB 5 / TOF (off-delay). Their preset and elapsed values are stored in the IEC TIME data type (DWORD, 32-bit signed), which the IEC 61131-3 standard defines as a duration in milliseconds. The maximum positive value is 231 − 1 ms = 2,147,483,647 ms, which is approximately 24.86 days. The 30-day requirement exceeds this ceiling by roughly 5 days, so a single TON instance cannot be used even at the mathematical limit.

The legacy S5TIME format used by S_ODT, S_PULSE, S_ODTS, S_OFFDT, and S_PEXT is even more restrictive. The 16-bit BCD count (0–999) is multiplied by a time base selected from 10 ms, 100 ms, 1 s, or 10 s, so the absolute maximum is 999 × 10 s = 9,990 s ≈ 2.77 hours. This explains why first attempts using an IEC timer with MD800 as the preset produced an apparently-correct network that could never reach the desired value - the preset silently saturated. Reference STEP 7 - Working with Timers and Counters tabulates the S5TIME ranges.

Range-error trap. On the S7-300, MD800 is interpreted as a TIME value whose MSB is the sign bit. Loading a constant of T#30d into MD800 produces the S7 compiler diagnostic "Range error" or silently saturates to T#24d_20h_31m_23s_647ms; the timer then never reaches its preset and the Q output never rises.

Two practical workarounds exist: cascade a 1-minute timer into a minute counter and convert counts to days, or compare real-time-clock (RTC) timestamps against a target DATE_AND_TIME using SFC 1. A third option - SFB 4 CEV (operating-hours counter) - is purpose-built for run-time meters. Each method has trade-offs in precision, retentivity, and code complexity. The full S7-300 Automation System Manual lists every available SFB/SFC and its retentive behaviour.

Method 1 - Cascaded 1-Minute Timer + Counter

This is the simplest, most portable approach and requires no system clock. The architecture is:

  1. An IEC TON with preset = 60,000 ms (= T#1m) generates a one-shot every minute while the run-condition is TRUE.
  2. A rising-edge-detected CV-flag increments an INT minute counter.
  3. When the minute counter reaches 60 it resets to 0 and a separate hour counter is incremented.
  4. Hour counters are compared to the day-equivalent preset (e.g., 30 d × 24 h = 720 h).
  5. When the hour counter reaches the preset, a one-shot "expired" bit is set and the process is started.

For a pump that runs essentially 24/7 the run-condition is "Pump-1 contactor closed" or "Pump-1 current > 5 A" (using a 4–20 mA transducer). For a tank high-high event the run-condition is "LHH TRUE AND Process-1 NOT yet started". Once the expired action has fired the timer should be latched off, and a manual reset bit must be provided to re-arm the cycle.

Data Block Layout

Use a dedicated DB (e.g., DB 50 "Timers") with the following structure so that values are grouped and easy to monitor online in STEP 7 or via the HMI:

DATA_BLOCK "Timers"
VERSION : 0.1
  STRUCT
   Pump1_RunMinutes    : INT;     // 0..59
   Pump1_RunHours      : DINT;    // 0..1000 for 41 d
   Pump1_PresetHours   : DINT;    // 720 = 30 d
   Pump1_Expired       : BOOL;
   Pump1_Reset         : BOOL;
   HH_7d_Minutes       : INT;
   HH_7d_Hours         : DINT;
   HH_7d_PresetHours   : DINT;    // 168 = 7 d
   HH_7d_Expired       : BOOL;
   HH_7d_Reset         : BOOL;
   HH_8d_Minutes       : INT;
   HH_8d_Hours         : DINT;
   HH_8d_PresetHours   : DINT;    // 192 = 8 d
   HH_8d_Expired       : BOOL;
   HH_8d_Reset         : BOOL;
   Tick_1min           : BOOL;
  END_STRUCT;
END_DATA_BLOCK

LAD Network - 1-Minute Tick Generator

The 1-minute tick uses an IEC TON with a 1-minute preset. Only the rising edge of the Q output at expiry is used; the elapsed time is irrelevant.

A  M 100.0        // Run-enable flag (TRUE for pump, LHH-latched for tank events)
AN M 100.1        // Inhibit on CPU fault
L  T#1m
SD "Tick_1min"    // IEC TON in DB 50 / multi-instance
A  "Tick_1min"
FP M 100.2         // Detect one rising edge per minute
JC INCR
BEU
INCR: ...
Self-reset pattern. The classic pattern where the timer output is reset in the same network that creates it is shown above only for clarity. In production code, use an edge memory bit (positive edge from M 100.2) so the timer output does not have to be cleared in the same scan; otherwise the timer will misbehave at scan times close to its preset.

ST Implementation of the Cascade

The cascade is more compact in Structured Text and easier to commission because all the time math is in one place. Place the following in OB 35 (cyclic interrupt, 100 ms by default) or directly in OB 1:

// 1-minute tick detection
IF "Timers".Tick_1min THEN
    "Timers".Tick_1min := FALSE;

    // -------- Pump-1 30-day run meter --------
    IF "Pump1_Running" AND NOT "Timers".Pump1_Expired THEN
        "Timers".Pump1_RunMinutes := "Timers".Pump1_RunMinutes + 1;
        IF "Timers".Pump1_RunMinutes >= 60 THEN
            "Timers".Pump1_RunMinutes := 0;
            "Timers".Pump1_RunHours   := "Timers".Pump1_RunHours + 1;
            IF "Timers".Pump1_RunHours >= "Timers".Pump1_PresetHours THEN
                "Timers".Pump1_Expired := TRUE;   // Pump-2 start condition
            END_IF;
        END_IF;
    END_IF;

    // -------- 7-day Process-1 timer (LHH triggered) --------
    IF "Tank_LHH" AND NOT "Timers".HH_7d_Expired THEN
        "Timers".HH_7d_Minutes := "Timers".HH_7d_Minutes + 1;
        IF "Timers".HH_7d_Minutes >= 60 THEN
            "Timers".HH_7d_Minutes := 0;
            "Timers".HH_7d_Hours   := "Timers".HH_7d_Hours + 1;
            IF "Timers".HH_7d_Hours >= "Timers".HH_7d_PresetHours THEN
                "Timers".HH_7d_Expired := TRUE;
                "Process_1_Cmd" := TRUE;
            END_IF;
        END_IF;
    END_IF;

    // -------- 8-day Process-2 timer (same LHH trigger) --------
    // identical pattern with preset = 192 h
END_IF;

// Manual reset paths
IF "Timers".Pump1_Reset THEN
    "Timers".Pump1_RunMinutes := 0;
    "Timers".Pump1_RunHours   := 0;
    "Timers".Pump1_Expired    := FALSE;
    "Timers".Pump1_Reset      := FALSE;
END_IF;

Note that the 7-day and 8-day timers share the same trigger (LHH) but are independent counters. The 7-day timer fires first; the 8-day timer keeps counting until 192 h have elapsed since the LHH event was first seen, producing a deterministic 24 h spacing between Process-1 and Process-2.

Resolution and Worst-Case Error

Each tick is one minute by definition, so the absolute worst-case timing error is +59 s, or about 0.003 % of a 30-day cycle. This is acceptable for pump rotation but is too coarse for an event-time-of-day requirement. Use Method 2 when you need real-time-clock precision (1 s) and an audit-grade timestamp.

Method 2 - Real-Time Clock Comparison with SFC 1

The CPU 315-2PN/DP contains a hardware-backed real-time clock with typical accuracy of ±2 s/day at 25 °C. SFC 1 READ_CLK reads the current DATE_AND_TIME (8-byte BCD format, base 1990-01-01) into a destination area. By stamping the trigger event and comparing it to the current RTC, the elapsed duration in seconds can be calculated using FC 3 / FC 33 / FC 40 from the STEP 7 standard library.

Data Structures

DATA_BLOCK "RTC_Timers"
VERSION : 0.1
  STRUCT
   LHH_Event_Time    : DATE_AND_TIME;   // SFC 1 capture
   LHH_Triggered     : BOOL;
   Process1_Due      : BOOL;
   Process2_Due      : BOOL;
   Pump1_Start_Time  : DATE_AND_TIME;
   Pump1_Running     : BOOL;
   Pump1_Due         : BOOL;
  END_STRUCT;
END_DATA_BLOCK

Capturing the LHH Trigger

A  "Tank_LHH"           // high-high digital input (I 0.7)
FP "LHH_Edge_Mem"        // one-shot on rising edge
JCN END1

CALL SFC 1
   RET_VAL := MW 200
   CDT     := "RTC_Timers".LHH_Event_Time

SET
S "RTC_Timers".LHH_Triggered
R "RTC_Timers".Process1_Due
R "RTC_Timers".Process2_Due

END1: NOP 0

Comparing Elapsed Time

S7-300 has no native DATE_AND_TIME subtraction, but FC 3 "D_TD" converts DT to seconds-since-1990-01-01 (DINT), after which straight subtraction and division gives elapsed days or seconds. A user-friendly approach is to encapsulate the math in an FB that returns a DINT of elapsed seconds:

// returns elapsed seconds since LHH_Event_Time
L "RTC_Timers".LHH_Event_Time
T #DT_old

CALL FC 3                         // D_TD: DT → DINT seconds
   IN  := #DT_now_sec
   RET_VAL := #elapsed_sec

CALL FC 3
   IN  := #DT_old
   RET_VAL := #DT_old_sec

L  #DT_now_sec
L  #DT_old_sec
-D
T  #elapsed_sec                    // signed DINT, allow wrap-around

// 7-day check: 7 * 86400 = 604800 s
L  604800
>=D
JC NO7
SET
S "RTC_Timers".Process1_Due
NO7: NOP 0

// 8-day check: 8 * 86400 = 691200 s
L  691200
>=D
JC NO8
SET
S "RTC_Timers".Process2_Due
NO8: NOP 0

Because the comparison is performed against absolute wall-clock time, the timer is inherently retentive. The RTC has its own battery-backed hardware clock and the trigger timestamp lives in a retentive DB. A power loss of any duration does not corrupt the elapsed-time calculation: when the CPU returns to RUN, SFC 1 reports the current time and the comparator immediately sees the correct value.

RTC battery endurance. On the CPU 315-2EH14 the hardware clock is buffered by the front-panel battery (typical 1-2 years) and a gold capacitor (~4 weeks at 25 °C). If both buffer sources expire the clock falls back to the last SFC 0 SET_CLK value, or to "1994-01-01 00:00:00" on a cold start. Always monitor the buffer-low diagnostic in the diagnostic buffer (OB 100) and re-synchronise the clock from an NTP-capable CP (e.g., CP 343-1 Lean 6GK7 343-1CX10-0XE0) at every warm restart.

Method 3 - Pump Run-Time Meter Using SFB 4 (CEV)

For the 30-day pump rotation requirement specifically, the cleanest implementation is to use the operating-hours counter SFB 4 ("CEV"). SFB 4 increments an internal DINT for as long as its CU input is TRUE and automatically resets when the DINT reaches the preset. The instance DB keeps the hours in volatile memory unless explicitly placed in the retentive area via the hardware configuration.

CALL "CEV" , DB72         // SFB 4 instance
   CU    := "Pump1_Running"   // 1 = count, 0 = hold
   RESET := "Reset_Button"
   PV    := L#720            // 30 d × 24 h
   Q     := "Pump1_HoursDone"
   CV    := "Pump1_HoursCounted"   // current hours, DINT

The CPU 315-2PN/DP requires SFB 4 to be instantiated as a multi-instance or in a dedicated DB. To make the counter survive STOP/RUN, open the CPU Properties in HW Config → Retentive Memory and tick "Retentivity for all DBs" or place the instance DB explicitly in the retentive area. Reference S7-300/400 Standard Software - System and Standard Functions for the full list of CEV/CTV/CU parameters.

Pump Changeover and LHH Process-Start Logic

30-Day Pump Rotation

Once Pump1_HoursDone goes TRUE, the duty-rotation code should:

  1. Latch Pump-1 off.
  2. Energise Pump-2 contactor after a 5 s overlap interlock to avoid both pumps starting together.
  3. Start a mirror SFB 4 CEV for Pump-2 with the same 720 h preset.
  4. Reset Pump-1's CEV only after Pump-2 has been confirmed running (current-feedback or contactor auxiliary).
A "Pump1_HoursDone"
AN "Pump1_Fault"
AN "Pump2_Running"
S "Pump2_Cmd"           // start pump 2
R "Pump1_Cmd"           // stop pump 1

// 5 s overlap interlock then pulse the reset
L S5T#5s
SD T 10
A T 10
A "Pump2_Running"
R "Reset_Button"        // pulse CEV reset for Pump-1

If the application requires absolute equal wear across multiple pumps, use a third FB that tracks total pump starts, total run-hours, and total starts since last maintenance, then selects the least-worn pump on each call. The PLCopen-compliant FB MC_Power patterns available in TIA Portal also apply on S7-300 with STEP 7 V5.x but require the optional "PLCopen Library" add-on.

7-Day and 8-Day LHH Process Starts

The 7-day timer should fire only the first time the LHH condition is observed after a reset (a new tank cycle). The 8-day timer should fire 24 h later. Code pattern in ST:

// Edge-triggered capture of LHH
IF "Tank_LHH" AND NOT "LHH_Latch" THEN
    "LHH_Latch" := TRUE;
    SFC1_RET := READ_CLK(CDT := "LHH_Start_DT");
END_IF;

IF NOT "Tank_LHH" THEN
    "LHH_Latch" := FALSE;
END_IF;

// 7-day check (uses ELAPSED_DT FB returning DINT seconds)
IF "LHH_Latch" AND NOT "Process1_Done" THEN
    IF ELAPSED_DT("LHH_Start_DT", CURRENT_DT) >= 604800 THEN
        "Process1_Cmd" := TRUE;
        "Process1_Done" := TRUE;
    END_IF;
END_IF;

// 8-day check
IF "LHH_Latch" AND NOT "Process2_Done" THEN
    IF ELAPSED_DT("LHH_Start_DT", CURRENT_DT) >= 691200 THEN
        "Process2_Cmd" := TRUE;
        "Process2_Done" := TRUE;
    END_IF;
END_IF;

The ELAPSED_DT FB subtracts two DATE_AND_TIME values via FC 3 (D_TD → seconds since 1990-01-01) and returns a DINT result. S7-300's IEC TON cannot directly accept a TIME result longer than 24.86 days, so the elapsed time must be compared as raw seconds (DINT) rather than fed into a TON preset.

Retentive vs Non-Retentive Storage

The CPU 315-2PN/DP allocates retentive areas during hardware configuration. Defaults are MB 0–15 (16 bytes), T 0–127 (128 timers), and C 0–63 (64 counters). For multi-day timing applications where the PLC may experience power dips, the storage location of the counters determines whether they survive.

Storage area Volatile Retentive Typical use
M 0.0 – M 15.7 No Yes (default) Run-time meter hours counter
M 16.0 – M 255.7 Yes No Intermediates, scan flags
DB with "Non-retentive" UNCHECKED No Yes Hour / minute counters, presets
DB with "Non-retentive" CHECKED Yes No Edge memories, one-shots
SFB 4 instance DB (DB 72 above) Volatile unless marked Requires tick in HW config Operating-hours counter
Retentive DB 50 above No Yes Cascade counters

For a pump duty-rotation or filter back-wash that must survive a power outage of indefinite length, place all hour/minute counters in a retentive DB (DB 50 above) and clear the "Non-retentive" checkbox in the DB properties. For a process that should restart its timer on every power-up (e.g., a one-shot 30-day sterilisation cycle), leave the DB non-retentive.

Alternative - Time-of-Day Interrupts (OB 10) for Periodic Schedules

If the 7/8/30-day requirements are periodic (e.g., "every 7 days at 02:00") rather than continuous from a trigger event, OB 10 time-of-day interrupt is the natural choice. OB 10 is called by the CPU operating system at the programmed date and time, regardless of OB 1 execution. Inside OB 10, set the next run time via SFC 28 SET_TINT and execute the desired action. This avoids counters entirely and uses the CPU's RTC scheduler.

// In HW config: enable OB 10, set execution date/time, e.g., 02:00:00 daily
// In OB 10:
CALL SFC 28
   OB_NR   := 10
   SDT     := "Next_OB10_DT"     // next trigger time (DATE_AND_TIME)
   PERIOD  := W#16#0000          // once
   RET_VAL := "OB10_RetVal"

// User action
A "Pump1_Running"
S "Pump2_Cmd"             // rotate pump duties at 02:00
R "Pump1_Cmd"

The CPU 315-2PN/DP supports OB 10–17 (eight time-of-day OBs), each capable of being scheduled once, every minute, hourly, daily, weekly, monthly, or yearly via the PERIOD byte. For multi-day intervals compute the next SDT in seconds and load it as a DATE_AND_TIME constant. The same caveat regarding TIME data-type limits applies when converting days × 86400 into a DINT offset, so use DINT arithmetic.

Commissioning and Verification

Do not run the timer for 30 days during commissioning. Two safe techniques compress the test cycle:

  1. Preset override. Temporarily change the preset from 720 h to 0 h so the expired bit fires on the first scan. Verify the downstream action (Pump-2 starts, Process-1 starts). Reset to the real value.
  2. Time compression. Change the 1-minute tick to 1-second (T#1s) and reduce presets by a factor of 60. The 30-day timer fires in 12 minutes, the 7-day in 2.8 min, and the 8-day in 3.2 min.

For the RTC method, temporarily set the CPU clock one week forward via SFC 0 SET_CLK, trigger the LHH event, then set the clock back. Verify the elapsed-time logic behaves as expected without disturbing the battery-buffered time.

Test Action Expected result
Pump-1 30-day rotation Start Pump-1, force 1-min tick to 1 s, preset = 12 min After 12 min Pump-2 starts, Pump-1 stops, Pump-2 hour meter starts
7-day Process-1 start Force LHH TRUE, monitor DB50.HH_7d_Hours Counts to 168, then Process_1_Cmd = TRUE
8-day Process-2 start Same as above with HH_8d_Hours Counts to 192, then Process_2_Cmd = TRUE; 24 h after Process_1 fired
Power-loss retention At 50 h elapsed, STOP CPU, power down 5 min, power up Pump1_RunHours still = 50, continues counting from 51
Cold restart (MRES) MRES, then run Timers reset to 0 unless retentivity is configured
RTC wrap test Set CPU clock back 2 days, retrigger LHH Elapsed_DT returns negative; no process start
Simultaneous pump prevention Manually force both Pump1_Cmd and Pump2_Cmd Interlock holds; only one contactor closed at a time

Troubleshooting Matrix

Symptom Likely root cause Fix
30-day timer never fires; Q stays FALSE Preset entered as S5TIME constant (max 2.77 h) Use IEC TON with TIME data type and cascade counter, or use SFC 1 + RTC comparison
MD800 shows 30 d but compiler warns "range error" MD loaded with T#30d overflows IEC TIME 32-bit signed Switch to DINT day counter and compare with 30, not MD with TIME constant
Hour counter resets to 0 on every STOP→RUN DB not retentive or placed outside retentive area Open DB properties → uncheck "Non-retentive", or move to MB 0–15 (retentive by default)
1-minute tick fires more than once per minute Self-reset in same network creates multiple passes Use edge bit (FP) and reset timer only in the next scan, or use IEC TP with PT = T#1m and clear the input
LHH event lost on power dip LHH was a momentary pulse; latch not retained Latch LHH in retentive M-marker or DB bit; reset only on manual acknowledge
Both Pump-1 and Pump-2 start simultaneously Reset of Pump-1 CEV happens before Pump-2 contactor closes Add 5 s overlap interlock; only reset Pump-1 meter after Pump-2 running contactor confirms
Process-1 and Process-2 fire at the same time Single 7-day timer used for both with wrong preset Implement two independent counters with presets 168 h and 192 h
RTC timestamps read as 1994-01-01 Battery exhausted / CPU cold-started without SFC 0 Replace battery, run SFC 0 from HMI or NTP at every warm restart, monitor buffer-low bit
OB 10 fires immediately on cold start OB 10 start time left in past Always set start time forward of current RTC; on firmware < V3.3 add 2 s margin
OB 35 cyclic interrupt not called OB 35 not inserted in OB 1 priority tree or scan time > 100 ms Insert OB 35 in HW config; verify scan time in OB 1

Choosing Between the Three Methods

Criterion Cascade counter (Method 1) RTC comparison (Method 2) SFB 4 CEV (Method 3)
Maximum duration Unlimited (counter only) Unlimited 2,147,483,647 h (≈ 245,000 y)
Resolution 1 min (default), tunable 1 s 1 h
Power-loss retentive Optional (mark DB retentive) Inherent (battery-backed RTC) Optional (instance DB)
Code complexity Low Medium (need DT math) Very low (one SFB call)
Audit-grade timestamp No Yes (DATE_AND_TIME) No (counter only)
Best for Tank-event cascade, multi-stage processes Audit-trail events, billing, alarms Pump / motor hour meters

For this application the recommended mix is SFB 4 CEV for the 30-day pump rotation (cleanest, smallest code, built-in PV comparison) and cascade counter for the 7-day and 8-day LHH timers (independent counters, easy HMI reset). If audit trails are required for compliance, layer the RTC method on top as a parallel timestamp log without removing the counter.

Field-Proven Caveats and Summary

Saturation warning. Never load a constant larger than T#24d_20h_31m_23s_647ms into an IEC TON/TP/TOF preset. STEP 7 V5.7 accepts the value at compile time but the runtime saturates at maximum, producing a timer that never reaches its preset. Source: CPU 31xC / 31x Manual, section on IEC timer data types.
Firmware V3.3 OB 10 bug. CPU 315-2PN/DP units with firmware older than V3.3 (e.g., 6ES7 315-2EH13-0AB0) have known bugs in the OB 10 start-time calculation when the start time is in the past relative to the current RTC. Always set OB 10 start times forward by at least two seconds, or upgrade to firmware V3.3 or later.
S7-1500 migration path. If you migrate to an S7-1500, the same logic applies but the IEC TIMER data type extends to 64-bit LTime (L#), removing the 24.86-day ceiling. The cascade-counter and SFB 4 CEV patterns port unchanged. SFB 4 is replaced by the standard timer/counter IEC blocks in TIA Portal but the CEV-equivalent is the RuntimeMeter instruction in the "Extended instructions" palette.

The 30-day, 8-day, and 7-day timing requirements cannot be met with a single S7-300 IEC timer block because the 32-bit signed TIME data type saturates at 24.86 days. Three production-grade workarounds exist: cascade a short IEC timer into a counter for continuous-run meters, compare DATE_AND_TIME stamps using SFC 1 for event-triggered delays, or use SFB 4 CEV for operating-hours accumulation. For this application, combining SFB 4 (pump rotation) with two independent cascade counters (7-day and 8-day) provides the best balance of code clarity, retentivity, and commissioning speed. The retention behaviour is governed by the retentive memory settings in HW Config and by the "Non-retentive" property of each data block. Verify all three timers with time-compressed commissioning before handing over the system, and always re-synchronise the CPU clock from NTP after a battery replacement.

FAQ

Why does my IEC TON never fire when I set the preset to 30 days?

The IEC TIME data type is a 32-bit signed value in milliseconds with a maximum of 2,147,483,647 ms (~24.86 days). A 30-day preset exceeds this limit, so the value is clamped at maximum or rejected by the compiler. Replace the single TON with a cascade of a short timer into a counter, or compare DATE_AND_TIME stamps using SFC 1 / FC 3.

How do I make the 30-day timer survive a power loss?

Place the hour and minute counters in a data block marked as retentive (clear the "Non-retentive" checkbox in the DB properties), or store them in MB 0–15 (retentive by default on the CPU 315-2PN/DP). Alternatively, use the real-time clock method with SFC 1 and a retentive DATE_AND_TIME timestamp; the RTC is battery-backed so wall-clock time is preserved through short outages.

Can I use a single 7-day timer for both Process-1 and Process-2?

No. The two processes must fire 24 h apart, so they need independent counters. Use two DINT hour counters in the same DB with presets 168 h and 192 h respectively, each driven by the same LHH edge-detect block. Once Process-1 fires, latch "Process-1 done" and let the 8-day counter keep counting until 192 h elapsed.

What is the simplest way to rotate two pumps every 30 days?

Use SFB 4 "CEV" with PV = L#720 (30 d × 24 h). Drive its CU input from the Pump-1 contactor-closed flag. When Q rises, start Pump-2, stop Pump-1, and reset the CEV via the RESET input (interlock to prevent both pumps running). Make the CEV instance DB retentive if you need to survive power loss.

Can OB 10 replace the cascade counter?

Yes, if the timing requirement is periodic (e.g., "every 30 days at 02:00"). OB 10 is called by the CPU operating system at the programmed date/time; inside OB 10 you set the next run time via SFC 28 and execute the desired action. For one-shot delays from a trigger event (e.g., "7 days after LHH goes TRUE"), use the cascade counter or RTC-comparison method instead.

Back to blog