A steadier reading
Every ADC flickers in its last count or two, and near room temperature one Uno count is about a tenth of a degree. Averaging 32 readings before converting takes a few milliseconds and holds the printed temperature still.
The last count flickers
Leave the block alone on a desk and print the count many times a second. It will not sit on one number. The last count or two wanders up and down: some of that is electrical noise the capacitor did not catch, and some is the ADC itself deciding which side of a step a voltage falls on. Every ADC does it.
Near room temperature on an Uno, one count is about 0.09 °C. So a flicker of three counts makes the printed temperature jump by a quarter of a degree while nothing has changed.
The noise in the figure is drawn, not recorded, but the arithmetic is general. Averaging N readings shrinks random flicker by about the square root of N: 8 readings make it nearly three times steadier, 32 nearly six.
Averaging in the sketch
The change is in thermistorOhms() and nowhere else. Instead of one
analogRead, it takes SAMPLES of them, adds them up and divides, and only
then works out the resistance. An Uno's analogRead takes about a tenth of a
millisecond, so 32 cost about 3 ms, once a second.
The sketch now prints two decimal places, because now the second one means something. It does not mean the answer is right to a hundredth of a degree. How far to trust it is about the difference between steady and correct.
The code
The counts-to-degrees sketch, with one change: thermistorOhms() takes SAMPLES readings and averages them before doing any arithmetic.
/*
NTC Thermistor - a steadier reading TK12 / /p/tk12
Wiring. Count from the square pad on the TinkerBlock board, parts
up, header at the bottom:
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
(SIGNAL is a fraction of VCC, so it stays in range)
NC -> nothing (unconnected on the board)
SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
ESP32-S3, GP26 on a Raspberry Pi Pico
Arduino IDE
Tools > Board your board, e.g. Arduino Uno
Tools > Port the one that appears when you plug in
Tools > USB CDC On Boot Enabled (ESP32-S3 only)
No library needed.
*/
#include <math.h>
// The analog pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int SENSOR_PIN = A0;
const int SAMPLES = 32; // readings averaged per answer
const float R_FIXED = 10000.0; // the 10 kOhm from VCC to SIGNAL
const float R25 = 10000.0; // the thermistor at 25 C: the "103"
const float B = 3950.0; // its B value: the "3950"
const float T0 = 298.15; // 25 C in kelvin
const float VCC_MV = 3300.0; // ESP32 only: your 3V3 pin, measured
float thermistorOhms() {
float sum = 0;
#if defined(ARDUINO_ARCH_ESP32)
for (int i = 0; i < SAMPLES; i++) sum += analogReadMilliVolts(SENSOR_PIN);
float mv = sum / SAMPLES;
if (mv <= 0 || mv >= VCC_MV) return NAN;
return R_FIXED * mv / (VCC_MV - mv);
#else
for (int i = 0; i < SAMPLES; i++) sum += analogRead(SENSOR_PIN);
float n = sum / SAMPLES;
if (n <= 0 || n >= 1023) return NAN;
return R_FIXED * n / (1023.0 - n);
#endif
}
float celsius(float ohms) {
float invT = 1.0 / T0 + log(ohms / R25) / B;
return 1.0 / invT - 273.15;
}
void setup() {
Serial.begin(115200);
}
void loop() {
float r = thermistorOhms();
if (isnan(r)) {
Serial.println("SIGNAL at 0: check VCC. At the top: check GND.");
} else {
Serial.print(celsius(r), 2);
Serial.println(" C");
}
delay(1000);
}32 readings on an Uno take about 3 ms. On an ESP32 each analogReadMilliVolts call is slower but the total is still a few milliseconds, once a second. VCC_MV only matters on an ESP32.
The same average in MicroPython: SAMPLES readings summed, divided, and only then turned into a resistance and a temperature.
"""
NTC Thermistor - a steadier reading, MicroPython TK12 / /p/tk12
Wiring. Count from the square pad on the TinkerBlock board, parts
up, header at the bottom:
GND -> GND
VCC -> 3V3 (SIGNAL is a fraction of VCC)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3,
GP26 on a Raspberry Pi Pico
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
Save it to the board as main.py to run it on every power-up.
Nothing to install: machine, math, sys and time are built in.
"""
import math
import sys
import time
from machine import ADC, Pin
# The GPIO number SIGNAL is wired to. ESP32: 34. ESP32-S3: 4. Pico: 26.
SENSOR_PIN = 4
SAMPLES = 32 # readings averaged per answer
R_FIXED = 10000 # the 10 kOhm from VCC to SIGNAL
R25 = 10000 # the thermistor at 25 C: the "103"
B = 3950 # its B value: the "3950"
T0 = 298.15 # 25 C in kelvin
VCC = 3.3 # ESP32 only: your 3V3 pin, measured
adc = ADC(Pin(SENSOR_PIN))
ESP = sys.platform == "esp32" # ESP32 and ESP32-S3
if ESP:
adc.atten(ADC.ATTN_11DB) # the full range, to about 3.1 V
def thermistor_ohms():
total = 0
for _ in range(SAMPLES):
if ESP:
total += adc.read_uv() / 1000000 / VCC
else:
total += adc.read_u16() / 65535
ratio = total / SAMPLES
if ratio <= 0 or ratio >= 1:
return None
return R_FIXED * ratio / (1 - ratio)
def celsius(ohms):
return 1 / (1 / T0 + math.log(ohms / R25) / B) - 273.15
while True:
r = thermistor_ohms()
if r is None:
print("SIGNAL at 0: check VCC. At the top: check GND.")
else:
print("%.2f C" % celsius(r))
time.sleep(1)On an ESP32 read_uv gives calibrated microvolts and VCC is your measured 3V3 pin; on a Pico read_u16 is already a fraction. Stop it with Ctrl-C.
When it does not work
The readings, before converting. It is one conversion instead of 32, and over the few counts of flicker involved the curve is straight enough that the two give the same answer to well under a tenth of a degree.
16 to 64 is plenty. Averaging N readings cuts random flicker by about the square root of N, so 32 is nearly six times steadier than one, and 128 only twice as steady again. Past a point you are polishing a number the parts cannot promise.
That is not ADC flicker. Look for a real cause: a draught, a hand near it, or on a classic ESP32 an ADC2 pin with Wi-Fi on. Averaging hides small random noise; it will not fix a wrong pin or a warm neighbour.
Yes: keep the last N readings and print their mean each time a new one arrives. It gives a new value every loop instead of every N. The simple block average here is easier to read and is what the figure shows.
A TK01 that lights when it gets warm, and does not flicker at the line.
A temperature alarm →Edit this page — content/books/ntc-thermistor/a-steadier-reading.mdx
Questions about this product
See what other owners have asked, and read their solutions.
NTC Thermistor
Loading discussions…
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.