The Sensing Principle: How Resistance Sensors Work
Resistance sensors—such as NTC thermistors, photoresistors (LDRs), and flex sensors—do not generate their own electrical signal. Instead, their internal resistance (measured in Ohms) changes predictably in response to a physical stimulus like temperature, light intensity, or mechanical bending. The raw output of these components is strictly a variable resistance; they do not natively output a voltage, current, or digital data stream.
Because microcontrollers cannot measure resistance directly, you must pass a known current through the sensor or place it in a voltage divider network. This converts the changing resistance into a proportional analog voltage (typically 0V to 3.3V), which the microcontroller's Analog-to-Digital Converter (ADC) can then sample and digitize into a raw integer value for your code to process.
Wiring and Hardware Setup
For this guide, we are using an ESP32 DevKit v1 and a standard 10kΩ NTC thermistor. The ESP32 operates at 3.3V logic, meaning our voltage divider must be referenced to 3.3V to prevent damaging the ADC pins. We use a 10kΩ 1% metal film fixed resistor to create the divider.
| Component / Pin | Connection | Notes & Supply Range |
|---|---|---|
| 3.3V Pin (ESP32) | Fixed Resistor (Leg 1) | Supply Range: 3.2V - 3.4V. Use the dedicated 3V3 pin, not VIN. |
| Fixed Resistor (Leg 2) | Sensor (Leg 1) & GPIO 34 | This junction is V_out. Add a 100nF ceramic cap to GND here to filter EMI. |
| Sensor (Leg 2) | GND (ESP32) | Completes the circuit. Keep this ground path short and direct. |
| GPIO 34 (ESP32) | ADC1_CH6 Input | Input only pin. Safe for ADC use even when WiFi is active (unlike ADC2). |
The Math: Converting Raw ADC Readings to Physical Units
Getting a number from analogRead() is only the first step. To make the data useful, you must mathematically reverse the voltage divider, then apply a sensor-specific transfer function. Here is the exact raw-to-unit math for an ESP32 (12-bit ADC) reading an NTC thermistor.
Step 1: Raw ADC to Voltage
The ESP32's 12-bit ADC yields values from 0 to 4095. Assuming a 3.3V reference:
V_out = (ADC_raw / 4095.0) * 3.3
Example: If ADC_raw is 2048, V_out = (2048 / 4095) * 3.3 = 1.65V.
Step 2: Voltage to Resistance
Using the voltage divider formula, we solve for the sensor's resistance ($R_{sensor}$). With the fixed resistor ($R_{fixed}$) on top and the sensor on the bottom:
R_sensor = R_fixed * (V_out / (3.3 - V_out))
Example: With a 10,000Ω fixed resistor and 1.65V out: R_sensor = 10000 * (1.65 / 1.65) = 10,000Ω (10kΩ).
Step 3: Resistance to Physical Unit (Steinhart-Hart)
For NTC thermistors, resistance does not scale linearly with temperature. We use the Steinhart-Hart equation to calculate the temperature in Kelvin, then convert to Celsius. You will need the A, B, and C coefficients from your specific thermistor's datasheet.
1 / T = A + (B * ln(R_sensor)) + (C * (ln(R_sensor))^3)
T_celsius = (1 / T) - 273.15
For a standard 10kΩ NTC (like the Vishay NTCLE100E3103), a simplified Beta parameter equation is often sufficient for hobbyist ranges (-20°C to +80°C):
T_celsius = (1 / ((1 / 298.15) + (1 / 3950) * ln(R_sensor / 10000))) - 273.15
Interference, Calibration, and Edge Cases
Analog resistance sensors are highly susceptible to environmental and electrical noise. If your readings are jumping around, you are likely hitting one of these common interference sources:
- ADC Non-Linearity: The ESP32's ADC is notoriously non-linear at the extremes (near 0V and 3.3V). Keep your operating voltage between 0.15V and 3.15V. Use the ESP-IDF ADC calibration API or
analogReadMilliVolts()in Arduino to apply factory eFuse calibration data. - EMI and High Impedance: A 10kΩ divider creates a relatively high-impedance node at the ADC pin, making it an antenna for RF noise (especially from the ESP32's own WiFi radio). Soldering a 100nF ceramic capacitor directly between the ADC pin and GND creates a low-pass filter that stabilizes the reading.
- Self-Heating: Passing too much current through a thermistor causes it to heat itself, skewing the ambient temperature reading. A 10kΩ resistor on a 3.3V rail limits current to 330µA, dissipating roughly 1mW of heat—well below the typical 2mW/°C dissipation constant of glass-encapsulated NTCs.
Calibration Note: If you are using a flex sensor or force-sensitive resistor (FSR) instead of a thermistor, the Steinhart-Hart equation does not apply. These require empirical multi-point calibration. Record the ADC values at three known physical states (e.g., 0°, 45°, 90° bend), then use polynomial regression in Python or Excel to generate a custom scaling curve for your code.
Frequently Asked Questions
How do I calibrate analog resistance sensors for accurate readings?
Calibration depends on the sensor type. For thermistors, use the manufacturer's Steinhart-Hart coefficients or measure the actual resistance at three known temperatures (e.g., ice water at 0°C, boiling water at 100°C, and room temperature) to calculate custom A, B, and C constants. For photoresistors or flex sensors, perform a multi-point physical calibration: record the raw ADC output at known physical thresholds, then map those values using linear interpolation or a polynomial curve fit in your microcontroller code.
Why do resistance sensors require a voltage divider circuit?
Microcontroller ADC pins measure voltage potential, not resistance. A resistance sensor alone simply restricts current flow; it does not generate a voltage signal. By placing the sensor in a voltage divider with a known fixed resistor, you force the changing resistance to alter the voltage drop across the sensor. This translates the physical property (Ohms) into an electrical property (Volts) that the ADC can quantify.
What causes self-heating errors in NTC resistance sensors?
Self-heating occurs when the electrical power dissipated by the sensor ($P = I^2R$ or $P = V^2/R$) raises the temperature of the sensor's internal element above the ambient environment. If you use a low-value fixed resistor (e.g., 1kΩ) with a 10kΩ thermistor on a 5V rail, the current flow generates excess heat inside the thermistor bead. To prevent this, use higher-value fixed resistors (10kΩ to 100kΩ), lower the supply voltage to 3.3V, or power the divider from a GPIO pin that you only drive HIGH for a few milliseconds right before taking the ADC reading.






