---
# System prepended metadata

title: How do you measure RPM using sensors?
tags: [Sensor]

---

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.
![Digital-RPM-Meter-Using-Arduino-1024x576](https://hackmd.io/_uploads/rJ_TzU2Fxe.jpg)


**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.