NTC thermistor/Reading it/06. Counts to degrees
Reading it · 06 of 12

Counts to degrees

Two lines of arithmetic: the count back to the thermistor's resistance, and the resistance to degrees with the B equation. They are exact at 25 °C by construction and good across the range. A straight map() is exact at two temperatures and wrong everywhere else.

Two steps

A count is not a temperature. Between them are two conversions, and each is one line.

Count to resistance. On an Uno the count is SIGNAL as a fraction of VCC, out of 1023, and the divider says what the thermistor must be to give that fraction:

R_ntc = 10000 × count / (1023 − count)

Resistance to degrees. The B model from the second article, solved for T:

1/T = 1/298.15 + ln(R_ntc / 10000) / 3950

T comes out in kelvin; subtract 273.15 for Celsius.

Counts to degrees
analogRead on an Uno512
Thermistor
10.0 kΩ
B equation
25.0 °C
map()
26.6 °C
A count of 512 means the thermistor is 10.0 kΩ, and the B equation says 25.0 °C. The straight line says 26.6 °C: 1.7 °C too warm. It was exact at 0 and 50 °C and has no way to follow the bend anywhere else.

Slide the count and follow the orange curve: every count has exactly one temperature, and the curve bends at both ends. At 512, halfway, the thermistor is 10 kΩ and the answer is 25 °C, which is the B model's fixed point.

Why not map()

The grey line is map() told that the count at 0 °C means 0 and the count at 50 °C means 50. It is exact at those two points and up to about 2 °C off between them. Outside them it has no way to bend: by 75 °C it reads more than 10 °C low, and by 100 °C about 30. Choosing different points moves the error; it does not remove it.

What you should see

The serial monitor prints the resistance and the temperature once a second:

10751 ohm   23.4 C
10751 ohm   23.4 C
10793 ohm   23.3 C
8499 ohm   28.7 C

The last line is a finger on the thermistor. If the line reads SIGNAL at 0 or At the top, the arithmetic is fine and a wire is missing: the sketch refuses to take the logarithm of a reading that cannot be a temperature.

The code

The whole chain: read SIGNAL, work out the thermistor's resistance, and turn that into degrees with the B equation. On an ESP32 the first step reads millivolts instead of a count, for the reason in the article after this one.

ntc_degrees.ino
/*
  NTC Thermistor - counts to degrees                     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 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

// The thermistor's resistance, or NAN if SIGNAL is at either end.
float thermistorOhms() {
#if defined(ARDUINO_ARCH_ESP32)
  // Own reference: calibrated millivolts, over what VCC is.
  float mv = analogReadMilliVolts(SENSOR_PIN);
  if (mv <= 0 || mv >= VCC_MV) return NAN;
  return R_FIXED * mv / (VCC_MV - mv);
#else
  // Uno, Pico: the count is already a fraction of VCC.
  float n = analogRead(SENSOR_PIN);
  if (n <= 0 || n >= 1023) return NAN;
  return R_FIXED * n / (1023.0 - n);
#endif
}

// The B equation, backwards: resistance to degrees Celsius.
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(r, 0);
    Serial.print(" ohm   ");
    Serial.print(celsius(r), 1);
    Serial.println(" C");
  }
  delay(1000);
}

R25 and B are the 103 and the 3950 from the thermistor's part number. VCC_MV only matters on an ESP32: measure the 3V3 pin with a multimeter and put the reading in, and the answer improves. On an Uno and a Pico there is nothing to measure.

When it does not work

It prints a temperature that falls when I warm it.

The resistance line is upside down: it was written for a board with the thermistor on top. On this block the thermistor is the lower half, so it is 10000 × n / (1023 − n). Swap it and warming it will raise the number.

It prints nan, inf or -273.

The count was 0 or the maximum, so the resistance came out as zero or infinite, and a logarithm of either is not a number. That is VCC or GND missing, not arithmetic. The sketch here catches both and prints which wire to check.

Why not use the Steinhart–Hart equation?

It follows a thermistor's curve more closely than the B model, but it needs three constants fitted to the part's own resistance table, and this part's table was not available. With only 10 kΩ and B = 3950 to go on, the B equation is what the numbers support.

Do I need float, or will int do?

Float. The logarithm and the division by B produce small fractions that an int rounds to zero. An Uno's float is slower than an int but still does this in well under a millisecond, once a second.

Where this goes next

Its own reference, a range that stops short of 3.3 V, and millivolts instead of counts.

Reading it on an ESP32

Edit this page — content/books/ntc-thermistor/counts-to-degrees.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

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.

Browse Modules and blocks on the forum