Siemens SINUMERIK Parts Counter and Cycle Time Display Guide

David Krause11 min read
Motion ControlSiemensTechnical Reference
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

Overview

Siemens SINUMERIK 810D/828D/840D sl controls expose machine data, R-variables, and a set of system variables that make it possible to build a parts counter and a live cycle-time / clock display without writing ladder logic on a PLC. The two building blocks used in this implementation are:

  • R-variables (R0..R99, extended R100+ where configured) – integer/free numeric work registers that can be loaded, modified, displayed and persisted across program runs.
  • NC system variables – read-only variables starting with $ that expose controller state. The relevant ones are $AC_CYCLE_TIME, $A_HOUR, $A_MINUTE, $A_SECOND, and $A_DAY.

The same pattern is frequently requested on SIMATIC S7-1200/S7-1500 CPUs for shop-floor cycle timers; that platform exposes the equivalent through the DTL data type, the clock-memory byte, and a cyclic interrupt OB. The two implementations are shown side by side so a controls engineer familiar with one Siemens line can map it to the other.

Critical safety note: On a SINUMERIK, every R-variable from R0 through R99 (and many of the extended range) may already be claimed by the machine tool builder (MTB) for tool-changer logic, pallet changer sequencing, or safety interlocks. Do not write to an R-variable until you have confirmed it is unused on your machine. Use a free, MTB-confirmed address and document the assignment in the program header.

Prerequisites

  • SINUMERIK 810D, 828D, or 840D sl control with SHOPMILL or SHOPTURN option loaded.
  • Operator access to the Offsets > R-variables screen (or equivalent on the HMI version installed).
  • Program directory write access for subprograms (_N_*.SPF) under /_N_WKS_DIR/_N_TEMPLATES_WPD/ or the manufacturer's template directory.
  • Knowledge of which R-variables are reserved by the MTB. Cross-check against the manufacturer's PLC ladder and any MTB-supplied template programs before assigning.

SINUMERIK R-Variable Conventions

R-variables on SINUMERIK are 32-bit signed real numbers (REAL/INT compatible). They retain their last value across program executions and across NC resets until the control is powered down or the value is cleared manually. They are the standard scratchpad for user-level counts, timers and flags.

Variable Direction Typical Use Comment
R0 RW Part count accumulator Often free on basic machines – verify with MTB docs first.
R1 RW Target parts count (setpoint) Operator enters this on the R-variables screen.
R2 RW Running parts count (incremented each cycle) Must be reset to 0 by the operator before a new run.
R3R9 RW User scratchpad Avoid collision with MTB assignments.
R10+ RW Frequently MTB-reserved Do not touch without explicit sign-off.
Format: On the HMI, R-values are displayed as fixed-point real numbers. To enter an integer count, type 5 (the control stores 5.000). Use TRUNC() when you need the integer portion only.

Building a Parts Counter Subprogram

The pattern below creates a standalone subprogram called COUNT that can be invoked at the start of every machining cycle. Each call increments R2 and compares it to the target R1; when the target is reached, the control halts with a clearable message and waits for the operator.

Subprogram: COUNT.SPF

;==========================================
; COUNT.SPF  --  Parts counter subprogram
; Invoke from main with a bare "COUNT" line.
;
; R1 = target parts (operator sets this)
; R2 = running count (operator resets to 0)
;==========================================

IF R2 == R1 GOTOF JOB_COMPLETE      ; if running count has hit target, branch
R2 = R2 + 1                         ; otherwise increment the running count
GOTOF END_COUNT                     ; and exit the subprogram

JOB_COMPLETE:
MSG("PARTS COUNT END")             ; first halt message
M00                                 ; program stop, operator clears
MSG("YOU HAVE REACHED YOUR LIMIT")  ; second halt message after cycle-start
M00                                 ; stop again so operator can acknowledge

END_COUNT:
M17                                 ; end of subprogram, return to caller

Main program wiring

;MPF - Main machining program
COUNT                               ; call the counter sub first thing
T1 D1
M06                                 ; tool change
...machining blocks...
M30                                 ; program end, rewind

Operator workflow

  1. Select Offsets > R-variables.
  2. Set R1 to the desired part quantity.
  3. Set R2 = 0 at the start of a new run.
  4. Run the program. The counter increments once per cycle.
  5. When R2 == R1, the control halts with "PARTS COUNT END".
  6. Press CYCLE START to acknowledge. The second message appears and the control halts again.
  7. To continue a partial run, increment R1 by the remaining quantity and press CYCLE START.

Adding a Cycle Time and Clock Display

SINUMERIK exposes the current cycle time and wall-clock time through system variables. Two useful variables are:

  • $AC_CYCLE_TIME – elapsed time in seconds for the current NC program run.
  • $A_HOUR, $A_MINUTE, $A_SECOND – current shift-clock time read from the controller.

The pattern below builds a stats subprogram that formats minutes/seconds from $AC_CYCLE_TIME and concatenates them with the live wall-clock time. It is designed to be called at the end of a cycle so the message line on the HMI updates after each part.

Subprogram: STATS.SPF

;==========================================
; STATS.SPF  --  Display part count + cycle time + clock
; R0 = part count
; R1 = minutes (integer portion)
; R2 = seconds (integer portion)
; R5 = working value (minutes with fraction)
;==========================================
PROC STATS DISPLOF

N35  R5 = $AC_CYCLE_TIME / 60         ; convert seconds -> minutes
N40  R1 = TRUNC(R5)                   ; integer minutes
N45  R2 = R5 MOD 1                    ; fractional remainder (0..1)
N50  R2 = TRUNC(R2 * 60)              ; convert fraction -> seconds
N55  R0 = R0 + 1                      ; increment part count

N20  MSG("PART COUNT= " << R0 << " : CYCLE TIME= " << R1 << " MINS " << R2 << " SECS : TIME= " << $A_HOUR << ":" << $A_MINUTE)

M17                                   ; return to caller

Triggering the display from the main program

;MPF - last blocks of main program
N230 CALL "/_N_WKS_DIR/_N_TEMPLATES_WPD/_N_STATS_MPF"   ;SM;*RO*
F_END(0,1,5);*RO*
Note on F_END: The F_END(0,1,5) line is a Siemens-specific termination block. The third argument controls reset behavior at end of program. Use the value configured by the MTB or copy from an existing working template to avoid changing the machine's reset semantics.

The same effect for a basic standalone display (no separate subprogram) is achieved with a single line in the program header:

N145 MSG("TIME= " << $A_HOUR << ":" << $A_MINUTE)

This is sufficient when SHOPMILL/SHOPTURN is the active interface and a richer HMI dashboard is not needed.

Formula Reference

Quantity Formula Source
Minutes from seconds R5 = $AC_CYCLE_TIME / 60 Constant 60 s/min
Integer minutes R1 = TRUNC(R5) TRUNC() drops the fraction
Fractional part R2 = R5 MOD 1 MOD returns 0..1
Integer seconds R2 = TRUNC(R2 * 60) Scale fraction to seconds
Part count increment R0 = R0 + 1 Direct addition

Equivalent on SIMATIC S7-1200 / S7-1500

When the same requirement is implemented on a SIMATIC PLC rather than a SINUMERIK, the clock functions are documented in the S7-1200 manual collection. The relevant elements are:

  • DTL (Date and Time Long) – 12-byte structure that holds year, month, day, weekday, hour, minute, second and nanoseconds. Read with RD_SYS_T, set with WR_SYS_T.
  • Clock-memory byte – a configured byte in the CPU properties whose individual bits toggle at fixed frequencies (e.g. 10 Hz, 5 Hz, 2 Hz, 1 Hz, 0.5 Hz). The 1 Hz bit is the canonical "seconds tick".
  • Cyclic interrupt OB (e.g. OB30..OB38) – for deterministic time bases that cannot rely on the main OB1 scan.

Pattern: seconds counter on S7-1200 using the clock-memory byte

// OB1 - count rising edges on MB100 bit 3 (1 Hz, per CPU clock-memory config)
"Counter_DB".SecTickOld := "Counter_DB".SecTick;
"Counter_DB".SecTick    := %MB100.3;             // configured 1 Hz bit
IF "Counter_DB".SecTick AND NOT "Counter_DB".SecTickOld THEN
    "Counter_DB".Seconds := "Counter_DB".Seconds + 1;
    IF "Counter_DB".Seconds >= 60 THEN
        "Counter_DB".Seconds := 0;
        "Counter_DB".Minutes := "Counter_DB".Minutes + 1;
        IF "Counter_DB".Minutes >= 60 THEN
            "Counter_DB".Minutes := 0;
            "Counter_DB".Hours   := "Counter_DB".Hours + 1;
        END_IF;
    END_IF;
END_IF;

Pattern: reading the CPU wall clock via DTL

// Read system clock into a DTL tag
#Now := RD_SYS_T("Now");        // DTL tag of length 12 bytes

// Display fields individually:
#ClockMessage := CONCAT("TIME=", INT_TO_STRING(#Now.HOUR), ":",
                              INT_TO_STRING(#Now.MINUTE), ":",
                              INT_TO_STRING(#Now.SECOND));

Both approaches are documented in the Siemens SiePortal knowledge base: see How can I make the seconds counter (Step 7 TIA)? and Hour counter. For cycle-synchronised counting, a cyclic interrupt OB is preferred over polling the clock bit in OB1 – see Clock Tags, counters and cycle time question.

Mapping Between Platforms

Function SINUMERIK (810D / 828D / 840D sl) SIMATIC S7-1200 / S7-1500
Wall-clock read $A_HOUR, $A_MINUTE, $A_SECOND DTL via RD_SYS_T
Wall-clock write Operator sets on HMI, or via SETTIME WR_SYS_T
Cycle timer $AC_CYCLE_TIME (s, REAL) Custom timer in OB1 / cyclic OB
1 Hz tick Implicit in $AC_TIMER family Clock-memory byte, bit at 1 Hz
Persistent counter R-variable (volatile across power-cycle) DB tag (retentive via "Remain" property)
HMI message MSG("..." << var) HMI tag / alarm via HMI configuration
Program stop M00 Not applicable (PLC continues scan)

Best Practices and Field-Proven Caveats

  • Never assume an R-variable is free. Tool changers, pallet changers, and probing cycles commonly use R10–R70 on machines from multiple builders. Verify with the MTB ladder, the as-shipped template programs, and the machine's PLC project before assigning.
  • Prefer defined variables on 840D sl. Modern SINUMERIK programming guides recommend using named GUD (Global User Data) variables or LUD (Local User Data) instead of bare R-variables, because R-numbers are an unstructured flat namespace that is easy to clash with.
  • Persist the count if you need it across power cycles. R-variables clear on power-down. If a count must survive, store it to a non-volatile NV location ($A_IN[0]$A_IN[9] as setters, or a settable machine data) or use a PLC counter.
  • Keep MSG() calls short. The HMI message bar truncates around 64 characters on older 810D panels. Concatenate only the essential fields.
  • Reset $AC_CYCLE_TIME at the right place. $AC_CYCLE_TIME is reset at program start by default but only if the appropriate machine data is set. If your display always shows the accumulated time of all programs in the NCK, set MD20150 $MC_GCODE_RESET_VALUES for the relevant G-code or reset $AC_CYCLE_TIME explicitly with $AC_CYCLE_TIME = 0 in your startup block.
  • Don't rely on the ISO side if SHOPMILL is loaded. The MSG line for clock display works on both ISO and ShopMill, but parts-counter behaviour (setpoint entry, reset) is significantly smoother on the ShopMill side where soft keys are tailored.

Verification

  1. Load the program with COUNT as the first executable block and run it for at least two cycles. After the first cycle, R2 should read 1.000; after the second, 2.000.
  2. Set R1 = 3 and R2 = 0. Run the program. On the third cycle, the message line must read "PARTS COUNT END" and the spindle must stop (M00 active).
  3. Press CYCLE START. The second message "YOU HAVE REACHED YOUR LIMIT" must appear and the control must stop again.
  4. Change R1 to 5 and confirm that pressing CYCLE START continues the run from the current count.
  5. With STATS.SPF wired in, verify that after each cycle the HMI displays a plausible CYCLE TIME and a live TIME= HH:MM matching the controller clock.
  6. Cross-check the controller's displayed time against an independent reference. If drift exceeds a few seconds per shift, the backup battery on the NCU may need replacement.

Troubleshooting Matrix

Symptom Likely Cause Fix
Counter does not increment Subprogram not saved under SPF extension or wrong directory Save to /_N_WKS_DIR/_N_<workpiece>_WPD/_N_COUNT_SPF and verify with the program manager.
R value shows garbled characters on HMI R-variable overwritten by MTB PLC Stop the test, switch to a confirmed-free R-number, document.
Cycle time always reads zero $AC_CYCLE_TIME reset by program start not enabled in MD Set MD20150 or reset $AC_CYCLE_TIME = 0 in a startup block.
Message line blank after cycle MSG() overwritten by another block Place the MSG in the last executable block before M30.
MSG truncated at 24 chars Old HMI software version Reduce displayed fields or upgrade HMI software.
Second halt message does not appear Operator cleared the first MSG too fast Insert a dwell (G04 F2) or a second explicit M00 before re-issuing MSG.
Clock display off by hours NCK time set to a different time zone Use SETTIME or adjust via HMI Commissioning > Time/Date.

FAQ

Which R-variables are safe to use on a SINUMERIK 810D?

There is no universal answer. Start with R0R9, but always verify against the MTB-supplied PLC project and template programs. If any of those R-numbers is already used, pick the next free number and document the assignment in the program header.

Why does $AC_CYCLE_TIME read zero on the first cycle?

It is reset at the start of each NC program. If your main program calls a subprogram and you read $AC_CYCLE_TIME inside that subprogram before any motion has occurred, the value may briefly read zero. Place the read after the first motion block, or in the cycle-end stats subprogram as shown above.

Can the parts counter survive a power cycle?

Not if it is stored in a plain R-variable – those clear at power-down. Either persist it via a settable machine data, mirror it into a PLC retentive data block, or accept that the count restarts at zero each morning and require the operator to re-enter the remaining quantity.

How do I read the wall-clock time on an S7-1200 instead of a SINUMERIK?

Use the RD_SYS_T instruction in SCL or LAD/FBD to populate a DTL tag, then read .HOUR, .MINUTE, and .SECOND fields directly. See the S7-1200 clock functions reference.

Why use a cyclic interrupt OB for a seconds counter on S7-1200?

The clock-memory byte polls in OB1 only when OB1 finishes its scan. If the main OB scan time exceeds 1 s, you can miss a 1 Hz tick. A cyclic interrupt OB at e.g. 100 ms gives a deterministic read and avoids drift. Details are in the Siemens SiePortal thread Clock Tags, counters and cycle time question.

Back to blog