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.