A passive resistance sensor changes its electrical resistance in response to a physical stimulus like temperature, light, or force. Because microcontrollers cannot measure ohms directly, you must convert this resistance change into a measurable analog voltage using a voltage divider circuit, then read it via an Analog-to-Digital Converter (ADC). This guide provides the exact wiring, raw-to-unit math, and calibration steps to interface these sensors reliably with 3.3V and 5V logic boards.
The Sensing Principle
Variable resistance sensors rely on material properties that shift under physical stress. For example, Negative Temperature Coefficient (NTC) thermistors use sintered metal-oxide semiconductors; as heat increases, more charge carriers are freed, causing resistance to drop exponentially. Force Sensitive Resistors (FSRs) use carbon-impregnated polymers where physical pressure increases the contact area between conductive particles, lowering resistance. Unlike active digital sensors (e.g., the DS18B20) that output pre-calibrated serial data, passive resistance sensors are strictly analog components.
Because an MCU's GPIO pins only understand digital logic or voltage levels, the varying resistance must be translated into a voltage. This is universally achieved using a voltage divider: pairing the unknown sensor resistance with a known fixed resistor. As the sensor's resistance fluctuates, the voltage at the junction between the two resistors shifts proportionally, creating an analog signal the MCU's ADC can sample.
Wiring and Pin Mapping
The most stable configuration places the resistance sensor on the high side (connected to VCC) and the fixed reference resistor on the low side (connected to GND). This ensures that as the sensor's resistance drops (e.g., an NTC getting hotter, or an FSR being squeezed), the output voltage rises, yielding a positive correlation that is easier to debug.
| Component / Node | Connection | Notes & Supply Range |
|---|---|---|
| Sensor Pin 1 | VCC (3.3V or 5V) | Use 3.3V for ESP32/RPi Pico; 5V for Arduino Uno. Never exceed sensor max power rating. |
| Sensor Pin 2 | ADC Pin & Fixed Resistor | Junction point. Keep leads short to avoid capacitive coupling. |
| Fixed Resistor (10kΩ) | ADC Pin & GND | Value should roughly match the sensor's nominal resistance at room temp. |
| Bypass Capacitor (100nF) | ADC Pin to GND | Filters high-frequency EMI and stabilizes the sample-and-hold circuit. |
Output Signal Math: Raw ADC to Physical Units
The output of a resistance sensor circuit is strictly an analog voltage between 0V and VCC. To get a physical unit (like Celsius), you must perform a two-step conversion: Raw ADC to Resistance, then Resistance to Physical Unit.
Step 1: Raw ADC to Sensor Resistance ($R_t$)
Assuming a 12-bit ADC (4095 max reading) and a 10kΩ fixed reference resistor ($R_s$), the voltage divider math simplifies beautifully. You do not need to calculate the intermediate voltage if VCC is exactly the ADC reference voltage:
$R_t = R_s \times \left( \frac{ADC_{max}}{ADC_{raw}} - 1 \right)$
For a 10kΩ fixed resistor on a 12-bit ESP32: $R_t = 10000 \times \left( \frac{4095}{ADC_{raw}} - 1 \right)$
Step 2: Resistance to Temperature (Steinhart-Hart Equation)
For NTC thermistors, the resistance-to-temperature curve is highly non-linear. The Steinhart-Hart equation models this curve with high precision. You will need the A, B, and C coefficients from your specific sensor's datasheet (or calculate them using three calibration points).
$\frac{1}{T_k} = A + B \ln(R_t) + C (\ln(R_t))^3$
Where $T_k$ is temperature in Kelvin. Subtract 273.15 to get Celsius. For a standard 10kΩ NTC (like the ubiquitous EPCOS/Murata 10k B=3950), the coefficients are approximately: A = 0.001129148, B = 0.000234125, C = 0.0000000876741. For deeper theory on semiconductor thermistors, refer to the All About Circuits thermistor chapter.
Calibration, Scaling, and Interference
While the math is straightforward, real-world bench conditions introduce errors that require mitigation. Understanding these interference sources is the difference between a toy project and a reliable instrument.
- Self-Heating Error: Current flowing through the sensor generates heat ($P = I^2R$). If your fixed resistor is too small (e.g., 1kΩ), the sensor will heat itself, reading 2-5°C higher than ambient. Always use a fixed resistor ≥ 10kΩ to keep current below 330µA.
- ESP32 ADC Non-Linearity: The ESP32's internal ADC is notoriously non-linear at the extremes. Readings below 0.15V (ADC < 150) and above 3.1V (ADC > 3800) are highly inaccurate. Design your voltage divider so the expected operating range falls between 0.5V and 2.8V.
- Electromagnetic Interference (EMI): High-impedance analog nodes act as antennas for 50/60Hz mains hum and switching noise from DC-DC converters. The 100nF bypass capacitor at the ADC pin is mandatory, not optional. For runs longer than 12 inches, use shielded twisted-pair cable.
- VCC Ripple: If your 3.3V rail has 50mV of ripple from a cheap buck converter, your ADC reading will fluctuate wildly. Power the sensor divider from a clean LDO or use the MCU's internal precision voltage reference if available.
Decision Tree: Which Resistance Sensor to Pick
Not all resistance sensors are created equal. Use this decision matrix to select the correct component for your physical measurement, terminating in a concrete default pick for the most common embedded use case.
| If you are measuring... | And your constraints are... | Choose this Sensor Type | Specific Part Recommendation |
|---|---|---|---|
| Temperature (-50 to 150°C) | High precision (<0.1°C), industrial environment | PT100 RTD | Requires MAX31865 amplifier IC. Not a direct MCU interface. |
| Temperature (-40 to 85°C) | Low cost, direct ADC read, compact PCB footprint | 10kΩ NTC Thermistor | DEFAULT PICK: Murata NCP18XH103F03RB (0603 SMD) or EPCOS B57891M0103K000 (Epoxy radial). |
| Ambient Light | Simple day/night triggering, non-linear lux is acceptable | Cadmium Sulfide (CdS) LDR | GL5528 (10k-20kΩ at 10 lux). Note: RoHS restricted in EU. |
| Physical Force / Pressure | 0.2N to 20N, robotics grippers or foot switches | Force Sensitive Resistor (FSR) | Interlink FSR 402 (0.2 to 20N range, 0.5" active area). |
The Verdict: For 90% of hobbyist and commercial IoT temperature monitoring tasks where a digital sensor (like the DS18B20) is unavailable or too bulky, the Murata NCP18XH103F03RB 10kΩ NTC is the definitive choice. It offers a tight ±1% tolerance, a predictable B-constant (3380K), and fits easily into automated pick-and-place assembly.
Step-by-Step Implementation (ESP32)
Follow these steps to wire, code, and verify a Murata 10kΩ NTC thermistor on an ESP32 DevKit V1.
- Build the Divider: Connect the NTC thermistor between 3.3V and GPIO34. Connect a 10kΩ 1% tolerance fixed resistor between GPIO34 and GND.
- Add Filtering: Solder or breadboard a 100nF (0.1µF) ceramic capacitor directly across GPIO34 and GND, as close to the ESP32 pin as possible.
- Upload the Firmware: Flash the following C++ code using the Arduino IDE (Board: ESP32 Dev Module).
// ESP32 NTC Thermistor Interfacing
// Hardware: 10k NTC to 3.3V, 10k Fixed to GND, Junction to GPIO34
const int ADC_PIN = 34;
const float VCC = 3.3;
const float R_FIXED = 10000.0; // 10k Ohm reference resistor
const int ADC_MAX = 4095; // 12-bit resolution
// Steinhart-Hart Coefficients for standard 10k NTC (B=3950)
const float A = 0.001129148;
const float B = 0.000234125;
const float C = 0.0000000876741;
void setup() {
Serial.begin(115200);
analogReadResolution(12); // Ensure 12-bit mode
Serial.println("NTC Sensor Initialized...");
}
void loop() {
// Read raw ADC and average to reduce noise
long adc_sum = 0;
for(int i = 0; i < 16; i++) {
adc_sum += analogRead(ADC_PIN);
delay(2);
}
int adc_raw = adc_sum / 16;
// Prevent divide-by-zero if sensor is disconnected
if (adc_raw <= 0) adc_raw = 1;
if (adc_raw >= ADC_MAX) adc_raw = ADC_MAX - 1;
// Calculate Sensor Resistance
float R_t = R_FIXED * ((float)ADC_MAX / (float)adc_raw - 1.0);
// Steinhart-Hart Equation
float logRt = log(R_t);
float tempK = 1.0 / (A + B * logRt + C * logRt * logRt * logRt);
float tempC = tempK - 273.15;
Serial.printf("ADC: %d | R_ntc: %.1f Ohms | Temp: %.2f C\n", adc_raw, R_t, tempC);
delay(1000);
}
- Verify with a Multimeter: Before trusting the serial monitor, use a digital multimeter to measure the DC voltage at GPIO34. At 25°C, the NTC is ~10kΩ, meaning the voltage should read exactly half of VCC (approx 1.65V). If your multimeter reads 1.65V but the serial monitor reports 2.0V, your VCC rail is sagging or the ADC is uncalibrated.
- Apply Offset Calibration: If the reading is consistently off by a fixed amount (e.g., +1.2°C) due to self-heating or PCB thermal mass, subtract this offset in the final
tempCcalculation rather than altering the Steinhart-Hart coefficients.






