Calculating Flow Rate (L/h) from Pulse Input on S7-1200 HSC

David Krause14 min read
S7-1200SiemensTutorial / 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

1. Problem Definition

A S7-1214C receives a pulse train from a process flow meter and must derive an engineering-units flow rate (L/h) for display and downstream control. The relevant signal chain is:

  • Pulse source: Paddle-wheel / turbine flow meter, sinking or sourcing output, 24 V DC.
  • Meter constant: K = 1000 pulses per liter (nominal).
  • Maximum specified flow: Qmax = 80 L/h.
  • Observed pulse rate: f = 25 Hz (period 40 ms) at the operating point.

The expected pulse frequency at the rated flow is

frated = Qmax · K = 80 L/h · 1000 pulses/L = 80 000 pulses/h = 22.22 Hz

A measured 25 Hz therefore sits roughly 12.5 % above the meter's nominal Qmax. Treat the first task on the bench as verifying that the meter is not being over-driven and that the K-factor is constant over the flow range; a paddle-wheel meter in turbulent flow can drift several percent and produce this kind of mismatch.

Engineering note: 25 Hz corresponds to a 40 ms period. A 6 ms OB1 scan is fine for arithmetic, but standard cyclical inputs on the S7-1200 are filtered by default and can drop pulses above ~10-15 Hz depending on the input filter setting. Use a High-Speed Counter (HSC) channel so the input is sampled in the hardware counter rather than at OB1 rate.

2. Prerequisites

2.1 Hardware

  • SIMATIC S7-1214C DC/DC/DC (firmware V4.2 or later recommended for full HSC functionality; V4.5+ if you intend to use the symbolic HSC IDB fields directly).
  • 24 V DC pulse output flow meter, K = 1000 pulses/L.
  • Wiring: meter output → DI of the CPU; for sourcing outputs use a 24 V input; for sinking outputs add a pull-up or use an interposing relay or signal conditioner.

2.2 Software

  • STEP 7 Basic / Professional in TIA Portal (V15.1 or later; V17/V18 recommended for the latest HSC application example).
  • S7-1200 System Manual, edition 09/2022 or later.

2.3 Official references

3. HSC Architecture on the CPU 1214C

The CPU 1214C exposes six independent HSC channels (HSC1-HSC6) implemented in hardware, independent of the OB1 scan. Each HSC can be configured for one of three counting modes:

Mode Phases Max input frequency (CPU 1214C DC/DC/DC) Typical use
Single-phase, internal direction control 1 100 kHz Pulse counting, simple flow
Two-phase (quadrature X1) 2 100 kHz Encoder position
Two-phase (quadrature X2/X4) 2 100 kHz Encoder with 2x/4x resolution
A/B counter, Z reset 3 100 kHz Encoder with index

Default input pin assignment on the CPU 1214C (DC/DC/DC) for an unused channel is reassignable in the device configuration. The factory defaults that matter for this application are:

HSC Default Clock (A) Default Direction (B) Default Reset (Z)
HSC1 I0.0 I0.1 I0.3
HSC2 I0.4 I0.5 I0.7
HSC3 I1.0 I1.1 I1.2
Filter note: CPU 1214C digital inputs have a configurable input filter (0.1 ms, 0.2 ms, 0.4 ms, 0.8 ms, 1.6 ms, 3.2 ms, 6.4 ms, 12.8 ms; default 6.4 ms). For HSC inputs, switch the filter to 0.1 ms (or 0.2 ms at 25 Hz) so the counter sees the full pulse train. Filtering is set per channel under Device configuration → Digital inputs → Input filter.

4. Engineering Units: From Pulses to Liters per Hour

Two equivalent conversions are useful. Define a sampling window W (in seconds). The number of pulses accumulated in the window is ΔN. The instantaneous volume throughput is then

V_dot [L/s] = ΔN / (K · W)

and the displayed engineering value is

Q [L/h] = V_dot · 3600 = (ΔN · 3600) / (K · W)

For K = 1000 pulses/L and W = 1 s, this simplifies to

Q [L/h] = 3.6 · ΔN [pulses in 1 s]

At the rated 22.22 Hz (Q = 80 L/h), ΔN = 22 pulses per second; at the observed 25 Hz, ΔN = 25 pulses per second, giving 90 L/h. Either the meter constant is slightly off, or the meter is being run above its specified Qmax - in either case, the FB below exposes the raw pulse count and the scaled L/h value so the mismatch is visible at commissioning.

Flow Q [L/h] Pulses/sec ΔN Period T [ms] HSC count after 1 s
0 0 0
10 2.78 360.0 3
40 11.11 90.0 11
80 (rated) 22.22 45.0 22
90 (observed 25 Hz) 25.00 40.0 25

4.1 Window length trade-off

  • W = 100 ms: responsive but quantised - at 80 L/h only 2.2 pulses accumulate, so the displayed value jitters between 72 and 108 L/h (jumps of 36 L/h).
  • W = 1 s: 22 pulses at 80 L/h, LSB ≈ 3.6 L/h, jitter 0 to 7.2 L/h - acceptable for display.
  • W = 10 s: 222 pulses, LSB ≈ 0.36 L/h - excellent stability but 10 s display lag.

Pick W = 1 s for HMI display. If the value is also used in a closed-loop control loop, run a second faster loop at 100 ms with a low-pass filter.

5. TIA Portal Device Configuration

  1. Open the project and the CPU 1214C device view.
  2. Select Properties → Digital inputs and assign HSC1 to the physical input that the meter is wired to (e.g. I0.0). Set the input filter for that channel to 0.1 ms.
  3. Select Properties → High-Speed Counters (HSC). Enable HSC1, choose Count mode, single-phase, internal direction control (count up).
  4. Set initial count value, initial reference, and any preset / upper limits you need. For this application, no preset is required; just count up.
  5. Compile and download the hardware configuration.

After download, the HSC exposes an Instance DB (IDB) of type HSC_Count (or CTRL_HSC_EXT in older projects). The fields you will read from the SCL FB are:

  • IDB_HSC1.CurrentCount - DInt, live count value.
  • IDB_HSC1.NewDirection - Bool, direction status.
Watch the field name. The exact name depends on the TIA Portal version and the HSC mode chosen. In V17/V18 projects the field is typically CurrentCount; in earlier V13/V14 SP1 projects it was CountValue. Always inspect the IDB before referencing it.

6. SCL Implementation: FlowRate FB

Create a function block FB_FlowRatePulses in a new SCL source. The FB latches the HSC count on every cycle of a 1 s timer, computes the delta, and scales to L/h.

FUNCTION_BLOCK "FB_FlowRatePulses"
TITLE = 'Pulse-train flow rate'

VAR_INPUT
    iRawCount   : DInt;     // IDB_HSC1.CurrentCount snapshot
    iPulsePerL  : Real := 1000.0;   // K [pulses/L]
    iWindow_s   : Real := 1.0;      // sampling window W [s]
    iEnable     : Bool;
END_VAR

VAR_OUTPUT
    oFlow_Lph   : Real;     // engineering-units flow rate [L/h]
    oDeltaN     : DInt;     // pulses accumulated in last window
    oAlarmHi    : Bool;     // 1 = above configured high limit
    oAlarmLo    : Bool;     // 1 = below configured low limit
END_VAR

VAR
    sCountPrev  : DInt;     // last latched count
    sFirstRun   : Bool := TRUE;
    sIEC_Timer  : IEC_TIMER; // TP or TON, 1 s pulse
    sWindow_Trig: Bool;
END_VAR

VAR CONSTANT
    cHighLimit_Lph : Real := 80.0;
    cLowLimit_Lph  : Real := 0.0;
END_VAR

BEGIN
    // Edge-triggered 1 s window
    sIEC_Timer(IN := iEnable, PT := T#1s);
    sWindow_Trig := sIEC_Timer.Q;

    IF NOT iEnable THEN
        sFirstRun := TRUE;
        oFlow_Lph := 0.0;
        oDeltaN   := 0;
        oAlarmHi  := FALSE;
        oAlarmLo  := FALSE;
        RETURN;
    END_IF;

    IF sFirstRun THEN
        sCountPrev := iRawCount;
        sFirstRun := FALSE;
        oFlow_Lph := 0.0;
        oDeltaN   := 0;
    END_IF;

    IF sWindow_Trig THEN
        // signed delta; flow meter is single-direction here
        oDeltaN := iRawCount - sCountPrev;
        sCountPrev := iRawCount;

        // guard divide-by-zero
        IF iWindow_s > 0.0 AND iPulsePerL > 0.0 THEN
            oFlow_Lph := (DINT_TO_REAL(oDeltaN) * 3600.0)
                         / (iPulsePerL * iWindow_s);
        ELSE
            oFlow_Lph := 0.0;
        END_IF;

        oAlarmHi := oFlow_Lph > cHighLimit_Lph;
        oAlarmLo := oFlow_Lph < cLowLimit_Lph;
    END_IF;
END_FUNCTION_BLOCK

Call the FB from OB1, supplying the HSC's CurrentCount snapshot. A clean snapshot is simply reading "HSC_1".CurrentCount into a local DInt; the HSC hardware register is updated in the background by the high-speed counter logic, so there is no race condition with OB1.

// OB1 - calling the FB
"Inst_FlowRate"(
    iRawCount  := "HSC_1".CurrentCount,
    iPulsePerL := 1000.0,
    iWindow_s  := 1.0,
    iEnable    := TRUE
);

// Push the engineering value to the HMI tag
"HMI_Flow_Lph" := "Inst_FlowRate".oFlow_Lph;
"HMI_AlarmHi"  := "Inst_FlowRate".oAlarmHi;

7. LAD/FBD Alternative (Pure Ladder)

If the project prohibits SCL (some legacy code bases), the same flow can be built in LAD/FBD without any HSC. The trade-off is that the count is taken on the OB1 scan edge rather than in hardware, so you must verify that no pulses are lost between scans. With a 6 ms OB1 and a 40 ms pulse period the worst case is one lost pulse in 7, which is tolerable for display.

  1. Wire the meter output to a standard DI (e.g. I0.0). Configure the input filter to 0.1 ms.
  2. Use a standard up-counter CTU with PV set above the maximum expected count over the window (e.g. 200 for 1 s at 25 Hz).
  3. Add a 1 s on-delay timer (TON) whose output resets the counter via the CTU R input.
  4. Capture the counter value on the timer's falling edge into a static word using a MOVE block triggered by the timer's Q output.
  5. Apply the scaling Q = 3.6 · ΔN as a math block or a CALCULATE instruction.

The math step uses the CALCULATE instruction in TIA Portal with the expression

OUT = (IN1 * 3.6) / 1000.0   // IN1 = delta pulses in 1 s

For a 500 ms window replace 3.6 with 7.2; for 100 ms use 36. The trade-off is a noisier display at small W, since the integer delta quantises to 1 pulse.

Watch the overflow. With W = 1 s and 25 Hz, ΔN = 25 fits easily in a DInt. If W is increased to 1 hour for a daily total, the meter emits 80 000 pulses and the DInt still has headroom. If you ever extend to multi-day totals, migrate the daily counter to a LReal or use DInt with a 24 h reset.

8. Sampling Window and Filtering

For HMI display, a single-pole exponential filter on top of the 1 s sample is usually enough to calm the visual jitter:

Qfilt(t) = α · Qraw(t) + (1 - α) · Qfilt(t - 1)

with α in [0, 1]. A 1 s sample window with α = 0.4 gives a display time constant of about 1.5 s, which is comfortable for operators. If the output is used as a PV in a PID loop, drop the filter and use the raw 1 s value; the loop's integral action provides the smoothing.

Use case Recommended W Filter α Notes
HMI display only 1 s 0.3 - 0.5 Smooth visual response
Alarm threshold only 1 s 1.0 (no filter) Detect overruns quickly
PID PV (slow loop, > 10 s Tc) 1 s 1.0 Let loop integrate
PID PV (fast loop, < 5 s Tc) 100 ms 0.7 Higher noise bandwidth
Custody transfer / billing Totaliser n/a Use pulse count, never an averaged rate

9. Edge Cases, Overflow, and Alarms

9.1 Negative delta from HSC wraparound

The HSC on the S7-1200 has a 32-bit count, so at 25 Hz it would take more than 4.8 years to roll over. If you ever change to a faster meter or remove the rollover, the difference oDeltaN must be treated as DInt, not as a Word, so the sign is correct.

9.2 Direction change

If the meter can read bi-directional flow, switch the HSC to two-phase mode and use the direction bit to gate the calculation. The SCL FB above assumes single-direction; for bi-directional, scale a positive delta by +1 and a negative delta by -1, or run two accumulators keyed off IDB_HSC1.NewDirection.

9.3 Stalled flow / wire break

A broken wire presents as zero pulses. Add a stall alarm: a TON with PT = 30 s that triggers when the HSC has not changed for 30 s, while the enable is true. This is often more useful than a low-flow alarm because it distinguishes "valve closed, no flow" from "flow at zero".

9.4 High-flow alarm

Set cHighLimit_Lph = 80 L/h. At 25 Hz the calculated 90 L/h will fire this alarm, which is the desired behaviour - it tells the operator the meter is over-driven and the K-factor should be re-verified or a smaller meter installed.

9.5 Totaliser

For totalised volume, do not average - add the unscaled count and divide by K once per minute. Store the total in a retentive LReal tag (e.g. Tot_L) and reset only on a manual command or a daily schedule.

10. Commissioning and Verification

  1. Disconnect the process and feed a calibration pulse generator into the meter input. Set the generator to 22.22 Hz (1 pulse every 45 ms) and verify that the displayed Q reads 80.0 L/h ± 1 L/h within 2 s.
  2. Repeat at 11.11 Hz (50 %) and 5.56 Hz (25 %) to confirm linearity.
  3. Set the generator to 0 Hz and check that the stall alarm fires after 30 s.
  4. Restore the process. Compare the integrated volume over 10 min against a manual draw into a calibration vessel. Aim for ± 1 %.
  5. Watch the HSC IDB online - CurrentCount should advance monotonically.

10.1 Online watch table

Add the following tags to a watch table during commissioning:

"HSC_1".CurrentCount         // raw hardware count
"Inst_FlowRate".oDeltaN      // pulses in last window
"Inst_FlowRate".oFlow_Lph    // scaled flow rate
"Inst_FlowRate".oAlarmHi     // high alarm
"Inst_FlowRate".oAlarmLo     // low alarm

11. Troubleshooting Matrix

Symptom Likely cause Diagnostic Action
Display reads 0 even with flow DI filter too long; HSC not enabled; wrong input assigned Force HSC IDB and watch CurrentCount online Set input filter to 0.1 ms, enable HSC1 in device config, reassign input to the wired terminal
Display reads exactly half the expected value K-factor set to 2000 instead of 1000 Inspect iPulsePerL input Correct K to 1000
Display jitters wildly W too short, or meter pulses are noisy (bouncing contacts) Capture oDeltaN over 10 s; check the rising edge on a scope Increase W to 1 s, fit a hardware low-pass on the input, or use a debounce filter in the FC
Display drifts high with no flow Noise counts on a floating input Disconnect meter; observe CurrentCount Add 2.2 kΩ pull-down to 0 V at the input; enable the input filter at 0.4 ms
High alarm always on at rated flow Meter K-factor inaccurate, or Qmax limit too low Measure pulses/s with a hand-held counter at known flow Re-calibrate K, or raise cHighLimit_Lph after engineering sign-off
HSC counts but display never updates 1 s timer is not pulsing; OB1 not running Watch sIEC_Timer.Q in the FB online Confirm iEnable is true, OB1 cycle light is on, IEC_Timer is not held by a JOG condition
Negative oDeltaN at start-up sCountPrev initialised to 0 while the HSC has counted in standby Set sFirstRun := TRUE on a power-on or on first OB1 scan Initialise on first run as shown in the FB; alternatively clear the HSC on cold restart

12. Variants and Migration

The same flow scales cleanly to other S7-1200 CPUs (CPU 1211C, 1212C, 1215C, 1217C) and to the S7-1500. On the S7-1500 the HSC is replaced by a TM Count or by a high-speed counter on the technology module, and the period measurement is built in. The scaling formula in §4 is identical, so the SCL FB body is portable verbatim. For a 1217C (DC/DC/DC) the HSC ceiling is 1 MHz and the same code is the right starting point; only the device configuration differs.

If the application is being ported from a MicroLogix or a third-party PLC, the only item that changes is the input filter default; the SCL math and the windowed scaling are the same.

Do I really need an HSC for 25 Hz on a CPU 1214C?

For pure display, no - 25 Hz is well below the digital input sampling limit of a 1214C and a standard CTU counter will work. Use the HSC when you need guaranteed lossless counting, when the loop time is unknown, or when the application may grow to higher meter rates. HSC also gives you a hardware-level snapshot that survives OB1 scan-time variation.

What is the maximum HSC input frequency on a 1214C DC/DC/DC?

100 kHz in single-phase or two-phase quadrature mode (X1, X2, X4), with the input filter set to 0.1 ms. The 1214C AC/DC/RLY is much lower (about 30 Hz) because its inputs are optocoupled with a longer filter; always check the manual for the exact model you are using.

Why does my display read 90 L/h when the meter is rated for 80 L/h?

Two likely causes. Either the meter is actually flowing above its rated Qmax (verify with a clamp-on flow reference), or the K-factor in software is wrong (check whether the meter nameplate reads 1000 pulses/L or, for example, 900 pulses/L). Recalibrate K from a measured draw if needed.

How do I totalise volume in addition to the instantaneous rate?

Read HSC_1.CurrentCount once per minute, subtract a latched previous value, and add the delta divided by 1000 to a retentive LReal tag. Do not derive total volume from the averaged rate - the integration error is unacceptable for billing.

Why does the display freeze at 0 when I turn the meter on?

The HSC needs the input filter configured for the high-speed pin. Check Device configuration → Digital inputs → Channel 0 (I0.0) → Input filter = 0.1 ms. The default 6.4 ms filter will silently drop every 25 Hz pulse. Confirm by forcing the HSC online and watching CurrentCount; if it never increments, the filter is the problem.

Back to blog