Overview
Counting rotational speed with a single inductive proximity switch is a classic S7-1200 application. The standard CPU 1212C includes onboard high-speed counter (HSC) inputs rated for signals up to 100 kHz, so a gear-tooth or slotted-disc target is a clean fit. This reference walks through the engineering workflow used on a 25-tooth gear driven by a 1000 RPM motor, where the resulting sensor frequency is 416.67 Hz, and shows how to convert that count into both RPM and linear web speed for an 800 mm drum.
Three implementation paths are documented here, ordered from simplest to most flexible:
- Edge counting in ID1000 with a cyclic-interrupt time base (works on any S7-1200 firmware).
- Frequency measurement with the extended HSC instruction
CTRL_HSC_EXT(firmware 4.0 and later on CPU 1211C/1212C/1214C). - Period measurement using
CTRL_HSC_EXTin period mode for very slow shafts.
Prerequisites
| Item | Specification |
|---|---|
| CPU | SIMATIC S7-1200, CPU 1212C (DC/DC/DC or DC/DC/RLY) |
| Firmware | V4.0 or later for CTRL_HSC_EXT; V4.2+ recommended for period mode stability |
| Engineering software | STEP 7 Basic / Professional V14 (matches the original installation) or V15, V16, V17 for current firmware |
| Sensor | Inductive proximity, PNP, NO, ≥1 kHz switching frequency, 24 V DC |
| Target | 25-tooth gear or 25-pulse slotted disc on the rotating shaft |
| Wiring | 24 V DC sensor supply from CPU, shielded cable, HSC input on the CPU front connector (Ia.0 to Ia.5 depending on slot) |
Reference the S7-1200 Programmable Controller System Manual (entry ID 109478121) for the exact HSC input pin map of the CPU 1212C. On the 1212C, the onboard inputs Ia.0 through Ia.5 are HSC-capable, with the maximum input frequency of 100 kHz on Ia.0 to Ia.3 (single-phase) and 30 kHz on Ia.4 to Ia.5.
Step 1: Signal Frequency Analysis
Before any code, calculate the maximum pulse rate the sensor will deliver. The 25-tooth gear at 1000 RPM produces:
f = (RPM × teeth) / 60 = (1000 × 25) / 60 = 416.67 Hz
This is well below the 100 kHz HSC ceiling, so the application is comfortable on a stock 1212C with no signal board or fast counting module. The constraint that previously blocked the user was a sensor with a switching frequency under 1 kHz, which would alias or stall at 416 Hz. A standard 1 kHz inductive proximity (for example, a Sick IME12 or ifm IFS204) is sufficient. For higher tooth counts or shaft speeds, recompute f first and confirm headroom:
| Shaft RPM | Teeth | Pulse Frequency | 1212C Headroom |
|---|---|---|---|
| 500 | 25 | 208.3 Hz | 480× |
| 1000 | 25 | 416.7 Hz | 240× |
| 3000 | 60 | 3000 Hz | 33× |
| 10000 | 120 | 20 kHz | 5× |
| 24000 | 250 | 100 kHz | 1× (at limit) |
Step 2: HSC Hardware Configuration in TIA Portal
- Open the device view of the CPU 1212C and select Properties → Pulse Generators (PTO/PWM) initially to confirm the CPU is not consuming the input for PTO.
- Open Properties → High Speed Counters (HSC) and add a new HSC instance (HSC_1 by default).
- Set:
- Type of counting: Count continuously (no preset, no gate control unless used).
- Counting direction: Single-phase with internal direction control.
- Input: Ia.0 (or the physically wired pin).
- Initial count value: 0.
- Set the input filter to a value appropriate for 416.67 Hz. The default filter of 0.8 µs (100 kHz) is fine. If noise is present, raise the filter to 6.4 µs (still 78 kHz).
- Assign the process image for the HSC count to ID1000 (the default for HSC_1).
ID1000is a 32-bit DINT accessible from any OB, FB, or DB.
Background on HSC configuration, ID1000 mapping, and the maximum input frequency table is documented in the S7-1200 System Manual, section on High-Speed Counters.
Step 3: CTRL_HSC_EXT Frequency Measurement
The extended HSC instruction provides built-in frequency and period measurement, which is the cleanest path on firmware V4.0 and later. From the TIA Portal instruction tree, navigate to Technology → Counting → CTRL_HSC_EXT and drag it into a function block. The F1 help for the instruction lists every parameter, including the new PERIOD and FUNCTION selectors.
Sample call inside OB1:
// CTRL_HSC_EXT instance DB "DB_HSC_EXT"
"DB_HSC_EXT"(HSC := 1, // HSC_1
PERIOD := 1000, // 1000 ms measurement window
FUNCTION := 1, // 1 = frequency measurement
MEASURED_FREQ => #MeasFreqHz,
EDGE_COUNT => #EdgeCount,
ERROR => #Err,
STATUS => #Status);
Parameter notes:
- PERIOD sets the integration window in milliseconds. 1000 ms gives a direct Hz reading at 1-second resolution; 100 ms gives 10 Hz steps but updates 10× faster. Trade off noise versus latency.
- MEASURED_FREQ returns Hz as DINT (real * 1000 in some firmwares, raw Hz in V4.2+, confirm via F1 status word).
- EDGE_COUNT is the number of edges captured inside PERIOD, useful as a cross-check against ID1000.
Apply the standard speed equation:
RPM = (EdgeCount × MeasurementFactor) / PeriodTime
where MeasurementFactor = 60 / teeth. With 25 teeth and a 1000 ms window, the formula collapses to RPM = EdgeCount × 2.4. For 416.67 Hz, EdgeCount = 416 or 417 and the displayed RPM = 999.4 to 1000.8, within one pulse of resolution.
Step 4: Cyclic Interrupt OB for Time-Based Counting
When CTRL_HSC_EXT is unavailable (firmware < 4.0) or when a second, independent channel is needed, an OB200 (Cyclic Interrupt) is the standard approach. The pattern is identical to legacy S7-300 work.
- Add a new Cyclic Interrupt OB (default OB200). Set its phase offset to 0 and execution time to 1000 ms for a one-second RPM update.
- Inside OB200, snapshot ID1000 and compute the delta against the previous snapshot stored in a static tag of an FB or in a global DB.
// OB200 - Cyclic Interrupt, 1000 ms
// Input: ID1000 (DINT) - HSC count from CPU
// Tags in global DB "DB_Speed":
// "DB_Speed".PrevCount : DINT
// "DB_Speed".EdgeCount : DINT
// "DB_Speed".RPM : REAL
#EdgeCount := "ID1000" - "DB_Speed".PrevCount;
"DB_Speed".PrevCount := "ID1000";
// EdgeCount pulses per 1000 ms = Hz
// RPM = Hz × 60 / 25 teeth
"DB_Speed".RPM := INT_TO_REAL(#EdgeCount) * 60.0 / 25.0;
Catch for 32-bit overflow: ID1000 is a DINT. At 416.67 Hz it overflows 2,147,483,647 in about 57 days. For an unattended line, reset the count or use a modulo counter in the DB.
Step 5: Linear Speed Calculation
Once RPM is known, linear web speed on the drum is:
V (m/min) = π × D (m) × n (RPM)
For the 800 mm drum at 1000 RPM:
V = π × 0.8 × 1000 = 2513.3 m/min
This is the value at the drum surface, not at the gear. The user case studies a 15 m/min web, which corresponds to roughly 6 RPM at the drum, not 1000 RPM. Confirm which shaft the proximity sensor actually monitors before applying the formula. If the sensor is on a low-speed take-up shaft, the divider changes; if it is on the motor, multiply by the gear ratio between motor and drum.
Reciprocal form (used by the user to back-compute n from a measured V):
n (RPM) = (V (m/min) × 1000) / (π × D (mm))
Substituting V = 15 m/min and D = 800 mm:
n = (15 × 1000) / (π × 800) = 5.97 RPM
Step 6: Memory Allocation Discipline
A common fault on first-time S7-1200 work is overlapping memory tags. The original program read MD201 while MD210 held the snapshot, and MD212 was a DINT that overlapped both. Memory bits and bytes in the M area (and in unoptimized DBs) lay out byte-by-byte, and a DINT occupies 4 consecutive bytes. Use the rules below:
| Data Type | Size (bytes) | Example Tag | Occupies |
|---|---|---|---|
| BOOL | 1 | M10.0 | MB10 |
| INT | 2 | MW10 | MB10, MB11 |
| DINT / REAL | 4 | MD10 | MB10, MB11, MB12, MB13 |
| LREAL | 8 | MD10 | MB10..MB17 |
Step the start addresses of any multi-byte M tag by a multiple of 4 to avoid silent overlap. The clean fix is to declare every speed, count, and status value inside a global DB with structured names, e.g. DB_Speed.RPM_Sec, DB_Speed.RPM_Min, DB_Speed.WebSpeed_mpm. The compiler then manages byte offsets and the cross-reference shows all reads/writes. Search the cross-reference for Ms (or any temporary test tag) and delete them before sign-off.
Step 7: Sensor Wiring and Filtering
Wire the proximity switch to a 24 V DC source from the CPU's sensor power output (terminal 24 V on the front connector). Use a shielded cable with the shield bonded at the cabinet entry, and keep the run away from VFD output cables to avoid capacitive coupling. Confirm the sensor is PNP (sourcing) so that the active-high edge matches HSC expectation on the S7-1200. If the sensor is NPN, add a 4.7 kΩ pull-up to 24 V at the input terminal and verify the resulting logic level.
Set the input filter in the CPU device configuration. The 1212C filter choices are:
- 0.8 µs → 100 kHz
- 1.6 µs → 100 kHz
- 3.2 µs → 100 kHz
- 6.4 µs → 78 kHz
- 12.8 µs → 39 kHz
For 416 Hz, any filter setting works. Use 6.4 µs (78 kHz) when the cable run exceeds 10 m or the installation shares the tray with motor power.
Step 8: Verification and Commissioning
- Force a known frequency from a signal generator or function-generator app on the input. Inject 416.7 Hz at 50% duty, 24 V swing. The online watch table for ID1000 must increment by roughly 416 each second.
- Spin the shaft by hand at a measured RPM. Use a tachometer on the same shaft as a cross-check. Expected reading at 1000 RPM with 25 teeth = 999.6 to 1000.8 RPM, single-pulse resolution.
- Validate
CTRL_HSC_EXToutput MEASURED_FREQ matches the ID1000 delta divided by the PERIOD. - Monitor the HSC STATUS word for non-zero values. STATUS = 0 means healthy. See the S7-1200 system manual HSC error codes for the full list; common values 0x0001 to 0x000F indicate illegal parameter combinations at configuration download.
- Run a 10-minute soak. Watch for dropped counts (HSC_VALUE stops incrementing while the shaft turns), which usually point to filter settings, sensor supply sag, or a wiring shield not terminated.
Troubleshooting Matrix
| Symptom | Likely Cause | Corrective Action |
|---|---|---|
| HSC stays at 0 | Sensor not powered, NPN sensor without pull-up, wrong HSC input pin | Verify 24 V at sensor; confirm input assignment matches wiring; add pull-up if NPN |
| Count is exactly 10× correct value | Tooth count off by factor of 10 (e.g., 250 vs 25) | Re-count teeth on the physical gear |
| Count drifts over time | Filter too slow for actual pulse width, mechanical bounce | Reduce filter time, add hysteresis on sensor target, check for axial runout |
| ERR non-zero on CTRL_HSC_EXT | Function/period combination illegal for the firmware | Check F1 help for supported modes; upgrade firmware to V4.2+ |
| PLC-SIM shows 0 in ID1000 | PLCSIM does not emulate HSC | Test on physical CPU only |
| OB200 does not run | OB200 not assigned a phase/time in the CPU properties | Set phase = 0 ms, time = 1000 ms, download hardware config |
| Overlapping tags give wrong RPM | Multiple multi-byte M tags share bytes | Move all speed-related values into a structured global DB |
| Linear speed is off by factor of π or 60 | Unit mix between m/s, m/min, mm, and RPM | Apply V = π × D × n with consistent units; cross-check with hand tachometer |
Sensor Selection Quick Reference
| Requirement | Minimum Spec | Recommended Spec |
|---|---|---|
| Switching frequency | 1 kHz | 2 kHz or higher for margin |
| Output | PNP, NO | PNP, NO, short-circuit protected |
| Supply | 10–30 V DC | 24 V DC ±10% |
| Repeatability | ≤5% of Sr | ≤2% of Sr |
| Housing | M12 or M18 barrel | M18, IP67, nickel-plated brass |
Generic application guidance on proximity-based RPM sensing (resolution versus pulses per revolution) is summarized in the Opto 22 RPM Measurement Techniques technical note (form 1784), which is independent of the PLC choice and is useful background when justifying the tooth count.
Final Notes on Field Practice
- Capture the calculation basis as a comment block in the FB so the next maintainer sees which shaft and which diameter the constants refer to.
- Save the HSC DB as a know-how-protected block (right-click → Know-how protection) only after the program is signed off, because protected blocks cannot be re-edited without the password.
- If the drum reverses, change the HSC to count continuously with direction control and track direction as a sign on the delta.
CTRL_HSC_EXTfrequency measurement always reports the absolute value, so it cannot directly indicate direction. - When a single CPU must measure more than 6 HSC channels, switch to an SM 1231 high-speed counter signal module. The 1212C only has 6 HSC-capable inputs on the CPU itself.
What is the maximum sensor frequency the CPU 1212C can count?
The onboard HSC inputs Ia.0 through Ia.3 support up to 100 kHz single-phase. Ia.4 and Ia.5 support up to 30 kHz. A 25-tooth gear at 1000 RPM produces only 416.67 Hz, leaving roughly 240× headroom.
Do I need a high-speed counting module for a 25-tooth gear at 1000 RPM?
No. The 416.67 Hz pulse train is well below the onboard limit. An SM 1231 is only required when the application exceeds 6 HSC channels or runs above 100 kHz per channel.
How do I convert HSC counts to RPM?
Use RPM = (EdgeCount × 60) / (Teeth × PeriodSeconds). With 25 teeth and a 1-second OB200 interrupt, RPM = EdgeCount × 2.4. For CTRL_HSC_EXT, RPM = MEASURED_FREQ × 60 / 25.
Why does my linear speed reading not match the drum spec?
Most often the formula is applied to the wrong shaft. The 800 mm drum at 1000 RPM yields 2513 m/min, not 15 m/min. If the spec is 15 m/min, the corresponding shaft is roughly 6 RPM, and the 25-tooth gear at that speed produces only 2.5 Hz. Confirm which shaft the sensor faces and which diameter the V = π × D × n formula uses.
Can S7-PLCSIM validate the HSC code?
No. PLCSIM does not execute high-speed counters. Commission the HSC code on a physical CPU and use a function generator or hand rotation to drive ID1000 and CTRL_HSC_EXT outputs.
What causes the HSC value to freeze or skip counts?
Most often an input filter set too slow, sensor supply sag under load, or a missing shield bond on the sensor cable. Verify 24 V at the sensor terminals under spin and reduce the input filter to 6.4 µs or less.
How do I avoid overlapping memory tags in the M area?
Declare speed and counter values inside a global DB with structured names. The compiler manages byte offsets and the cross-reference shows every read and write, eliminating the manual MW/MD alignment errors that bit the first-time user.