Low Cost, High Accuracy Temperature Sensing with a Thermistor

For many microcontroller projects requiring accurate temperature sensing the sensor of choice is the Maxim DS18B20.  Although this has a specified absolute accuracy of +/- 0.5°C, it has several drawbacks, not least of which is its relatively high cost.  For my prototype sensors I incorporated a TI TMP112, which is an I2C device with a minimum operating voltage of 1.4 V, making it particularly attractive for battery powered applications.  My preferred option for cost-reduction, however, has always been to use a cheap thermistor with the microcontroller’s built-in analogue to digital converter (ADC).

This post discusses the evaluation of a thermistor-based technique for small embedded systems capable of achieving uncalibrated temperature accuracy to rival expensive digital sensors.  An experimental comparison of various sensors over temperature is then introduced.

There are a few challenges in using a thermistor well.  Firstly, care must be taken to measure its resistance accurately, and secondly some characteristics of the thermistor need to be obtained, either from the datasheet or experimentally, and applied to a model in order to derive the actual temperature.  The formula that is usually used for this calculation is the Steinhart-Hart equation, which is not well suited for calculation on an 8-bit micro.

To solve the first problem the thermistor is used in a potential divider configuration as one might expect, but with the ADC configured to use the supply rail as its reference.  This makes the ADC count dependent only on the relative resistances in the divider, and eliminates any dependency on the accuracy of the ADC’s voltage reference.  Since the value of the fixed resistor remains important a 10k 0.1% tolerance part was used here. Even such tight tolerance resistors still only cost pence, so the cost advantage of the thermistor is not lost.  The divider is powered from a GPIO to eliminate current sinking through it while the sensor is asleep.

The second part of the problem helps drive thermistor selection, because choosing a part with reliable manufacturer-supplied Steinhart-Hart coefficients eliminates the need for calibration.  A Vishay NTCS0603E3103FMT was chosen and a spreadsheet devised which calculates the thermistor resistance (Rt) and the ratio Rt/R25 value for every 16 ADC counts across the full 10-bit range.  Maximum, nominal and minimum values are calculated in each case, based on quoted component tolerances.  For each row the maximum, nominal and minimum temperature is then calculated using Steinhart-Hart with the coefficients provided by the manufacturer.  Alternative thermistors can be evaluated by entering the R25 value and Steinhart-Hart coefficients on the “Graphs” sheet.

The predicted temperature spread due to component tolerance is plotted on the “Graphs” sheet and can be seen below for the Vishay thermistor and a 0.1% 10k reference.  At room temperature an error of +/- 0.3°C is predicted, which is well within the desired range.

To enable the microcontroller to measure temperature directly, the spreadsheet was used to derive a 64-slot lookup table mapping ADC values directly to nominal temperature.  Linear interpolation is used at runtime to calculate intermediate values, but all remaining maths, including the resistance calculation, is mopped up in the lookup table .  When generating the table the output values can be pre-scaled according to the requirements of the application.  Here, a 16-bit fixed-point representation with 8 fractional bits was used, but it would be equally straightforward to calculate the table for direct output of 100ths of °C, or any other scale factor.  The following code fragment demonstrates the resulting steps required to convert an ADC value to temperature on the microcontroller (lookup table truncated for clarity):

/* Lookup table for thermistor ADC values / 16 (64 points for full scale).
 * The result is °C with 8 fractional bits. Values include the
 * resistance calculation for a divider with a 10 k reference, and are
 * calculated using the full Steinhart-Hart formula with constants
 * given on the thermistor datasheet.
static int16_t thermistor_table[] = {
  32767, /* saturate */
  32767, /* saturate */
  32767, /* saturate */


#define STEP 16

/*! Convert thermistor ADC value to temperature by interpolating
 * the above lookup table */
static int16_t adc_to_temp(uint16_t val)
  uint16_t idx = val / STEP; /* FIXME: Limits */
  uint16_t offset = val - idx * STEP;
  int16_t y0 = thermistor_table[idx];
  int16_t y1 = thermistor_table[idx + 1];
  return y0 + (y1 - y0) * (int16_t)offset / STEP;

All of the above is of course purely theoretical, so a sensor board was modified to place the thermistor directly adjacent to the TMP112, and an additional TMP102 sensor was added as shown in the photograph at the top of this article.  The firmware was altered to transmit temperature measurements from each of the three sensors at 10 second intervals, then these values were logged while the board was temperature cycled in the oven and the freezer.

The measured values can be seen in this second spreadsheet.  For each data point the mean temperature is calculated as well as the difference from mean for each sensor, which is used as a figure of merit.  The following graphs show the average temperature over the duration of the test, and the corresponding variation from the mean for each of the three sensors:

It can be seen that the offset from mean is fairly constant for a given sensor, with the total spread being under 1 degree at steady-state.  Interestingly the TMP112 was almost as far from the mean value as the thermistor, but still within its +/- 0.5°C specification.  The large swing seen during periods of high rate-of-change is thought to be due to the difference in response time between the thermistor and the diode sensors used in the TMP1x2s.  For the thermistor, the average difference from mean measured temperature is about 0.4°C; slightly worse than the predicted value.  This is not unexpected since the prediction takes into account only the spread of component values, and not errors in the Steinhart-Hart coefficients, details of which were not available.

The table below summarises the vital statistics for the sensors used in the experiment, with the DS18B20 included for reference. Pricing was obtained from Farnell UK on 28/4/13 and is ex-VAT.

Device Absolute Accuracy °C Vcc min /V Icc min /uA Price 1 off Price 100 off
DS18B20 +/- 0.5 3.0 0.75 £3.80 £2.27
TMP112 +/- 0.5 1.4 0.5 £2.76 £0.92
TMP102 +/- 2 (+/- 0.5 typ) 1.4 0.5 £1.68 £1.16
Vishay NTCS0603E3103FMT 1% on R25 N/A N/A £0.39 £0.35

The results indicate that, using the described lookup table method, a low-cost, uncalibrated thermistor can yield an absolute accuracy similar to that of the much more expensive digital sensors.  At the same time, there are no supply voltage restrictions beyond those of the microcontroller, and by using a GPIO to power the divider standby current consumption is limited to leakage and should be negligible.


3 thoughts on “Low Cost, High Accuracy Temperature Sensing with a Thermistor

  1. Pingback: Low Cost, High Accuracy Temperature Sensing with a Thermistor - Home Brew Forums

  2. Alex


    I’m planning something similar for my project.
    Except I’m using even cheaper thermistors and resistors (5% ones) and generating a custom LUT for each of them using curve fitting.

  3. Pingback: Better Thermistor Readings with an Arduino: Series Resistors & Aref | Arduino based underwater sensors

Leave a Reply

Your email address will not be published. Required fields are marked *