1. Problem Overview
You have a conveyor roller driven by a variable-frequency drive. A proximity switch detects 8 ferrous nuts mounted on the roller, producing 8 pulses per mechanical revolution. From those pulses the PLC must compute a linear speed in meters per minute (m/min) and refresh the value every time the VFD changes its output frequency. This is a classic incremental-encoder-style measurement solved on a SIMATIC S7-300 with a standard digital-input module (SM 321) or, when pulse rates exceed DI filter limits, with a counter module (FM 350-1 / FM 350-2 or the FM 452 cam controller for very high resolution).
The same logic generalises to any rotational-to-linear conversion: extruder screws, wire-draw capstans, calender rolls, web tension idlers, and packaging conveyors. The hardware stays the same, the constants change.
2. Prerequisites
Before writing code, confirm the following:
- Roller geometry — outer diameter D in mm; circumference C = π·D.
- Pulses per revolution — P = 8 (the eight nuts). For encoders, P is the line count printed on the body (e.g. 1024, 2048).
- Maximum shaft speed in RPM. The VFD nameplate or the mechanical gearbox ratio sets this. Convert to pulses/second to size the DI module:
fpulse,max = (nmax / 60) · P
-
Hardware kit:
- 1 × SIMATIC S7-300 CPU 31x (e.g. CPU 315-2 PN/DP) with STEP 7 V5.5 or TIA Portal V16+.
- 1 × SM 321 digital-input module (e.g. 6ES7321-1BH02-0AA0) — 16 DI, 24 V DC, 0.5 ms input filter for slow applications; for > 1 kHz use a counter module.
- Optional 1 × FM 350-1 counter module (6ES7350-1AH03-0AE0) for pulse rates above the standard DI filter cutoff, or FM 452 cam controller when sub-millisecond gating is needed.
- 1 × 3-wire PNP inductive proximity switch, 10–30 V DC, NPN/PNP matched to SM 321 sourcing input.
- STEP 7 hardware catalog entry for the chosen FM (only if the counter module path is used).
3. Pulse-Rate Analysis and DI Module Selection
Compute the maximum expected pulse frequency before you wire a single terminal. Assume a worst-case mechanical overspeed of 110 % of motor rated speed.
| Motor RPM (nmax) | Pulses/rev (P) | fpulse (Hz) | SM 321 standard DI OK? |
|---|---|---|---|
| 60 | 8 | 8.0 | Yes |
| 300 | 8 | 40.0 | Yes |
| 1500 | 8 | 200.0 | Yes (with reduced filter) |
| 3000 | 8 | 400.0 | Borderline — use FM 350-1 |
| 4500 | 8 | 600.0 | No — FM 350-1 mandatory |
The general rule, derived from the Nyquist criterion plus a 2× safety margin, is:
fpulse,max ≤ 1 / (4 · tfilter)
For the standard 3 ms filter on a 6ES7321-1BH02 that gives fpulse,max ≤ 83 Hz. Anything above this must use a counter module. The same threshold logic appears in the SIMATIC FM 452 documentation when configuring simulation speed — the unit of travel is set in µm/pulse and the integer portion of the simulation increment is used for subsequent calculation, which is exactly the same pulseto-distance relationship this article implements in software.
4. Architecture: Three Implementation Paths
| Path | When to use | Hardware | OB used | Update latency |
|---|---|---|---|---|
| A — Standard DI + OB35 | fpulse ≤ 80 Hz, soft real time OK | SM 321 DI | OB1 + OB35 (1 s) | 1 s |
| B — FM 350-1 counter | fpulse up to 500 kHz, accurate | FM 350-1 | Hardware counter, polled in OB1 | OB1 cycle |
| C — Hardware interrupt OB40 | Standard DI but fast cycle, no FM | SM 321 with HW-int cap | OB40 | Per pulse |
This article focuses on Path A, the cheapest and most common. The formulas in Section 6 apply to all three paths; only the place where the counter value is read changes.
5. Standard-DI Method with OB35 — Step-by-Step
- Configure the cyclic interrupt OB35 in STEP 7 hardware configuration: open the CPU properties → "Cyclic Interrupts" → set OB35 to 1000 ms (range 1–60000 ms). Longer windows give better statistical accuracy because the pulse count grows; 1 s is a sensible default for 8-pulse-per-rev applications. 10 s is acceptable if the displayed value can tolerate a 10 s refresh.
-
Create a shared data block (DB10) for the speed data. Declare the following tags:
-
dbCountINT — pulse count captured in the last OB35 cycle. -
dbPulsesPerRevINT = 8 (constant). -
dbCircumference_mmREAL — circumference C in mm, computed once from D. -
dbSpeed_mPerMinREAL — output speed in m/min. -
dbSpeed_mmPerSecREAL — output speed in mm/s (handy for HMI). -
dbHandshakeBOOL — toggled by OB35, reset by OB1 to confirm liveness.
-
-
Implement an up-counter (CTU) in a function block (FB100, instance DB100). The counter is incremented by the proximity-sensor DI in OB1 (sample edge on the input). CTU parameters:
CU := I0.0,R := FALSE,PV := 32767,Q := dbCount_Overflow,CV := dbCount_Acc. Use the instance-DB CV for the current accumulated count. -
Read and reset the counter in OB35 (FC10 "SpeedCalc"). Copy the instance-DB CV to
DB10.dbCount, then callCTUwithR := TRUEfor one PLC cycle to clear, thenR := FALSEagain. This gives an atomic read-and-reset for the next window. - Compute speed in FC10. See Section 6 for the formula and code.
-
Write the result to a process tag (e.g.
MW200or a WinCC / HMI tag) so the operator can read m/min and the VFD can compare to its setpoint for closed-loop speed trim.
6. The Speed Formula and the Code
Given the counter value N in one OB35 window of duration T seconds, with P pulses per revolution and roller circumference C in metres, the linear speed is:
v [m/s] = (N / P) · C / T
v [m/min] = v [m/s] · 60
→ v [m/min] = (N · 60 · C) / (P · T)
For the typical values P = 8, T = 1 s, C = 0.250 m (roller Ø 80 mm), the formula reduces to:
v [m/min] = (N · 60 · 0.250) / (8 · 1) = 1.875 · N
So 100 pulses in a 1 s window = 187.5 m/min. Easy to verify in the field with a hand tachometer.
6.1 STL implementation (S7-300, STEP 7 V5.5)
FUNCTION FC 10 : VOID
TITLE =Speed calculation from pulse counter
AUTHOR :automation
VERSION :1.0
VAR_TEMP
tCount : INT ; // pulses this window
tPulsesPerRev : INT ; // = 8
tCirc_m : REAL ; // roller circumference in m
tWindow_s : REAL ; // = 1.0
tSpeed : REAL ; // m/min
tSpeed_mps: REAL ; // m/s
END_VAR
BEGIN
// ---- read counter and reset ----
L DB100.DBD 0 // instance DB, CV as DINT
T #tCount
L 0
T DB100.DBD 0 // reset CV (only safe if no OB1
// pulse will arrive in this cycle)
// ---- load constants from DB10 ----
L DB10.DBW 2 // dbPulsesPerRev (INT)
T #tPulsesPerRev
L DB10.DBD 4 // dbCircumference_mm (REAL mm)
DTR
L 1.000000e+003
/R // convert mm -> m
T #tCirc_m
L 1.0
T #tWindow_s
// ---- compute v [m/min] ----
L #tCount
DTR // INT -> REAL
L 6.000000e+001 // 60 s/min
*R
L #tCirc_m
*R
L #tPulsesPerRev
DTR
L #tWindow_s
*R
/R
T #tSpeed // m/min
// ---- derive m/s for HMI ----
L #tSpeed
L 6.000000e+001
/R
T #tSpeed_mps
// ---- write outputs ----
L #tSpeed
T DB10.DBD 16 // dbSpeed_mPerMin (REAL)
L #tSpeed_mps
T DB10.DBD 20 // dbSpeed_mmPerSec stored as m/s
// ---- liveness handshake ----
U DB10.DBX 24 // dbHandshake
= DB10.DBX 25 // toggle bit
SET
S DB10.DBX 24
END_FUNCTION
6.2 SCL (Structured Control Language) implementation
FUNCTION FC 10 : VOID
VAR_TEMP
tCount : INT;
END_VAR
BEGIN
// snapshot & reset the counter atomically
tCount := WORD_TO_INT(DB100.CV); // CV from CTU instance
DB100.CV := 0;
DB10.dbSpeed_mPerMin := (INT_TO_REAL(tCount) * 60.0
* (DB10.dbCircumference_mm / 1000.0))
/ (INT_TO_REAL(DB10.dbPulsesPerRev)
* DB10.dbWindow_s);
DB10.dbSpeed_mmPerSec := DB10.dbSpeed_mPerMin / 60.0;
DB10.dbHandshake := NOT DB10.dbHandshake;
END_FUNCTION
7. High-Speed Path with FM 350-1 Counter Module
The FM 350-1 (6ES7350-1AH03-0AE0) is a single-channel counter module rated up to 500 kHz with 32-bit count width. The functional principle is the same, but the counter is hardware: PLC reads the latched value via a data record, no software CTU required. The FM is mandatory when:
- The maximum pulse frequency exceeds 200 Hz.
- Direction of rotation must be captured (FM 350-1 has a separate count-up / count-down input pair).
- 24 V encoder signals must be conditioned (FM accepts 24 V or 5 V via sub-D).
The speed formula is identical to Section 6; only the read procedure changes. The FM is read using SFC 59 / SFC 58 with data record 0 (job) and 1 (count value). An alternative is the standard FCs shipped with FM 350-1: FC CNT_CTL1 writes the control bits, FC CNT_READ1 returns the current count. Reference the FM 350-1 manual in Siemens Entry ID 1087048 for the exact data-record layout.
7.1 FM 350-1 pseudo-code in OB35
// every OB35 cycle, 1 s
iJobRetVal := CNT_CTL1( // initialise once in OB100
LADDR := 256, // module address (config dependent)
SW_GATE:= TRUE,
OT_ERR := iErr);
iCount := CNT_READ1(
LADDR := 256,
JOB_ID := 1, // read count
OT_VAL := diCountValue,
OT_ERR := iErr);
dbSpeed_mPerMin := (DINT_TO_REAL(diCountValue) * 60.0
* dbCircumference_m)
/ (DINT_TO_REAL(dbPulsesPerRev) * dbWindow_s);
// reset by writing SW_GATE := FALSE then TRUE
When using the FM 452 cam controller (a higher-end motion module) the same speed/position logic is built in; the engineering tool exposes "simulation speed" with a unit of µm/pulse in the axis configuration, which is precisely the same conversion constant as C (in metres) × 10⁶ in our formula. See the TIA Portal FM 452 axis documentation for the integer-only µm/pulse format.
8. Hardware-Interrupt Path with OB40 (No FM Module)
If you cannot add an FM 350-1 and the standard SM 321 supports hardware interrupts (e.g. 6ES7321-7RD01-0AB0 with interrupt-capable inputs), assign the proximity-sensor input to OB40 in the hardware configuration. OB40 is then called on every rising edge of the input. Inside OB40, increment an instance-DB counter. The advantage over OB1 polling is that no edge is missed; the disadvantage is OB40 must be kept very short to avoid blocking higher-priority interrupts.
// OB40 (hardware-interrupt OB) - keep < 200 µs
L DB100.DBD 0
+ 1
T DB100.DBD 0
The rest of the calculation is identical to Section 6. A flag OB40_PulseArrived can be set in OB40 and cleared in FC10 to indicate that the count was incremented in hardware, removing the race condition described in Section 6.
9. Commissioning and Verification
-
Simulated pulse test. Before mounting the proximity switch, force DB100.CV in STEP 7 to a known value (e.g. 200) and run a single OB35 cycle. Confirm
dbSpeed_mPerMin= 200 · 1.875 = 375.0 m/min. This validates the formula without rotating hardware. -
Hand-spin test. Spin the roller at a known RPM (use a hand tachometer on the shaft) for 30 s. Capture
dbCountin OB35; verify the computed speed matches tachometer-derived m/min within ±2 %. - Reference-frequency test. Drive the VFD at 50 % of rated frequency, capture 10 consecutive OB35 windows, compute mean and standard deviation. Coefficient of variation should be < 1 % for a healthy signal.
- Bounce test. Briefly block the proximity switch with aluminium foil. The PLC speed should drop to 0 within 1–2 OB35 windows. A persistent non-zero reading indicates contact bounce, electrical noise, or counter not being reset.
-
Closed-loop test. Enable PID trim of the VFD setpoint from
dbSpeed_mPerMin. Run a step change of +10 % setpoint and verify the measured speed reaches the new setpoint within the mechanical time constant.
10. Edge Cases and Field-Proven Caveats
- Direction reversal. The CTU in Section 5 cannot count down. If the VFD can run the roller in reverse, switch to FM 350-1 with a count-direction input, or use a two-pulse quadrature sensor.
- Initial value at startup. DB100.CV is initialised to 0. During the first OB35 window the displayed speed will be artificially low. Either preset DB100.CV to 0 explicitly in OB100 (warm restart) and accept the first 1 s of low display, or display "0 / no data" until the second OB35 window has executed.
- OB35 overflow. If OB35 is not called for more than its configured time (CPU overload, STOP-RUN transition), the calculated speed will be wrong. Use SFC 6 / SFC 7 in FC10 to read the time stamps and warn the operator if the OB35 cycle exceeded the configured period by more than 20 %.
- Mechanical slip. If the proximity switch is on the motor shaft but the conveyor roller can slip, measure the roller, not the motor. Speed = (N · 60 · C) / (P · T) always describes the measured surface, not the commanded setpoint.
- CTU integer overflow. P = 8, T = 1 s, max motor 1500 RPM → N = 200 pulses/s. INT (16-bit) overflows at 32 767, which is 163 s of continuous counting. For long windows use DINT (32-bit) as in Section 6.1 (CV is DINT in modern S7-300 CPUs).
- VFD noise on the 24 V rail. VFD output filters and switching PSUs inject high-frequency noise that doubles as extra "pulses" on the DI. Use a shielded cable, ground at the cabinet end only, and add a 10 kHz hardware filter on the SM 321 if available.
11. Sample Parameter Set for an 80 mm Roller at 1450 RPM
| Parameter | Value | Unit | Source |
|---|---|---|---|
| Roller diameter D | 80 | mm | mechanical drawing |
| Circumference C | 251.327 | mm | π·D |
| dbCircumference_mm | 251.327 | mm | DB10 |
| Pulses per rev P | 8 | — | 8 nuts on roller |
| Max RPM | 1450 | 1/min | motor nameplate |
| Max pulse freq fpulse | 193.3 | Hz | (1450/60)·8 |
| OB35 window T | 1.0 | s | CPU config |
| Expected count at 1450 RPM | 193 | pulses/window | f·T |
| Expected speed | 362.5 | m/min | (193·60·0.251327)/(8·1) |
| Surface speed (m/s) | 6.04 | m/s | 362.5/60 |
Use this table in the HMI faceplate as the engineering reference for first-article inspection.
12. Cross-Platform Notes
- S7-1500 — use the technology object "Counting and Measurement" (TO_Counter) and the high-speed counter onboard I/O of the CPU. The formula stays the same; the OB is now the "MC-Interpolator" or a regular cyclic task.
- S7-1200 — use the "CTRL_HSC" instruction and the onboard HSC. The same v = N·C/(P·T) applies.
- LOGO! 8 — the on-board high-speed counter can drive a virtual analogue value scaled to m/min using the same constant.
- ET 200S 1COUNT 24V — distributed variant of FM 350-1, ideal when the roller is far from the CPU.
13. FAQ
What is the minimum pulse count I can detect on a standard SM 321 DI?
With a 3 ms input filter (default on 6ES7321-1BH02-0AA0) the shortest reliably detected pulse width is 6 ms, so the maximum countable frequency is roughly 83 Hz. For faster signals, configure the DI group to the 50 µs hardware filter (where supported) or use the FM 350-1 counter module rated to 500 kHz.
Why is my calculated speed 1.5 % below the VFD display?
Three usual causes: (1) mechanical slip between the motor shaft and the measured roller — install the proximity switch on the roller that actually drives the web, (2) one or two pulses lost in the OB35 race window — increase the OB35 time to 2 s or 5 s, (3) the roller diameter was nominal but the actual diameter under load is smaller — re-measure the warm, loaded roller.
Can I do this without an OB35 cyclic interrupt?
Yes — read the counter once per OB1 scan and divide by the time since the last read. SFC 64 "TIME_TCK" gives a 16-ms system tick. The result is noisier because OB1 cycle time varies with the program length, but it is adequate when the count per cycle is high (e.g. 1000+ pulses/cycle).
How do I get a signed speed (positive for forward, negative for reverse)?
Switch from a single proximity switch and a CTU to the FM 350-1 with a directional input, or to a quadrature encoder. Read the 32-bit signed count and apply the same formula; the sign of the result equals the sign of the count.
Is the formula the same if I switch from nuts on a roller to a real encoder?
Yes. Replace P = 8 with the encoder line count (e.g. 2048) and C with the roller circumference. The relationship v = (N · 60 · C) / (P · T) is encoder-agnostic. For very long conveyors where each pulse covers several mm, the FM 452 "simulation speed" parameter uses the same constant expressed in µm/pulse — the integer portion of the µ/pulse value is what the cam controller uses for downstream calculation, exactly as the integer portion of our N is what the formula uses.