Saturday, 3 May 2014

Billysugger Simples: How to measure temperature with a Thermistor

Introduction

Often we have a requirement to measure the temperature of the board, the environment or some process.  Here’s a quick and easy guide to simple temperature measurement using a simple, cheap thermistor.

There are numerous silicon devices on the market which seem to simplify temperature measurement, but it’s difficult to beat a good quality NTC thermistor.  I’ve used them to measure the temperature of things as diverse as engine manifolds to LEDs, and in medical applications have measured patient internal temperatures to accuracies far better than 0.1°C.

Selecting the Thermistor

There are two types of thermistor, defined by whether their resistance increases or decreases as temperature rises.  Temperature is best measured using NTC (negative temperature coefficient) thermistors, whose resistance decreases as temperature rises.

There are two parameters of importance in defining the characteristic: A reference resistance and the Beta value.  The reference resistance is usually specified as the resistance at a temperature of 25°C.  The most common types have a 10k resistance at 25°C.  The Beta value specifies how the resistance varies as temperature deviates from the reference temperature.  The most common types have values in the region of 4000 and have units of Kelvin.

For this example, we will use a Vishay NTCLE100E3103JB0, (Farnell/Newark part 1187031, Digikey part BC2301-ND).  This is a cheap and simple leaded part with a 2.54mm (0.1”) lead spacing, has a 10k resistance at 25°C and a Beta value B=3977K.



There are many, many types of NTC thermistor, some with different case styles including surface mount parts, different reference resistances for nominal temperature ranges other than room temperature, and different tolerances for accuracy.  This one is good for general purpose air temperature measurement.

The Measurement Circuit

The thermistor is connected to the ADC 0V and in series with a reference resistor, forming a potential divider from the ADC reference.  A filter capacitor across the thermistor will reduce any thermal noise, or other pickup.



Now, we can easily calculate the ADC value at 25°C.  And we’ll see that as the temperature increases, the thermistor resistance decreases and the voltage measured at the ADC falls.

Calculating Temperature

We could approximate the thermistor response as a linear function, but beyond a very small range around 25°C, the errors would quickly become unacceptable.  A better approximation is made by using the Beta-curve function:

R = exp[(Beta/Tk) + LN(A)]

Where Tk is the thermistor temperature in Kelvin, not degrees centigrade, and LN(A) is a constant value for the thermistor. (Kelvin is an absolute temperature scale, where Tk = Tc + 273.15).

Solving the above equation for temperature gives

Tk = Beta/(LN(R)-LN(A))

Or

Tc = Beta/(LN(R)-LN(A)) – 273.15

Where

LN(A) = LN(R25)-(Beta/298.15)

But now we need to know the thermistor resistance R.  The ADC value depends of the resistance R as follows:

ADC = ADC_TOP * R / (R + Rref)

Where ADC_TOP is the highest value given by the ADC, (e.g. 4095 for a 12-bit ADC), and Rref is the reference resistor value.

Solving for R gives

R = Rref * ADC / ((ADC_ TOP * Kadc) – ADC)

Implementing in C-code

The following is representative of code which calculates temperature measured using the above method.  The detailed code will need to be adapted depending on your processor, your board and your thermistor.
// Include math library for calculations
#include <math.h> 

// Define ADC parameters
#define ADC_TOP 1023 

// Define thermistor parameters
#define R_NTC 10000
#define BETA 3977
#define LNA (-4.12858298874828)

// Define Reference Resistor
#define R_REF 15000 

float read_temperature(void)
{
  float x = 0; 

  // Calculate thermistor resistance from ADC
  x = (R_REF * adc[0]) / (ADC_TOP – adc[0]; 

  // Calculate Kelvin temperature from resistance
  x = BETA / (log(x) - LNA); 

  // Convert temperature to Celsius
  x = x – 273.15; 

  // Return result
  return(x);
}
 And if you want to play around with different thermistor parameters, I’ve prepared an Excel file with all the calculations included.

4 comments:

  1. Have you had any issues with low temperatures? I also had issues with your formula for calculating the T.

    According to the data sheet the formula should be:

    (A+B*log(R/R_REF)+C*log(R/R_REF)^2+D*log(R/R_REF)^3))^(-1)

    This gives good results for temperatures around the ref temp but when I attempt to use it in my freezer (~-8F) it displays temperatures around 29F.

    Im not sure what is going on. might be an issue with my selected resistor?

    ReplyDelete
  2. Hi Tyler, Thanks for the comment. The international standard for temperature measurement, and the one used to characterise these thermistors, is the Kelvin scale. This has the same slope as the Celsius scale, just with an offset of -273.15. This method, and indeed the data sheet values usually given, are completely unsuitable for Fahrenheit. If you want a Fahrenheit result, for quaint colloquial American usage (smile), then you first need to calculate the Celsius temperature using the above, then convert to Fahrenheit using Tf = (Tc * 9/5) + 32. Good luck!

    ReplyDelete
  3. If you want better approximations, over a wider range, then the Steinhart-Hart method is better, and may be what your formula is based on. Be sure to use the natural log, (ln) not the decimal log (log) function. I'll think about posting on using that method, which I've used in precision medical applications, but for now, you may find what you need by Googling Steinhart-Hart.

    ReplyDelete
  4. "We could approximate the thermistor response as a linear function, but beyond a very small range around 25°C, the errors would quickly become unacceptable."

    True, but a very useful, cheap (as in CPU resource / code size)and as accurate as required implementation, is to calculate the temperature for a few (how many depends on how accurate you need it to be) evenly spaced ADC values and interpolate between them.
    Look-up and interpolation can be very fast operations if implemented correctly. Minimal code and CPU usage.

    ReplyDelete