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.
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.
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
- Open HW Config, insert FM350-1 in the slot next to the CPU.
- Set channel 0 to continuous counting, 32-bit, gate always open.
- Set the output value address, e.g.
PQW 304(DO load value) andPIW 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
- Force
DB100.Reset_cmd := TRUEfor one OB35 scan; verify both totals return to 0. - 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 = 1000andTotal_m3 = 1.000. - 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.
- 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.