To read a 10K NTC thermistor with an Arduino Uno, you must wire it in a voltage divider circuit with a 10K precision pull-down resistor to analog pin A0, then use the Steinhart-Hart equation in your C++ code to convert the resulting analog voltage into accurate Celsius readings. Unlike digital sensors, thermistors require careful analog conditioning and math to prevent floating-point errors.
Project Overview & Difficulty Rating
Time Required: 30 minutes
Estimated Cost: $8 - $12 USD
Target Board Variant: Arduino Uno R3 (ATmega328P) or Arduino Uno R4 Minima (Renesas RA4M1). The code relies on a 10-bit ADC (0-1023 range) and 5V logic.
Required Parts List
- Microcontroller: Arduino Uno R3 or Uno R4 Minima
- Sensor: 10K NTC Thermistor (e.g., Vishay NTCLE100E3103 or generic 3950 B-value epoxy coated)
- Pull-down Resistor: 10K Ω 1% Metal Film Resistor (1% tolerance is critical for accuracy; do not use a 5% carbon film)
- Wiring: 22 AWG solid core breadboard jumper wires
- Prototyping: Standard 830-point solderless breadboard
Thermistor Specification Sheet
| Parameter | Value | Notes |
|---|---|---|
| Nominal Resistance (R25) | 10,000 Ω | Measured at 25°C (77°F) |
| B-Value (Beta) | 3950 K | Determines the resistance/temperature curve slope |
| Tolerance | ±1% to ±5% | 1% yields ±0.2°C accuracy; 5% yields ±1.5°C |
| Operating Range | -40°C to +125°C | Epoxy coating limits max temp vs. glass bead variants |
| Dissipation Constant | ~2 mW/°C | Used to calculate self-heating errors in still air |
Hardware Wiring & Pin Mapping
A thermistor is a variable resistor. The Arduino cannot read resistance directly; it only reads voltage. We use a voltage divider to convert the changing resistance into a changing voltage that the 10-bit ADC (Analog-to-Digital Converter) can measure.
Pin Mapping Table
| Component Lead | Arduino Uno Pin | Breadboard Rail/Node |
|---|---|---|
| Thermistor Leg 1 | 5V Output | Positive (+) Rail |
| Thermistor Leg 2 | Analog A0 | Shared Node (Junction) |
| 10K Resistor Leg 1 | Analog A0 | Shared Node (Junction) |
| 10K Resistor Leg 2 | GND | Negative (-) Rail |
Wiring Steps
- Insert the 10K NTC thermistor into the breadboard. Connect one leg to the 5V rail using a red jumper wire.
- Insert the 10K 1% metal film resistor so that one leg shares the same breadboard row (node) as the thermistor's second leg.
- Connect the other leg of the 10K resistor to the GND rail using a black jumper wire.
- Run a yellow jumper wire from the shared junction node (where the thermistor and resistor meet) directly to the Arduino's A0 pin.
- Connect the Arduino 5V and GND pins to the breadboard power rails.
Compilable Arduino Code with Error Handling
The following code uses the Steinhart-Hart equation, which is vastly superior to the simpler B-parameter equation for wide temperature ranges. It also includes oversampling (averaging 16 reads) to smooth out the ATmega328P's ADC noise, and explicit bounds checking to prevent math crashes.
#include <math.h>
// --- Pin Definitions ---
#define THERMISTOR_PIN A0
// --- Hardware Constants ---
#define SERIES_RESISTOR 10000.0 // Value of the pull-down resistor (10K)
#define ADC_MAX 1023.0 // 10-bit ADC maximum value
#define NUM_SAMPLES 16 // Oversampling count for noise reduction
// --- Steinhart-Hart Coefficients for standard 10K 3950 NTC ---
// Derived from manufacturer datasheet resistance/temperature tables
#define SH_A 1.1292421e-3
#define SH_B 2.3410774e-4
#define SH_C 0.8762678e-6
void setup() {
Serial.begin(115200);
while (!Serial); // Wait for serial monitor (required for Uno R4 / Leonardo)
Serial.println("Thermistor initialized. Reading temperatures...");
}
void loop() {
// 1. Oversample the ADC to reduce noise
float adc_average = 0;
for (int i = 0; i < NUM_SAMPLES; i++) {
adc_average += analogRead(THERMISTOR_PIN);
delay(2); // Small delay to allow ADC sample-and-hold capacitor to settle
}
adc_average /= NUM_SAMPLES;
// 2. Error Handling: Prevent division by zero and log(0) math errors
if (adc_average < 1.0) {
Serial.println("Error: ADC reads 0. Check for short circuit to GND.");
delay(2000);
return;
}
if (adc_average >= ADC_MAX) {
Serial.println("Error: ADC reads 1023. Check for open circuit or disconnected thermistor.");
delay(2000);
return;
}
// 3. Calculate Thermistor Resistance
// Formula: R_therm = R_series * ((ADC_MAX / ADC_avg) - 1)
float resistance = SERIES_RESISTOR * ((ADC_MAX / adc_average) - 1.0);
// 4. Steinhart-Hart Equation to calculate Temperature in Kelvin
float logR = log(resistance);
float temp_kelvin = 1.0 / (SH_A + (SH_B * logR) + (SH_C * pow(logR, 3)));
// 5. Convert to Celsius and Fahrenheit
float temp_celsius = temp_kelvin - 273.15;
float temp_fahrenheit = (temp_celsius * 9.0 / 5.0) + 32.0;
// 6. Output Data
Serial.print("Raw ADC: ");
Serial.print(adc_average, 1);
Serial.print(" | Resistance: ");
Serial.print(resistance, 0);
Serial.print(" ohms | Temp: ");
Serial.print(temp_celsius, 2);
Serial.print(" C (");
Serial.print(temp_fahrenheit, 2);
Serial.println(" F)");
delay(1000);
}
Debugging: Fixing "nan" Readings and Temperature Drift
When working with analog sensors and logarithmic math, the Serial Monitor will occasionally output Temperature: nan C (Not a Number) or inf (Infinity). This happens when the microcontroller attempts to calculate the logarithm of zero or divide by zero.
The First Three Things to Check When It Fails
- Verify the Raw ADC Value: Comment out the math and print the raw
analogRead()value. If it sits solidly at0or1023, you have a hardware wiring fault, not a code bug. - Multimeter Continuity Test: De-energize the board. Use your multimeter's continuity mode to check the breadboard junction node. Solderless breadboards frequently suffer from broken internal leaf springs, causing an open circuit between the thermistor and the A0 jumper wire.
- Check Power Rail Polarity: Ensure your 5V and GND rails aren't swapped. Reversing the voltage divider won't destroy the thermistor, but it will pull the A0 pin below 0V, which the ATmega328P's internal protection diodes will clamp, resulting in erratic, non-linear ADC readings.
Ranked Causes for "nan" Errors
If your serial monitor explicitly prints nan or inf during the Steinhart-Hart calculation, here are the root causes ranked by probability:
- Open Circuit (ADC = 1023): The thermistor is disconnected. The A0 pin reads 5V. The math attempts to calculate
(1023/1023) - 1 = 0. Thelog(0)function returns-inf, corrupting the final temperature variable intonan. - Short Circuit (ADC = 0): The A0 pin is shorted to GND. The math attempts to divide by zero when calculating
1023 / 0, yieldinginfresistance. - Incorrect Coefficients: If you copied Steinhart-Hart coefficients from a 10K thermistor but are using a 100K thermistor, the resistance calculation will be wildly out of bounds, pushing the math into floating-point overflow.
INPUT_PULLUP) in place of a physical 10K pull-down resistor. The internal pull-up is roughly 20K-50K and highly imprecise (±30% tolerance), which will destroy your temperature accuracy.
Extending and Simplifying the Build
How to Extend for Higher Precision
The standard Arduino Uno ADC uses the 5V rail as its reference. If your 5V USB power sags to 4.7V (common with cheap PC USB ports), your temperature readings will drift. To fix this, use the Arduino's internal 1.1V reference by adding analogReference(INTERNAL); in your setup() block. Note: You must change the voltage divider to drop the max voltage below 1.1V, or use a 3.3V Arduino variant and use analogReference(EXTERNAL) tied to a precision 3.3V LDO.
For data logging, extend the build by adding an I2C OLED display (SSD1306) or logging the temp_celsius variable to a MicroSD card module via SPI.
How to Simplify the Build
If the Steinhart-Hart math, ADC noise, and voltage divider wiring feel like overkill for your application, simplify the build by abandoning analog thermistors entirely. Swap the NTC thermistor for a DS18B20 digital temperature sensor. The DS18B20 handles the ADC conversion and linearization internally, communicating via the 1-Wire protocol. It requires only a single 4.7K pull-up resistor and the OneWire and DallasTemperature Arduino libraries, eliminating floating-point math errors completely.
Frequently Asked Questions
Can I use a 10K thermistor with Arduino without a pull-down resistor?
No. A thermistor is a passive resistive component; it does not output a voltage on its own. The Arduino's analog pins measure voltage potential relative to GND. Without a pull-down (or pull-up) resistor to create a voltage divider, the A0 pin is left "floating." A floating pin will pick up ambient electromagnetic interference, resulting in random, rapidly fluctuating ADC values that have no correlation to temperature.
Why is my thermistor with Arduino reading 2 degrees higher than ambient?
This is almost always caused by self-heating or thermal conduction. First, calculate your dissipation: if you are powering the divider continuously from a 5V rail, the current generates a small amount of heat inside the thermistor's epoxy body. Second, check your breadboard layout. If the thermistor leads are bent too close to the Arduino's onboard voltage regulator or microcontroller, heat will travel up the copper leads (thermal conduction) directly into the sensor bead. Keep the thermistor at least 3 inches away from heat-generating components, or use longer twisted-pair wires.
How do I waterproof a thermistor with Arduino for liquid measurements?
Standard epoxy-coated NTC thermistors are moisture-resistant but not fully waterproof for prolonged submersion; water ingress will eventually alter the resistance baseline. For liquid measurements (like brewing, hydroponics, or aquariums), purchase a stainless steel probe-encapsulated NTC thermistor. These feature the thermistor bead potted inside a sealed metal tube with a PVC or silicone cable. Ensure the Arduino and breadboard remain in a dry enclosure, and route the probe wires through a drip loop to prevent water from wicking back into your electronics.
What is the difference between NTC and PTC thermistors for Arduino projects?
NTC (Negative Temperature Coefficient) thermistors decrease in resistance as temperature rises. They are highly sensitive and used for precision temperature measurement. PTC (Positive Temperature Coefficient) thermistors increase in resistance as temperature rises. PTCs are rarely used for precision measurement; instead, they are used as self-resetting fuses (overcurrent protection) or crude heating elements. For Arduino temperature sensing projects, you should almost exclusively use NTC thermistors. Always verify the datasheet to confirm you have an NTC variant before wiring it to your microcontroller.






