Flaky [sensor](https://www.ampheo.com/c/sensors) readings almost always come from a handful of root causes. Here’s a concise, field-tested checklist to find and fix them fast. ![Make-an-Arduino-Temperature-Sensor-Thermistor-Tutorial-LCD-Output-of-Temperature-Readings](https://hackmd.io/_uploads/ryXwzF2ueg.png) **1) Usual suspects (by category)** **Power & grounding** * Noisy/weak supply: Ripple or droops during sampling. * Fix: local 100 nF at sensor + 1–10 µF bulk nearby; separate analog LDO if needed. * Grounding: Shared digital return currents pollute analog ground. * Fix: star/low-impedance ground, short return for sensor/ADC, single-point AGND↔DGND tie. * Reference noise: ADC Vref not decoupled. * Fix: 100 nF + 1 µF at Vref pin, keep Vref trace short and quiet. **Analog front-end / ADC setup** * Source impedance too high: ADC sample cap can’t charge in time → saggy values. Fix: keep source ≤ 5 kΩ (typical MCUs) or increase sample time/buffer with op-amp. * Aliasing of mains/EMI: Sampling near 50/60 Hz (or harmonics) causes wobble. Fix: RC anti-alias (cutoff < Fs/5), or sample synchronized to mains + average. * Common-mode/amp limits: Instrumentation amp outside input range → clipping/offset. Fix: check headroom vs rails; use proper gain and bias. **Digital comms (I²C/SPI/UART)** * I²C: Wrong pull-ups or long cable → edges rounded, bit errors. Fix: pull-ups 2.2–10 kΩ, keep bus < 400 pF, slow the bus (100–400 kHz), solid GND; check address conflicts/clock stretching. * SPI: CPOL/CPHA mismatch, CS not stable, MISO floating. Fix: verify mode, add series [resistors](https://www.onzuu.com/category/resistors) (22–100 Ω) near master, ensure sensor drives MISO only when CS active. * UART: Baud/format mismatch, noise. Fix: confirm 8-N-1 (etc.), enable CRC/Checksum if available. **Environment & sensor physics** * Warm-up/time constant: Some sensors (gas/IMU/precision temp) need seconds to minutes to stabilize. * Self-heating: Thermistors/RTDs or bridge sensors with too much current. * Fix: duty-cycle excitation, lower current, four-wire/Kelvin for RTD. * Cross-sensitivities: Humidity, airflow, vibration, magnetic fields, light leaks. **Software & math** * Naive averaging: Outliers skew means. Fix: median, trimmed mean, or IIR with outlier rejection. * Scaling/calibration: Wrong units, missing offset/scale. Fix: 2-point (or multi-point) calibration stored in NVM. * Race conditions: Reading multi-byte registers non-atomically; or reading while sensor updates. Fix: use burst reads/locks, respect data-ready/status bits. **2) 15-minute triage flow** 1. Power check: Scope Vcc at the sensor while sampling. Look for > 50–100 mV dips/ripple. 2. ADC sanity: Short ADC input to GND then to Vref/2 (via divider). Noise σ should be near a few LSBs. 3. Comms sanity: Read a fixed ID register 1000×; count errors/timeouts. 4. Static input: Feed a stable source (precision ref or fixed resistor); log 60 s → plot mean/σ. 5. Slow the system: Cut sample rate 10× and average 8–16 samples. If noise improves a lot, you’re aliasing or bandwidth-limited. 6. Isolation test: Power [sensor](https://www.ampheoelec.de/c/sensors) from lab supply; connect GND only to MCU → if readings calm down, your 5 V/3V3 rail is noisy. **3) Solid fixes** **Hardware** * Decouple properly: sensor Vcc (100 nF + 1–10 µF), ADC Vref (100 nF + 1 µF). * RC at ADC pin: e.g., R = 100–1kΩ, C = 1–10 nF right at the pin. * Buffers & amps: Use rail-to-rail op-amp to drive ADC if source Z is high or signal is small. * Cables & shielding: Twisted pair for analog, shield to ground one end; keep high-dv/dt lines away. * I²C pull-ups: Start with 4.7 kΩ at 3.3 V; adjust for length/speed. * Layout: Keep analog traces short, far from clocks/PWM; solid ground under analog. **Firmware** Median / outlier rejection: ``` // 5-sample median (tiny, robust) int16_t median5(int16_t a[5]){ /* small sorting network */ ... } // Simple outlier gate around running mean if (abs(sample - mean) > K*std_est) drop_sample(); ``` IIR low-pass (single-pole): ``` // y += alpha*(x - y); alpha in Q15: 0..32767 y = y + ((alpha * (x - y)) >> 15); ``` * Oversample & decimate: 4× samples → average → +1 bit effective resolution (ideal case). * Synchronize reads: Wait for data-ready / use blocking transfer that reads all bytes in one go. * Calibration template: * Measure raw at two known points (x₁,y₁), (x₂,y₂); store slope/offset. * Apply y = a*x + b each read; optionally temp-compensate with a lookup. **4) Sensor-specific quick checks** * [Thermistor](https://www.onzuu.com/category/thermistor-kits)/RTD: Is the divider reference stable? Use ratiometric with ADC Vref = divider Vref; limit current to avoid self-heating. * Load cell/strain gauge: Shielded cable, INA with proper gain, low-noise supply; sample post-notch for mains. * IMU (accel/gyro): Mounting vibration? Turn on LPF in the device, align ranges, run bias calibration at rest. * Ultrasonic/ToF: Multipath & temperature; compensate speed of sound; average multiple pings. * Gas/pressure: Warm-up time, humidity compensation tables. **5) Quick “is it fixed?” checklist** * σ/peak-to-peak noise within datasheet limits * No CRC/timeout errors on bus * Stable after warm-up (logged over expected temp range) * Calibration stored & reapplied after reboot * Power events (motors, radios) don’t disturb readings