Persisting S7-1200 Counter Values in KTP400 HMI Recipes

David Krause17 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

Persisting S7-1200 Counter Values in KTP400 HMI Recipes

Overview

This article documents a field-proven pattern for storing the current value (CV) of an IEC counter running on a SIMATIC S7-1211C CPU in a recipe on a KTP400 Basic HMI, then reloading that value on demand so the counter resumes from its last persisted count rather than restarting at zero. The pattern combines a PLC-side data block, a TIA Portal recipe definition, the system functions getDataRecordRecipe and setDataRecordRecipe, and a deliberate Retain configuration on the counter instance DB.

The original failure mode is a counter that starts at 0 every cycle even after a MOVE block has copied the CV into a recipe element and the recipe has been reloaded. The investigation shows that the counter instance's Retain attribute, not the MOVE block, is overwriting the freshly loaded recipe value. Disabling retain on the counter and routing CV through a recipe element fixes the issue. The remainder of this article formalizes the pattern so the same trap does not have to be rediscovered on every new station.

Prerequisites

  • CPU: SIMATIC S7-1211C DC/DC/DC (or DC/DC/Rly) with firmware V4.2 or higher. The IEC counter functions (CTU, CTD, CTUD) and the work memory and instruction support needed are present from firmware V4.0 onward; V4.2 is the minimum baseline used in current TIA Portal V17+ projects. Reference: SIMATIC S7-1200 Programmable Controller System Manual.
  • HMI: SIMATIC KTP400 Basic (6AV2 123-2DB03-0AX0 or current equivalent), PROFINET-connected to the S7-1200, configured in TIA Portal.
  • Software: TIA Portal V16 or later with the STEP 7 Basic and WinCC Basic (or Comfort) options. Recipes are configured in the HMI project tree under Recipes.
  • PLC tags: Recipe elements must be HMI tags (internal) or PLC tags reachable from the HMI over the configured connection. Indirect tag addressing from a recipe is not supported on Basic panels.
  • Network: CPU and panel on the same PROFINET subnet; the HMI must be the only station issuing getDataRecordRecipe / setDataRecordRecipe at a given moment to avoid collisions.

System Architecture

The PLC owns the live counter; the HMI owns the recipe definition and the file storage on its internal flash or external media. The MOVE blocks on the PLC side are the bridge that lets a single HMI recipe element (for example, CurrentCount) drive the counter's CV.

[S7-1211C] --PROFINET--> [KTP400 Basic] --USB/SD--> [External recipe file (*.csv/.txt/*.rdf)]
   |                           |
   |  Instance DB (Counter)    |  Recipe: CounterRecipe
   |   - CV (INT/DINT)         |    - Elements: TargetCount, CurrentCount, BarcodeString, LabelName
   |   - CU, CD, R, LD         |  Data records (1..n): one per SKU/operator
   |                           |
   +--- Recipe DB (Global) <---+  (counter CV routed through MOVE blocks)

Counter Configuration in the S7-1200

Use an IEC counter from the Instructions task card, Basic Instructions > Counter operations. The recommended block is CTUD (count up/down) for barcode-driven applications where the operator can correct a wrong scan by decrementing.

  1. Add a counter instance DB (for example, iCtr_ScanCount) in the PLC program. Do not place the counter in the default Counter instance DB if you intend to control its retain attribute precisely; place it in a project-side FB instance or in a global DB with an IEC_Counter instance.
  2. Open the instance DB and select the Counter structure (or the CTUD block itself if used as a multi-instance). In the Properties of the counter tag, locate the Retain column for the CV field and any other fields you want cleared on restart.
  3. Uncheck Retain for the CV field. The user-found fix hinges on this: if the counter is retainful, the PLC restores the old CV on warm restart, overwriting the value you just MOVEd in from the recipe. The recipe must be the only source of truth.
  4. CU (count up), CD (count down), R (reset), and LD (load) are wired as normal. The barcode OK signal pulses CU; the operator's decrement button pulses CD. R should be asserted only when the operator explicitly wants to zero the counter and overwrite the recipe.
  5. The CV is INT by default for a single-instance CTU/CTD. For CTUD or when the count may exceed 32,767, set the counter type to DINT in the Properties > Counter page.

Recipe Configuration in TIA Portal

A recipe in TIA Portal is a named container of elements (each mapped to a tag) plus a list of data records (the per-SKU values). The recipe itself is stored in the project; the data records are stored on the panel's internal flash or on removable media.

  1. In the project tree, expand your HMI device (KTP400 Basic) and open Recipes.
  2. Right-click Recipes and choose Add new recipe. Name it, for example, CounterRecipe.
  3. Add elements:
    • TargetCount (INT/DINT) — the maximum count the operator configured.
    • CurrentCount (DINT) — the live value; must match the counter CV type.
    • BarcodeString (WSTRING[64]) — the scan pattern this record is for.
    • LabelName (WSTRING[32]) — the human-readable label to print.
  4. For each element, set the tag source to a PLC tag. Ensure the tag exists in the PLC and is visible on the HMI connection. Recipe element tags can be located in a global DB or in a dedicated recipe DB.
  5. Under Data records, add one record per SKU. Populate the static values (TargetCount, BarcodeString, LabelName) in the engineering view. CurrentCount is intentionally not filled in engineering; it is written at runtime via setDataRecordRecipe after each successful scan, and read back at startup via getDataRecordRecipe.

Reference: SIMATIC WinCC Recipes Programming and Operating Manual (TIA Portal). For cross-platform comparison, the same concept on Beckhoff TwinCAT 3 is documented at Object Recipe Manager — Beckhoff Information System; the underlying idea — a named container of tag-mapped elements with persistence to storage — is identical, only the system function names differ.

PLC Program Structure

The PLC side is intentionally small. All recipe loading and saving is initiated by the HMI through getDataRecordRecipe and setDataRecordRecipe; the PLC merely hosts the tags and the counter.

Tag Container (Global DB dbRecipe)

DATA_BLOCK "dbRecipe"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
  STRUCT
    TargetCount   : DINT;       // matches recipe element TargetCount
    CurrentCount  : DINT;       // matches recipe element CurrentCount
    BarcodeString : WSTRING[64];
    LabelName     : WSTRING[32];
  END_STRUCT;
END_DATA_BLOCK

Counter Logic (SCL)

// Load phase: HMI presses "Load Recipe" -> PLC tag xLoadRecipe pulses TRUE
// We MOVE the recipe CurrentCount into the counter CV exactly once, on the rising edge.
IF "xLoadRecipe" AND NOT "xLoadRecipe_Old" THEN
    "iCtr_ScanCount".CV := "dbRecipe".CurrentCount;
END_IF;
"xLoadRecipe_Old" := "xLoadRecipe";

// Save phase: HMI presses "Save Recipe" -> PLC tag xSaveRecipe pulses TRUE
IF "xSaveRecipe" AND NOT "xSaveRecipe_Old" THEN
    "dbRecipe".CurrentCount := "iCtr_ScanCount".CV;
END_IF;
"xSaveRecipe_Old" := "xSaveRecipe";

// Count up on barcode OK
IF "xBarcodeOK" AND NOT "xBarcodeOK_Old" THEN
    "iCtr_ScanCount".CU := TRUE;        // pulse
END_IF;
"xBarcodeOK_Old" := "xBarcodeOK";
"iCtr_ScanCount".CU := FALSE;

The two edge-detection latches are the critical detail. Without them, the MOVE in the load phase keeps re-executing and re-asserting the value, which is harmless here but, combined with the recipe element being a PLC tag, masks whether the recipe is actually being read.

HMI Configuration

Buttons and Events

On the KTP400 Basic screen, configure two buttons:

  • Load Recipe — Press event uses the system function getDataRecordRecipe. Parameter: recipe name = CounterRecipe, data record number = the operator's selection from a recipe view control.
  • Save Recipe — Press event uses setDataRecordRecipe with the same parameters.

Place a Recipe View control on the screen. The recipe view shows the selected data record's elements and lets the operator edit them. On Basic panels the recipe view must be configured with a single fixed recipe; switching recipes requires a screen change or a SetRecipe system call.

I/O Fields for the Counter Live Value

Add an I/O field bound to "iCtr_ScanCount".CV (process tag) for the live read-out. Add another I/O field bound to "dbRecipe".CurrentCount (HMI tag with PLC connection) to show what the recipe believes the count is. If the two values ever diverge outside a load/save window, the retain attribute is misconfigured.

System Function Blocks

Function Purpose When to Call
getDataRecordRecipe Read a data record from panel storage into the connected tags Operator selects a record and presses Load
setDataRecordRecipe Write the current tag values back to the data record on the panel Operator presses Save (manual) or after each successful count (auto)
LoadDataRecord Reads a data record from external storage into panel-internal storage On startup if the active record should be the last used one
ExportDataRecords / ImportDataRecords CSV/RDF exchange for backup and engineering Optional, for traceability

The get/set functions operate on the panel-internal representation; the LoadDataRecord / ExportDataRecords functions are the boundary to the *.csv file on the SD card. Reference: SIMATIC WinCC Recipes Programming Manual (TIA Portal).

The Retain Pitfall

The single most common reason a recipe-loaded counter "starts from 0" is retainful counter instance data. The PLC boot sequence is:

  1. Power on / restart.
  2. Retentive tags are restored to their last values from the retentive memory area.
  3. Startup OB executes.
  4. The HMI initializes and runs its startup screen.

If the counter's CV is retainful, step 2 reasserts the last PLC-side CV, which may be 0 if the PLC was last online without the recipe having been saved. The HMI's getDataRecordRecipe event fires after the HMI initializes, but by that time the counter has already been set, and the MOVE block from dbRecipe.CurrentCount into the counter runs only when the operator presses Load. Until the operator presses Load, the retainful CV wins.

Disabling retain on the counter's CV field forces the counter to start at 0 on every restart, making the recipe the only path to a non-zero value. This is the field-proven configuration that resolved the original issue.

Setting Counter behavior at restart Recipe load behavior
Retain = TRUE on CV Restores last PLC value (possibly 0 or stale) Recipe is loaded but may be immediately overwritten by retain value on next restart
Retain = FALSE on CV Starts at 0 Recipe value is the authoritative source after load
Do not confuse the retain setting on the counter instance DB with the retain setting on the dbRecipe global DB. The counter instance should have CV retain = FALSE; the recipe DB should have retain = TRUE so the PLC holds the last recipe values across a panel outage. The two settings work together, they do not substitute for each other.

Step-by-Step Implementation

  1. Create the counter instance. In the S7-1211C program, add a CTUD with an instance DB. In the instance DB properties, uncheck Retain for CV.
  2. Create the recipe tag container DB. Add a global DB (dbRecipe) with tags TargetCount, CurrentCount, BarcodeString, LabelName matching the recipe element list. Retain on the DB is optional; if retain is enabled, the PLC holds the last value even if the panel is offline, which is usually desired.
  3. Define the recipe in the HMI project. Add the recipe CounterRecipe and its four elements, each pointing to the matching PLC tag. Add the data records.
  4. Wire the PLC MOVE blocks. In OB1 (or a dedicated FB), implement the load/save edge-triggered MOVE between dbRecipe.CurrentCount and the counter's CV, as in the SCL snippet above.
  5. Add the HMI buttons. Configure Load and Save with the system functions getDataRecordRecipe and setDataRecordRecipe.
  6. Add a recipe view. Drop a recipe view control on the screen, bound to CounterRecipe. Configure the columns and editability.
  7. Add a recipe selection control (optional). A drop-down list driven by the recipe's data record names lets the operator pick a record by SKU.
  8. Compile and download. Compile the PLC project and the HMI project. Download the PLC program first, then the HMI.
  9. Verify the connection. In the HMI's Connections editor, run a Diagnostics test to confirm all recipe element tags resolve and are not greyed out.

Verification and Commissioning

A signed-off recipe-counter loop is verified in this order:

  1. Static read test. With the PLC in STOP, change a recipe element value in the HMI's recipe view and press Save. Start the PLC. The HMI's I/O field for dbRecipe.CurrentCount should show the saved value.
  2. Load-to-counter test. Press Load. The counter's CV I/O field on the HMI should jump from 0 to the saved CurrentCount. Pulse the barcode input a few times; the counter increments from the loaded value, not from 0.
  3. Counter-to-recipe test. Manually increment the counter using the I/O field on the HMI (or by pulsing CU). Press Save. Power cycle the entire station. Press Load again. The counter must resume from the last saved value.
  4. Retain test. Power cycle only the HMI (not the PLC). Press Load; the counter should not be re-zeroed by the PLC retain, because retain is off. Power cycle the PLC; counter starts at 0; press Load; counter jumps to the recipe value.
  5. Data record count test. Add a second data record with a different BarcodeString and CurrentCount. Switch between record 1 and record 2 using the recipe view selection; verify each press of Load moves the counter to the right value.

Troubleshooting Matrix

Symptom Likely Cause Diagnostic Fix
Counter starts at 0 even after Load Retain is enabled on counter CV Open counter instance DB, check Retain column on CV Uncheck Retain for CV
Load button does nothing Tag connection is broken or recipe element points to a non-existent tag Open the HMI Connections editor; check for warnings on recipe elements Re-bind the element to a valid PLC tag and recompile
Save appears to succeed but the value resets on restart Data record stored on removable media that was ejected Check the Storage location of the recipe; verify SD card presence Set storage to Internal Flash or insert the media before save
Recipe view shows no records No data records defined in engineering Open the recipe in the project tree, check Data records Add at least one data record with valid element values
MOVE block errors with "Type mismatch" Counter CV type (INT) does not match recipe element type (DINT) Hover over the MOVE block; check the data type LEDs Change counter to DINT or change recipe element to INT
Counter overflows at 32767 CTU is INT-typed, count exceeded 16-bit limit Observe CV in the watch table Change counter to DINT or reset before the limit
Operator edits a value in recipe view but it is overwritten on next save Save is auto-fired by the HMI after each load, or operator pressed Save before editing Inspect the Save button event and the Recipe View configuration Remove automatic save, or sequence Load → Edit → Save explicitly
Recipe view columns are greyed out Element tag is not configured as read/write on the HMI connection Open HMI tags, check the Access column Change access from read-only to read/write
Data record save returns an error code (e.g., 0x8004xxxx) Storage path does not exist or is write-protected Check the HMI's Recipe Properties > Storage Location Switch to Internal Flash or remount the SD card

Performance and Timing Notes

  • getDataRecordRecipe and setDataRecordRecipe on a Basic panel block the HMI task for the duration of the SD/flash write. For a 4-element recipe of 64-byte strings and DINTs, the operation completes in single-digit milliseconds on internal flash and 30–50 ms on SD card. This is fast enough to call on every successful barcode event.
  • If the operator scans faster than the panel can save, queue the saves or move to a Comfort panel with a faster processor. The S7-1211C is not the bottleneck; the KTP400 storage subsystem is.
  • For high-speed applications, set the recipe storage to Internal Flash and avoid the SD card. The SD card has additional wear concerns when the recipe is saved once per scan.
  • The 1211C's OB1 cycle time is dominated by the MOVE blocks; on a 1211C, two edge-triggered MOVEs plus one CTUD add under 50 µs to a typical 1–2 ms cycle. Negligible.

S7-1211C-Specific Considerations

  • The 1211C has 50 KB of work memory and 1 MB of load memory. Each IEC counter consumes a small amount of program and data memory. With 32 counters (the realistic upper bound for this kind of multi-SKU station), total program size stays well within limits.
  • The 1211C has 4 KB of bit memory and 2 KB of retentive memory. The recipe tag DB dbRecipe consumes retentive memory only if the DB is set retainful; if it is, budget ~120 bytes per record-equivalent of structure for the four DINT/WSTRING fields. A 4-SKU station with one shared DB consumes under 500 bytes of retentive memory — negligible.
  • The CPU's high-speed counters (3 HSC on the 1211C) are an alternative to software CTU/CTUD when the count rate exceeds 1 kHz. The HSC's CV is also a 32-bit integer accessible as an I/O address; it can be used as a recipe element target just as easily. HSC CV is not retainful by default, so the same retain pitfall does not apply.
  • On 1211C firmware V4.2 and earlier, the IEC counter instance DB does not expose the Retain column for individual fields in the same way as V4.4+. The recipe pattern still works, but retain is controlled at the instance DB level. Reference: S7-1200 System Manual, chapter on IEC counters.

KTP400 Basic-Specific Considerations

  • The KTP400 Basic supports recipes on PROFINET, PROFIBUS, MPI, and PPI; recipe data transfer to PLC is protocol-agnostic.
  • Maximum recipe data records per recipe: limited by storage, typically several hundred for short recipes.
  • Basic panels do not support the Recipe View control with full editability for WSTRING elements longer than 32 characters. Split long barcode strings into two elements or use a Comfort panel.
  • The KTP400 Basic runs WinCC Basic, which uses the same getDataRecordRecipe and setDataRecordRecipe function IDs as WinCC Comfort.
  • On a KTP400 Basic with internal flash of ~4 MB usable for recipes, a 4-element recipe of 100 bytes per record uses 10 kB per 100 records — capacity is not the constraint.

Related Patterns

  • Cyclic save on increment: Wire xSaveRecipe to the rising edge of CU instead of a button. This guarantees the recipe is always current at the cost of more flash writes.
  • Multiple counters, one recipe: Define the recipe with N×4 elements (TargetCount, CurrentCount, BarcodeString, LabelName per counter). Use a multi-instance array in the PLC to scale.
  • Audit trail: Enable the Data record log option on the recipe to write each change with a timestamp. This requires a Comfort panel and a properly set panel time.
  • Multi-panel recipes: Multiple KTP400 Basic panels sharing a single PLC: define one recipe per panel to keep the data record namespace separate. The PLC holds the merged tag DB.

Safety and Data Integrity

  • Recipe saves are not transactional with respect to the counter increment. If the panel loses power between an increment and the next auto-save, the last count is lost. Mitigate by saving on every increment, or by holding the unsaved count in a retainful dbRecipe DB on the PLC side and saving less aggressively to the panel.
  • On the KTP400 Basic, the panel's internal flash has a finite write endurance (~100,000 cycles per sector). Saving on every increment with a high scan rate can wear the sector. Consider a Comfort panel for write-heavy applications.
  • The barcode validation must reject duplicates and invalid patterns before pulsing CU; an erroneously counted scan is persisted in the recipe, and the only way to fix it is a manual decrement + save.
  • The counter instance must never be declared as a multi-instance in a retainful FB with Retain = TRUE at the FB level. The retain attribute on the counter's CV field is overridden by the FB-level retain if the FB is retainful. This is a second, less obvious retain pitfall.

FAQ

Why does the counter start at 0 every time even though I am loading the recipe?

The counter instance DB's CV field is marked retentive. On PLC warm restart the CPU restores the old CV (often 0) before the HMI's getDataRecordRecipe event fires, so the recipe value never makes it into the counter. Open the counter instance DB and uncheck Retain for CV; this makes the recipe the only source of truth.

What is the difference between getDataRecordRecipe and LoadDataRecord on a KTP400 Basic?

getDataRecordRecipe copies a data record from the panel's internal storage into the connected tags. LoadDataRecord reads a data record from external media (SD card) into the panel's internal storage. The two functions are typically chained: LoadDataRecord on startup, then getDataRecordRecipe on operator demand.

Can I use a Siemens LOGO! or S7-200 with the same recipe pattern?

No. The recipe concept with getDataRecordRecipe/setDataRecordRecipe is part of WinCC Basic/Comfort/Advanced and requires an HMI with that runtime. LOGO! and the S7-200 Smart line use simpler data block transfer, not the WinCC recipe system. For the same pattern, pair a WinCC runtime HMI (Basic or Comfort) with an S7-1200/1500 CPU.

Should the recipe tag DB on the PLC side be retentive?

Yes, in most cases. Retentive on the DB ensures the PLC holds the last recipe values even if the panel is offline or being replaced. Retain on the DB is independent of retain on the counter instance; the retainful DB stores the last loaded values, the non-retainful counter is initialized from the DB on each restart.

My recipe view shows the data records but I cannot edit the CurrentCount field. Why?

Either the element is set to read-only in the recipe view configuration, or the HMI tag is not configured as read/write. Open the recipe view's column settings and enable editing for the CurrentCount column; if the field is still locked, verify the underlying PLC tag is mapped to an HMI tag with read/write access.

Back to blog