1. Why a Dedicated Seconds Counter on the S7-1200?
The S7-1200 CPU family (CPU 1211C, 1212C, 1214C, 1215C, 1217C) provides nanosecond resolution on its system clock, but the available time tags in the user program default to one of the following:
-
DTL(Date_And_Time_Long): 12 bytes, year down to nanoseconds. Carries 8 ns of resolution but is awkward to increment by hand. -
TimeIEC type: 32-bit signed milliseconds. Easy to use for timers, but reading "Time" inside OB1 gives the elapsed time of the last cycle, not wall-clock seconds. - No native
UDInt "SecondsSincePowerOn"tag on the S7-1200.
For runtime displays, batch timers and shift-hour counters you almost always want a plain UDInt or DInt that goes up by one each second. You then format that value to display in HMI tags. The four methods below all produce exactly that result; they differ in resource usage, determinism, and resilience to power cycles.
2. Method Comparison
| Method | Resources | Resolution | Retentive | Best For | Limitations |
|---|---|---|---|---|---|
| Clock memory byte + edge | 1 byte memory, 1 BOOL, 1 DINT | 0.1 s – 2.0 s selectable | No (resets on power cycle unless the counter is retentive) | General-purpose, simplest implementation | Depends on clock byte being enabled in CPU properties |
Multi-instance TP_TIME
|
16 bytes per instance, 1 DINT | Any (set by PT) | No | No clock byte available, deterministic, code in FB | Slightly higher overhead; must be inside an FB |
| Cyclic interrupt OB (OB30) | 1 OB, 1 DINT | 1 ms – 60 000 ms | No | Precise interval, isolates logic from OB1 | OB30 must be created; OB1 jitter does not affect counter |
RD_SYS_T / READ_CLK diff |
2 DTL, 1 DINT | 1 s (wall clock) | Yes (DTL holds year/month/day) | Real-time-of-day values, time stamping | More math, INT/DINT conversion needed |
3. Prerequisites and Clock Memory Byte Setup
For Methods 1 and 2 you must enable the clock memory byte in the CPU hardware configuration. Without it, the M-bit you reference will read FALSE forever — the most common reason the seconds counter never moves.
- Open the TIA Portal project and select the S7-1200 CPU in the device tree.
- Open Properties → System & Clock Memory.
- Tick "Enable the use of clock memory byte".
- Set the Address to the byte you want to use. The default is
MB0. The discussion thread specifically called out the value22for a user who set the byte toMB22. - Click OK and download the hardware configuration to the PLC (not just the program — the entire device configuration must be reloaded for the change to take effect).
3.1 Default Bit Frequencies
Once the byte is enabled, each bit toggles at a fixed period. The periods below are the defaults shipped with every S7-1200 and S7-1500 CPU:
| Bit | Period | Frequency | Typical Use |
|---|---|---|---|
| Mx.0 | 0.1 s | 10 Hz | Fast blink, 100 ms cyclic logic |
| Mx.1 | 0.2 s | 5 Hz | Slow blink |
| Mx.2 | 0.4 s | 2.5 Hz | Heartbeat indicator |
| Mx.3 | 0.5 s | 2 Hz | Half-second tick |
| Mx.4 | 0.8 s | 1.25 Hz | — |
| Mx.5 | 1.0 s | 1 Hz | Seconds counter |
| Mx.6 | 1.6 s | 0.625 Hz | — |
| Mx.7 | 2.0 s | 0.5 Hz | Slow indicator |
For a 1-second counter use bit .5. The original poster attempted M22.5, which is the correct bit — but only if byte 22 was actually configured as the clock memory byte.
4. Method 1: Clock Memory Byte with Edge Detection (LAD)
This is the most concise approach and is the one the discussion thread converged on. It uses a P_TRIG (rising-edge detector) to ensure the ADD only fires once per second rather than on every OB1 scan.
4.1 Tag Declaration
| Tag | Type | Address / Value | Comment |
|---|---|---|---|
| ClockByte | BYTE | MB22 (or MB0) | Configured clock memory byte |
| Clock_1Hz | BOOL | %M22.5 | 1 s pulse |
| SecondCounter | DINT | %MD24 (default tag table) | Counts upward in 1 s steps |
4.2 Network 1 — Counting
Network 1: Seconds counter via clock memory
%M22.5 "Clock_1Hz"
----| |---------|P TRIG|------(ADD_DI, 1, SecondCounter, SecondCounter)---
The contact %M22.5 closes every 0.5 s and opens every 0.5 s, producing a 50 % duty cycle at 1 Hz. P TRIG converts the closing edge into a single-cycle pulse, so the ADD fires exactly once per second. Using the closing edge (or the opening edge with N TRIG) avoids double-counting on a slow OB1.
4.3 Network 2 — Reset (Optional)
Network 2: Reset on operator command
%I0.0 "ResetSeconds"
----| |---------[MOVE, 0, SecondCounter]------------------
Add a reset input if HMI operators must zero the counter. Mark SecondCounter as Retain in the PLC tag table if the count should survive a power cycle.
5. Method 2: Multi-Instance TP_TIME Pulse Timer
Use this method when the clock memory byte is disabled, the byte is used by another subsystem, or you need a period that is not one of the eight standard frequencies. Siemens' official programming recommendation is to instantiate the IEC timer TP_TIME as a multi-instance inside a function block (FB). This keeps timer data encapsulated in the FB's Static section and avoids the need for a separate global DB.
- In the project tree, add a new Function Block (e.g.
FB_SecondsCounter). - In the FB interface, add a Static tag named
Time_1of typeTP_TIME. - Add an Input tag
Runof typeBOOL. - Add a Static tag
Counterof typeDINTmarked Retain. - Add an Output tag
Secondsof typeDINT.
5.1 FB Code
// FB_SecondsCounter
// Static
Time_1 : TP_TIME; // IEC pulse timer, multi-instance
Counter : DINT; // Retentive count
Network 1: 1 s pulse generator
%Run
----| |------[TP_TIME]---(Q := Pulse1Hz)----
|
+-- IN : Run
+-- PT : T#1s
+-- Q : Pulse1Hz
+-- ET : unused
Network 2: Increment on rising edge of pulse
%Pulse1Hz
----| |---------|P TRIG|------(ADD_DI, 1, Counter, Counter)---
Network 3: Map to output
%Counter
----[MOVE, Counter, Seconds]---------------
Call the FB from OB1 in a cyclic instance DB. The pulse generator will produce a 1 s pulse on Pulse1Hz for the full second, which the rising edge will detect once per second and feed the ADD. Reference: Siemens TIA Portal Help — Using IEC timers and counters (S7-1200, S7-1500).
6. Method 3: Cyclic Interrupt OB Counter
The S7-1200 supports a hardware-driven cyclic interrupt OB (default name OB30 in TIA Portal, configurable interval 1 ms to 60 000 ms). Counting inside a cyclic OB isolates the increment from the OB1 jitter of the main program and guarantees that the counter ticks at exactly the configured interval regardless of the main scan time.
- Right-click Program blocks in the device tree and choose Add new block → Organization block → Cyclic interrupt.
- Name it
OB_Cyclic_1s. TIA Portal assigns OB30 by default. - Open the OB's properties and set the Cycle time to
1000 ms. - Inside the OB, increment a global DINT tag
SecondCounterby 1.
// OB_Cyclic_1s (OB30)
Network 1: Increment seconds counter on every cyclic call
[ADD_DI, 1, "SecondCounter", "SecondCounter"]
7. Method 4: RD_SYS_T / READ_CLK in OB1
If you need a seconds counter that is tied to wall-clock time (i.e. it survives a power cycle and is not driven by the clock memory), read the CPU real-time clock and compute the seconds since a reference value. The S7-1200 instruction is RD_SYS_T (in older projects READ_CLK). Output is a DTL structure.
// OB1
Network 1: Read current time
[RD_SYS_T] --> now_DTL
To produce a seconds counter, capture now_DTL on the first scan into start_DTL and compute diff_seconds = T_DIFF (now_DTL, start_DTL) / 1000 using the T_DIFF instruction (returns a TIME, which you divide by 1000 to get seconds). This approach is overkill for a simple counter but is the only one of the four that survives an OB1 cycle skip or a CPU stop without losing track of wall-clock time.
8. Complete Working Example for TIA Portal V11 / V15 / V17
The complete ladder snippet below compiles on TIA Portal V11 SP2 (the version the original poster used) and is forward-compatible with V15, V16, V17 and V18. It uses only standard IEC instructions and global PLC tags.
// PLC tags (default tag table)
"Clock_1Hz" : BOOL at %M0.5 // Clock memory byte bit 5
"SecCount" : DINT at %MD4 (Retain = TRUE)
"SecReset" : BOOL at %I0.0 // Reset pushbutton
// OB1
// Network 1: 1 s edge -> ADD
"Clock_1Hz"
----| |---------|P TRIG|------------(ADD_DI, IN1:=1, IN2:="SecCount", OUT:=>"SecCount")---
// Network 2: Reset on pushbutton (rising edge)
"SecReset"
----| |---------|P TRIG|------------[MOVE, IN:=0, OUT1:=>"SecCount"]----
Download the project (Hardware and Software) to the S7-1200. After a power cycle, the value of SecCount is restored from the retain area and continues counting from the previous value.
9. Troubleshooting Matrix
| Symptom | Likely Cause | Fix |
|---|---|---|
| Bit stays FALSE, counter never moves | Clock memory byte is not enabled in CPU properties | Enable it under CPU Properties → System & Clock Memory, then download hardware configuration |
| Bit toggles in some projects but not this one | Different CPU / project is using a different MB address (M22 instead of M0) | Verify the configured byte matches the address in your program. The byte configured in the CPU properties is the only byte that toggles |
| Bit toggles in TIA online watch table but counter is still 0 | Memory overlap — the same byte is being written by another block (HMI, recipe, data block) | Search the cross-reference for the byte, remove the duplicate write, or move the clock memory byte to a free address |
| Project downloads multiple times, still does not work | Hardware configuration was not reloaded after enabling the clock memory byte | Right-click the device → Download to device → "Hardware configuration" |
| Firmware 2.2 on a CPU 1214 — bit still does not toggle | Firmware 2.2 supports the clock memory byte, but a corrupt firmware image can disable it | Perform a factory reset, update firmware to the latest 4.x release, then re-download the project |
| Counter ticks twice per second | No edge detection — the ADD sees the contact closed for the entire 0.5 s pulse and counts twice | Add a P_TRIG or N_TRIG before the ADD |
| Counter jumps by 2 or 3 sporadically | OB1 cycle time is much longer than 1 s (rare, but possible on a heavily loaded CPU) | Use OB30 with a 1 s period instead of a clock memory bit, or enable a 100 ms bit and divide by 100 |
9.1 Memory-Overlap Diagnostic
To confirm whether the clock memory byte is being clobbered:
- Open the project, right-click the CPU and select Cross-reference.
- Filter on the address
MB22(or whatever byte is configured). - Any tag other than the implicit clock memory access that writes to
MB22is suspect. Either move the clock memory byte, or stop the conflicting write.
9.2 Firmware Compatibility
The clock memory byte is supported on every S7-1200 CPU firmware from V1.0 onwards. Firmware 2.2 (released in 2012) is more than capable. If the bit does not toggle after a fresh factory reset and re-download, the issue is the project download, not the firmware. Reference the S7-1200 system manual for the supported feature set on your specific CPU: Siemens Industry Online Support.
10. Verification and Commissioning Checklist
Before signing off the seconds counter as "done":
- Add the counter to a watch table with a 1 s refresh and confirm the value increments by exactly 1 every second for at least 60 cycles.
- Toggle the reset input and confirm the counter returns to 0 and resumes counting.
- Power-cycle the PLC and confirm the counter either resets to 0 (non-retentive) or continues from the previous value (retentive) as the design specifies.
- Bind the counter to an HMI tag and confirm the display updates in real time.
- Use the cross-reference to confirm no other block writes to the clock memory byte.
11. FAQ
Why does my M22.5 bit stay FALSE even though the clock memory byte is enabled in TIA Portal?
The most common cause is that the hardware configuration was not reloaded to the PLC. Use "Download to device → Hardware configuration" rather than the software-only download. Also confirm that no other block, data block, or HMI tag is writing to MB22, which will mask the clock memory toggle. On TIA Portal V11 with S7-1200 firmware 2.2 the feature is supported, so a missing toggle almost always means a project load issue, not a firmware limitation.
What is the difference between TP_TIME and TON in TIA Portal for a seconds counter?
TP_TIME is a pulse timer that generates a fixed-width output pulse on a rising edge of the input, while TON is a delay-on timer that needs the input to be true for the full preset time. For a seconds counter you want a one-second pulse and a one-time increment, so TP_TIME plus a P_TRIG is the cleanest combination. A TON with a 1 s preset and a rising edge on the output works too but is harder to read in the code.
Can I use the same clock memory bit on a S7-1500 and a S7-1200 in the same project?
Yes. The bit frequencies (0.1 s, 0.2 s, 0.5 s, 1.0 s, …) are identical across both CPU families. Configure the clock memory byte in each CPU's properties. The default address is MB0 on both platforms, but you can move it to a free byte such as MB100 if the default area is already used by the program.
How do I make the seconds counter retentive so it survives a power cycle?
Open the PLC tag table, select the counter tag, and tick the "Retain" column. On the S7-1200 the retain area is backed up by the internal maintenance-free capacitor, so a brief power cycle is preserved automatically. For a permanent loss of power you need a battery cartridge (BB1297) on the CPU 1214C/1215C/1217C.
Which method is best for a shift-hour counter on a 24/7 packaging line?
Use Method 3 (cyclic interrupt OB30 at 1000 ms) combined with a retentive DINT counter. The OB30 path is independent of the OB1 scan, so it is immune to spikes in main program cycle time. Add a P_TRIG inside OB30 if you need to confirm that the counter advances by exactly one per OB call, and bind the DINT to an HMI tag for display.