Here’s a practical guide to measuring RPM with common [sensors](https://www.ampheo.com/c/sensors) and a [microcontroller](https://www.ampheo.com/c/microcontrollers). It covers sensor choices, wiring, math, and proven firmware patterns.

**1) Pick a sensing method**
**Digital, easiest**
* Hall-effect + magnet (1–N pulses/rev). Output is open-collector/open-drain → needs pull-up.
* Optical (interrupter or reflective). Clean digital edges; add pull-up if open-collector.
* Incremental encoder (A/B, optional Z). Many counts/rev (PPR/CPR) and direction info.
* PC fan “tach” (FG wire): typically 2 pulses/rev, open-collector.
**Analog, robust at harsh targets**
* Inductive proximity (senses metal teeth/slots): usually digital output.
* VR/magnetic pickup (coil near gear): sine wave amplitude ∝ speed → needs a VR conditioner (comparator or dedicated IC) to square it up.
**Last resort / inference**
Back-EMF in BLDC, frequency of commutation, or analog tachogenerator (voltage ∝ RPM) → measure with ADC and scale.
**2) Condition the signal (make clean edges)**
* Open-collector outputs → add pull-up (e.g., 4.7–10 kΩ to MCU I/O voltage).
* Long/noisy runs → use twisted pair + shield, place a Schmitt trigger (e.g., [74HC14](https://www.onzuu.com/search/74HC14)) near MCU.
* Reed switches → add RC debounce or do it in software.
* VR sensors → rectify/limit and feed a comparator or dedicated VR front-end.
**3) Convert pulses to RPM**
Let PPR = pulses per revolution produced by your sensor arrangement.
Two core strategies:
**A) Frequency (count edges for a fixed time gate)**
Count edges N during a window Tgate.
\text{RPM} = \frac{60}{\text{PPR}} \cdot \frac{N}{T_\text{gate}}
]
Pros: great at high speed. Cons: coarse at low speed unless Tgate is long (more latency).
**B) Period (measure time between two edges)**
Measure period Tperiod between consecutive pulses (use input capture or high-res timer).
\text{RPM} = \frac{60}{\text{PPR} \cdot T_\text{period}}
]
Pros: excellent low-speed resolution and low latency. Cons: jittery at high speed unless you average multiple periods.
Many products use a hybrid: period mode below a threshold, frequency mode above.
**4) Quick examples**
**Fan with 2 pulses/rev at 3000 RPM:**
RPS = 50, pulses/s = 100 Hz. With Tgate=0.1 s you count ≈10 pulses → RPM ≈ 60·10/(0.1·2)=3000.
**Encoder 600 PPR at 120 RPM:**
RPS = 2, pulses/s = 1200 Hz → period ≈ 0.833 ms per pulse → RPM = 60/(600·0.000833) ≈ 120.
**5) MCU implementation patterns**
**(i) Minimal “frequency” method (any MCU)**
* Configure an external interrupt on rising edge to increment a counter.
* Use a periodic timer (e.g., every 100 ms) to snapshot and zero the counter.
```
volatile uint32_t edge_count=0;
volatile uint32_t rpm=0;
void sensor_isr(void){ edge_count++; } // attach to GPIO EXTI
// 100 ms tick
void timer_isr(void){
uint32_t n = edge_count; edge_count = 0;
// RPM = 60/PPR * n / 0.1
rpm = (600 * n) / PPR; // 0.1 s gate → multiply by 600
}
```
**(ii) Precise “period” method (any MCU)**
```
Run a free-running timer (e.g., 1 MHz = 1 µs ticks).
On each edge ISR, compute delta ticks and low-pass/average.
```
```
#define TICKS_PER_SEC 1000000UL
volatile uint32_t last=0;
volatile float rpm=0;
void sensor_isr(void){
uint32_t now = timer_now_ticks(); // read HW timer
uint32_t dt = (now - last); last = now; // handles wrap if unsigned
if (dt>0){
float t = (float)dt / TICKS_PER_SEC; // seconds per pulse
float inst = 60.0f / (PPR * t);
// simple IIR filter for stability
rpm = 0.7f*rpm + 0.3f*inst;
}
}
```
**(iii) [STM32](https://www.ampheo.com/search/STM32) specifics (popular choice)**
* Single channel sensor: use TIMx CHy Input Capture (measures period) or External Clock mode (counts edges).
* Quadrature encoder: set TIMx in Encoder Mode; read CNT at a known rate for speed, and instantly get direction from DIR bit.
* High rates: combine timer input capture + DMA to buffer timestamps with near-zero CPU.
**(iv) [Arduino](https://www.ampheo.com/c/development-board-arduino) quick start (UNO/Nano, Hall sensor)**
* Sensor → D2 (INT0), pull-up enabled.
* Period method using micros() or frequency method with a 100 ms millis() gate as above.
**6) Accuracy, range, and latency**
* Resolution vs latency: Frequency method resolution ≈ 60/(𝑃𝑃𝑅⋅𝑇gate)RPM. Increase Tgate for finer resolution (but slower updates).
* Timer resolution: For period method, RPM resolution improves with higher timer clock (e.g., 1–10 MHz).
* Missing pulses: Add timeout—if no edge for X ms, set RPM=0.
* Averaging: Median of last N periods reduces outliers from noise or wobble.
**7) Common pitfalls (and fixes)**
* Wrong PPR assumption: Verify pulses per rev (many PC fans: 2 PPR; encoders: CPR vs PPR can be confusing).
* Bouncy/mechanical sensors: Debounce (RC or digital).
* Noise & long cables: Shielded cable, Schmitt trigger input, proper grounding.
* Open-collector not pulled up: Add pull-up to the MCU’s logic level.
* VR sensor at low speed: amplitude may be too low—use proper VR interface IC with adaptive thresholds.
* Overflow: Use unsigned arithmetic and handle timer wraparound.
* Direction (encoders): If needed, read A/B with a quadrature decoder, not just one channel.
**8) Calibration & scaling**
* If there’s a gear/belt between sensor and shaft, multiply by the ratio.
* For analog tachogenerators, calibrate slope: RPM = (measured_volts – offset) / (V_per_RPM).
**Quick selection guide**
* One magnet + Hall or reflective tape → simplest; set PPR=1 (or 2, etc.), use period method for low speed, frequency for high.
* Industrial gear/toothed wheel → inductive prox or VR → square up → same math as above.
* Precise motion + direction → incremental encoder → [STM32](https://www.ampheoelec.de/search/STM32) Encoder Mode timer.
* PC fans → read tach wire, assume 2 pulses/rev, add pull-up, use frequency method with 100–250 ms gate.