Siemens FB100 Totalizer in STEP 7 5.5: Drift, LREAL, Pulse Method

David Krause12 min read
S7-300SiemensTechnical 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

1. Overview

Siemens FB100 "Totalizer" from the standard library is one of the most commonly requested blocks for S7-300/S7-400 programs written in STEP 7 V5.5 (and earlier). It is invoked from OB1 or, more typically, from a cyclic interrupt such as OB35 to integrate an instantaneous flow rate (m³/h, L/min, kg/h) into a running total (m³, L, kg). Field experience shows that this block, when fed from an analog flow input, drifts by 10-15% within 30-40 days of continuous operation. This article explains why the drift occurs, why no amount of analog-based "Totalizer" FB tuning will eliminate it, and how to implement either an LREAL 64-bit version or, preferably, a pulse-input totalizer that is exact by construction.

Engineering rule: A flow meter has a digital pulse output for a reason. Any analog-based integrator is fundamentally a numerical estimate; only a pulse counter is a true totalizer.

2. FB100 "Totalizer" - Block Mechanics

The FB100 Totalizer is delivered with the STEP 7 V5.5 standard library Standard Library > TI-S7 Converting Blocks (catalog name varies by service pack) and with the older stdlibs CD. The block multiplies the instantaneous input by the OB scan time and adds the result to a running accumulator.

Parameter Type Direction Meaning
AI_IN REAL (32-bit) IN Instantaneous flow, engineering units (e.g. m³/h)
TI TIME / S5TIME IN OB35 cycle time (default 100 ms)
CV REAL OUT Accumulated total
RESET BOOL IN Reset to zero
QERROR BOOL OUT Overflow / error flag

Internally the integration is essentially:

CV := CV + (AI_IN * TI)
// where TI is converted to hours

Both AI_IN and CV are stored as REAL (32-bit IEEE-754 single precision), giving approximately 7 significant decimal digits of mantissa. The flow range of any real-world process (e.g. 0.05 to 250 m³/h integrated over weeks) easily exceeds that precision window.

3. Why Analog Totalization Drifts - The Floating-Point Root Cause

Field reports match published Siemens support material: integrating a small REAL (flow rate) into a large REAL (totalizer) repeatedly creates rounding loss because the relative magnitude of the addend shrinks as the totalizer grows. The classic example:

Step CV (REAL, 32-bit) Addend Operation Effective resolution
Day 1 0.00 m³ 0.0014 m³ (100 ms @ 50 L/h) 0.0014 ~1e-7 m³ (OK)
Day 10 ~120 m³ 0.0014 m³ 120.0014 ~1e-5 m³ (degraded)
Day 40 ~480 m³ 0.0014 m³ 480.0014 ~1e-4 m³ (lost!)

After about a month, the 32-bit mantissa cannot represent the 0.0014 m³ increment against the 480 m³ running total. Each scan either drops the increment entirely or rounds it to zero, producing the reported 10-15% loss versus the meter's mechanical register. This is not a bug in FB100; it is a property of IEEE-754 single precision documented in the Siemens KB article on floating-point arithmetic accuracy: Entry ID 14844391 - Accuracy of floating-point arithmetic in S7-300/S7-400.

Even extending the totalizer with DINT (32-bit integer m³ × 1000) and adding LREAL only delays the inevitable; the analog input still carries the noise, scaling error, and ADC quantization that the pulse counter avoids entirely.

4. LREAL (64-Bit Real) Library for S7-300/S7-400

STEP 7 V5.5 supports the LREAL (64-bit IEEE-754 double precision, ~15-17 significant digits) data type on S7-300 CPUs with firmware ≥ V2.x and on all S7-400 CPUs. The Siemens-contributed library of LREAL arithmetic functions (add, subtract, multiply, divide, compare, conversion to/from REAL) is published on the Siemens Support forum entry "Using Double Float (64-bit Real) in S7-300/400 Library with Functions" and is the canonical extension for any totalizer that must remain analog-driven. Key functions:

FC Function Comment
FC101 LREAL_ADD CV_LR := CV_LR + (AI_LR * TI_LR)
FC102 LREAL_SUB Decrement / preset
FC103 LREAL_MUL Scale raw integer to LREAL flow
FC104 LREAL_DIV Average / rate
FC110 LREAL_TO_REAL Display conversion only
FC111 REAL_TO_LREAL ADC input conversion

An LREAL-based totalizer in OB35 reduces drift from ~1 part in 10⁴ to ~1 part in 10¹⁵ at the same data rate - effectively drift-free for any practical plant life. However, the analog noise remains; use LREAL when you have no pulse output, not because it is "more accurate" than a counter.

5. Pulse-Based Totalization - The Only Exact Method

Every modern flow meter (electromagnetic, vortex, Coriolis, turbine, ultrasonic) offers a scaled digital pulse output - typically one pulse per litre, per 0.1 m³, per kg, or per gallon. The meter's own register is driven by the same pulse train, so the PLC totalizer will agree with the meter to within one pulse, by definition. The required S7-300 hardware is one digital input module (SM321 DI32 or DI16 × DC24V); no analog scaling required.

5.1 Pulse Counter Hardware Configuration

On S7-300, use the FM350-1 / FM350-2 counter modules or, more commonly, the integrated CPU 31xC fast counters:

  • CPU 312C / 313C / 313C-2 PtP / 314C-2 PtP: 4 built-in counters, 10 kHz max.
  • CPU 31x-2 PN/DP (V3.x and later): none integrated; use FM350-1.

For S7-400 use FM450-1 (8 channels, 100 kHz) or the IM178-4 high-speed module. Always terminate the pulse line through the meter's recommended pull-up/down resistor (typically 1-2.2 kΩ to +24 V for an open-collector output).

5.2 Pulse to Engineering Units

Define the meter's pulse weight at the HMI/parameter level, not hard-coded in the FB. A typical configuration block (DB100) for OB1 initialization:

DATA_BLOCK DB100
STRUCT
  PulseWeight : REAL := 0.001;  // 1 pulse = 0.001 m³ (1 L)
  Total_m3    : LREAL;          // accumulated volume
  Pulses_raw  : DINT;           // raw counter from FM350 / DI
  Reset_cmd   : BOOL;
END_STRUCT
END_DATA_BLOCK

5.3 The Integration Network (OB35, 100 ms)

// Network 1: Read counter
     L     "DI_Counter".Pulses_raw          // MD100 - actual counter
     T     DB100.DBD   8                    // mirror to DB100.Pulses_raw

// Network 2: Compute delta pulses this scan
     L     DB100.DBD   8                    // pulses_now
     L     DB100.DBD  12                    // pulses_last
     -I                                    // delta = now - last
     T     #delta_pulses                    // INT scratch
     L     DB100.DBD   8
     T     DB100.DBD  12                    // update last

// Network 3: LREAL accumulation
     L     #delta_pulses
     DTR                                    // DINT -> REAL
     L     DB100.PulseWeight                // REAL
     *R
     DTR                                    // already REAL; repeat-safe
     L     DB100.Total_m3.LB0                // load low word of LREAL
     // (call FC101 LREAL_ADD here from the 64-bit library)
     CALL FC 101
       IN1   := DB100.Total_m3
       IN2   := #inc_LREAL
       OUT   := DB100.Total_m3

For a DINT-only implementation (preferred for absolute minimum drift), store the total in m³ × 1000:

// Per scan: Total_dL := Total_dL + delta_pulses * (PulseWeight * 1000)
// PulseWeight = 0.001 m³ -> PulseWeight*1000 = 1 dL/pulse
// => Total_dL := Total_dL + delta_pulses   // pure DINT addition, no FP

This DINT counter is exact for ~24 days at 1 L/pulse and 1 Hz flow; for longer campaigns, add a high-word rollover using two DINTs (low / high 32 bits = 64-bit total in dL).

6. OB35 Cycle Time and Sampling Theory

OB35 default cycle is 100 ms on both S7-300 and S7-400 and is configurable in HW Config → CPU Properties → Cyclic Interrupts from 1 ms to 60 000 ms. Trade-offs:

OB35 period Pulse-resolution loss at 10 kHz input CPU load contribution Recommended use
10 ms 0.01% High Batch / fast dosing
100 ms (default) 0.1% Moderate Plant totalizers
1000 ms 1.0% Low Utility / non-critical

For pulse counting in OB35, prefer the absolute delta-pulses approach (Section 5.3) over simple "count since last scan", because OB35 can be delayed by higher-priority OBs (OB82, OB121, OB122). Always read the counter from the FM350 hardware image rather than from a software flag.

7. Step-by-Step LAD Implementation (STEP 7 V5.5)

Prerequisites

  • STEP 7 V5.5 + SP4 or later
  • S7-300 CPU 31x-2 PN/DP or S7-400 CPU 41x
  • FM350-1 counter module (or DI module + pulse meter with 24 V OC output)
  • Siemens LREAL library (download from Siemens Support, copy FC101-FC112 into your S7 program)

Step 1 - Hardware Configuration

  1. Open HW Config, insert FM350-1 in the slot next to the CPU.
  2. Set channel 0 to continuous counting, 32-bit, gate always open.
  3. Set the output value address, e.g. PQW 304 (DO load value) and PIW 304 (DI actual value).

Step 2 - Create the Instance DB

DATA_BLOCK DB100 "TotData"  // Shared DB
  PulseWeight  : REAL  := 0.001;   // m³ / pulse
  Total_m3     : LREAL;            // LREAL accumulator
  Total_dL     : DINT;             // integer accumulator (backup)
  Pulses_now   : DINT;             // last raw count
  Pulses_last  : DINT;
END_DATA_BLOCK

Step 3 - OB35 Network 1: Read raw counter

|    L     PIW 304                // low word
|    L     PIW 306                // high word
|    T     MD    100              // store as DINT in flags

Step 4 - OB35 Network 2: Compute delta

|    L     MD    100              // pulses_now
|    L     DB100.DBD  12          // pulses_last
|    -I
|    T     MW    104              // delta this scan
|    L     MD    100
|    T     DB100.DBD  12          // update pulses_last

Step 5 - OB35 Network 3: DINT accumulator (primary)

|    L     MW    104              // delta (pulse count)
|    L     DB100.DBD   0          // not used - pulse weight is unitless
|    // Assuming pulse weight = 1 L/pulse, delta is direct in L
|    L     DB100.DBD  16          // Total_dL
|    +I
|    T     DB100.DBD  16          // Total_dL := Total_dL + delta

Step 6 - OB35 Network 4: LREAL accumulator (for HMI display)

|    CALL FC 101
|      IN1 := DB100.Total_m3
|      IN2 := #inc_LREAL            // delta * PulseWeight, as LREAL
|      OUT := DB100.Total_m3

Step 7 - WinCC / HMI Tag

Expose DB100.Total_dL and DB100.Total_m3 to WinCC as integer and floating-point tags. Use scaling on the integer tag: 0.001 m³/dL.

8. Verification Procedure

  1. Force DB100.Reset_cmd := TRUE for one OB35 scan; verify both totals return to 0.
  2. Inject a known pulse burst from a signal generator (e.g. 1000 pulses at 100 Hz, weight = 0.001 m³) and confirm both Total_dL = 1000 and Total_m3 = 1.000.
  3. Run 24 h with the meter on a closed loop; compare PLC total to the meter's mechanical register - they must agree to within ±1 pulse.
  4. For analog/LREAL validation, compare against the pulse totalizer and graph the residual over 72 h. Residual must be flat or slowly diverging at <0.01% per week, not the 10-15% per month reported for FB100.

9. Method Comparison

Criterion FB100 (REAL) LREAL integrator Pulse + DINT Pulse + LREAL
Drift over 30 days 10-15% <0.001% ±1 pulse ±1 pulse
Hardware required AI module AI module DI / FM350 DI / FM350
Resolution ADC limited ADC limited 1 pulse 1 pulse
Susceptible to noise Yes Yes No No
CPU load Low Moderate Very low Moderate
Code complexity Lowest Medium Low Medium
Recommended for new projects No Only if meter has no pulse output Yes (default) Yes

10. Troubleshooting Matrix

Symptom Likely cause Fix
Totalizer reads 0 after power cycle CV stored only in M/DB volatile area; not retentive Mark CV as retentive in DB properties, or use NVRAM / recipe backup
Reading 10-15% low after 30+ days REAL precision loss (Section 3) Switch to LREAL or pulse counter
Reading 10-15% high after 30+ days OB35 overrun: same scan processed twice because of time-jitter, or AI scaling reversed Verify OB35 phase offset, check AI sign; add OB35 monitor DB to log period
Totalizer jumps at OB35 entry AI value not refreshed; using process image from OB1 Move AI read into OB35 itself, or use direct peripheral access L PIW ...
Totalizer increments once per OB35 scan instead of proportionally TI parameter left at default S5TIME constant; OB35 period mismatch Pass OB35's OB35_TIME (local temp, byte 6) to TI input
Totalizer saturates at 3.4E38 (REAL max) Long-term accumulation overflowing REAL Divide by 1000 every 100 m³, or move to LREAL
QERROR = TRUE immediately AI input underflow/overflow Check wire break / over-range diagnostic on AI module
Pulse counter loses pulses above 1 kHz DI input filter active (default 6 ms) Disable input filter or use FM350-1
Pulse counter counts noise spikes Open-collector output not pulled up Install 1-2.2 kΩ pull-up to +24 V; shield cable

11. Specifications & Limits Reference

Item Value Source
REAL (32-bit) mantissa precision 23 bits ≈ 7 decimal digits Siemens KB 14844391
LREAL (64-bit) mantissa precision 52 bits ≈ 15-17 decimal digits IEEE-754-2008
DINT range -2 147 483 648 to +2 147 483 647 STEP 7 V5.5 manual
CPU 31xC fast counter max frequency 10 kHz (DI built-in) CPU 31xC manual, chapter "Counting"
FM350-1 counter max frequency 500 kHz (5 V) / 200 kHz (24 V) FM350-1 manual
OB35 minimum period 1 ms S7-300 CPU manual
OB35 default period 100 ms HW Config default
FB100 location Standard Library → TI-S7 Converting Blocks → FB100 STEP 7 V5.5 stdlibs

12. Field-Commissioning Checklist

  • □ Confirm the meter has a pulse output and the weight (e.g. 1 pulse / L) is documented.
  • □ Wire the pulse output through a shielded twisted pair; terminate with the recommended pull-up.
  • □ Configure the DI / FM350-1 channel in HW Config and download hardware.
  • □ Insert DB100 (TotData) and verify all tag addresses against the symbol table.
  • □ Insert FC101-FC112 (LREAL library) into the S7 program blocks.
  • □ Replace any call to FB100 with the new pulse-counter network.
  • □ Force a reset, generate a 1000-pulse test burst, verify totals.
  • □ Run for 24 h against the meter register; record residual.
  • □ Document the pulse weight and OB35 period in the loop drawing and HMI tag list.
  • □ Mark DB100 as retentive and verify after power-cycle that the total is preserved.

13. Frequently Asked Questions

Why does Siemens FB100 lose 10-15% of total after a month?

Because FB100 integrates a 32-bit REAL flow into a 32-bit REAL total. As the total grows, the per-scan increment becomes smaller than the mantissa resolution and is rounded away. The drift is exponential and unavoidable for any 32-bit integrator; see Siemens KB 14844391 for the math.

Where can I download FB100 Totalizer for STEP 7 V5.5?

FB100 ships with every STEP 7 V5.5 installation under Standard Library → TI-S7 Converting Blocks. If it is missing, reinstall STEP 7 and select "Standard Libraries" or restore from the Stdlibs CD. The 64-bit LREAL companion library is on Siemens Support (entry "Using Double Float (64-bit Real) in S7-300/400 Library with Functions").

Can I keep FB100 and just switch to LREAL?

Yes, but you must replace FB100 with an LREAL-aware integrator (FC101 from the LREAL library) and convert the analog input from REAL to LREAL with FC111. Drifting drops below 0.001% per month, but analog noise remains. Pulse counting is still preferred.

What is the fastest pulse input the CPU 31xC can count?

10 kHz on the built-in fast counters of CPU 312C / 313C / 314C-2. For higher rates use FM350-1 (200-500 kHz) or FM450-1 on S7-400. Disable the DI input filter in HW Config for any pulse above 100 Hz.

Which OB should call the totalizer?

OB35 (cyclic interrupt) is standard. Use OB32 for 500 ms, OB33 for 200 ms, OB34 for 50 ms, OB35 for 100 ms, OB36 for 20 ms, OB37 for 10 ms, OB38 for 5 ms - all configurable in HW Config. Time-jitter on OB35 is acceptable for pulse counting because the integrator uses an absolute counter snapshot, not a fixed-period assumption.

How do I make the totalizer retentive across power-cycle?

Open DB100 in STEP 7, right-click each tag (PulseWeight, Total_m3, Total_dL, Pulses_last) and enable Non-Retain → Retain, OR enable retain on the entire DB. S7-300 stores retentive data in NVRAM (limited to ~512 bytes total - check your CPU manual). For larger DBs, back up to MMC and reload on startup from a recipe.

Back to blog