Learn about thermistors and how to program an Arduino to measure its data.
Have you ever wondered how some devices like thermostats, 3D printer heat beds, car engines, or ovens measure temperature? With this project, you can find out!
Knowing the temperature in a project can a very useful piece of data to have handy. Knowledge of temperature can help regulate room temperature for a comfortable environment, ensure that a 3D printer bed is hot enough for materials like ABS to stick to its surface, prevent engine overheating, and keep food from being burnt.
For this article, we are only concerned with one type of sensor that can measure temperature. This sensor is called a thermistor.
A thermistor exhibits resistance that is far more sensitive to temperature than that of other types of resistors.
We will use an Arduino to measure and process the reading from a thermistor and then convert this into a human-friendly format of common temperature units.
MEGA or Uno or your favorite flavor of Arduino
Some jumper wires
Solder and soldering iron (maybe in case your thermistor does not fit well into the Arduino headers)
In a typical application of a resistor, you do not want the resistance to change with temperature. This is not really possible in real life but it's possible to ensure only a small change in resistance with a large change of temperature. If this were not the case, resistors would make weird things happen in circuits, such as an LED that gets much brighter and dimmer as the ambient temperature changes.
But, what if you really did want that LED’s brightness to be a function of temperature? This is where the thermistor comes in. As you might have guessed, a thermistor has a large change in resistance with a small change of temperature.
The units are shown but not the actual values as a thermistor can tailor to different ranges depending on which you buy. As you can see, the temperature gets hotter, the resistance is lower. This is a property of a Negative Temperature Coefficient resistor (NTC for short).
There are also thermistors that have Positive Temperature Coefficient (PTC for short) which means as the temperature increases, the resistance increases. However, PTC thermistors have a sort of tipping point and greatly change the resistance at some temperature. This makes the PTC thermistor a little harder to interface with. For this reason, for most low-cost temperature measurement, NTC thermistors are preferred.
For the remainder of the article, you can assume we'll be referring to NTC type thermistors.
Four Approaches to Finding a Curve Fitting Formula
Now that we better understand the general behavior of thermistors, you may start to wonder how we could possibly use an Arduino to measure temperature. The curve in the graph above is non-linear and, therefore, a simple linear equation does not seem possible. (In reality, we can work out an equation, but more on this later.)
So what to do?
Before reading on, think about how you would do this in the Arduino or even a circuit without a microprocessor component.
There are a few ways you can approach this problem, listed below. This is by no means a list of every technique out there, but it will show you some popular approaches.
Some manufacturers are nice enough to give you an entire chart mapping a certain integer range of temperature and resistance (typical values). One such thermistor can be found on this datasheet, by the company Vishay.
But then you think how you would do this in the Arduino. You would need to hard code all of these values into the code in a huge lookup table or a very long "switch…case" or "if…then" control structures.
And if the manufacturer is not nice enough to give a lookup table, you need to measure each point yourself to generate the data. That's a pretty bad day to be a programmer for sure. But this method is not all bad and has its place. If the project at hand only checks a few points or even a small range, this may be the preferred way to go. For example, one such situation is if you only want to measure if values fall within select temperature ranges and set up an LED to light up to indicate this situation.
But for our project, we want to measure a near-continuous range and send it to the serial monitor, so this method will not be used.
You could try to “linearize” the response from the thermistor by adding external circuitry to it.
A popular way of doing this is to connect a resistor in parallel with the thermistor. Some ICs offer to do this for you.
Determining how to pick and linearize a region along with choosing the correct value is an article all by itself. This approach is great if the microprocessor does not have floating point precision (like the PICAXE) since it simplifies a range of temperature to a linear response. It also makes designing a circuit without a microprocessor easier.
But we have a microprocessor in this article and want make use of the entire range.
You could take the table data from the datasheet or (if you enjoy punishing yourself) generate your own data that you made with independent measurements and recreate the plot in something like Excel. Then, you can use the curve fitting feature to create a formula for the curve. This is not a bad idea and all of the work performed will give a nice formula in your program—but it does take some time and preprocessing of data.
Although this is a legitimate approach, we do not want to be stuck analyzing all of this data. Plus, every thermistor is slightly different (but, of course, this is not really an issue if the tolerance is pretty low).
Turns out there is a general curve fitting formula meant for devices like thermistors. It is called the Steinhart-Hart equation. A version of it is shown below (other versions use the squared term as well as the cubed term):
where R is the resistance of the thermistor at temperature T (in kelvins).
This is a general curve fitting equation to accommodate all NTC type resistors. The approximation of the relationship of temperature and resistance is “good enough” for most applications.
Note that the equation needs the constants A, B, and C. These are different for each thermistor and need to be either given or calculated. Since there are three unknowns, you need three measurements of resistance at a certain temperature which then can be used to create three equations to solve for these constants.
Even for those of us that are algebraic wizards, this is still too much work.
Instead, there is a simpler equation that is less accurate but has only one constant. The constant is denoted by β, and thus the equation is referred to as the β equation.
where Ro is the resistance at reference temperature To (e.g., the resistance at room temperature). β is usually given in the datasheet—and if not, you only need one measurement (one equation) to calculate for it. This is the equation that I will be using for our thermistor interface as it is pretty straightforward to code and is the simplest one I have encountered without needing to linearize the thermistor’s response.
Measuring Resistance with the Arduino
Now that we've got our approach out of the way, we need to figure out how to actually measure the resistance with the Arduino before we can feed this info into the β equation.
This will be our interface circuit to our thermistor. When the thermistor senses a change in temperature, this will be reflected in the output voltage.
Now, usually, we use a voltage divider with the equation below:
But we do not want Vout as the answer—we want Rthermistor. So let us solve for that using algebra magic:
This is almost perfect but we need to measure our voltage output now as well as the supply voltage. This is where we make some good use of the Arduino’s built-in ADC. (If you're not familiar with the concept, please refer to AAC's textbook entry on ADCs for some background information.)
We can represent the voltage as a digital number within a certain scale. So really, our equation finally winds up like below:
This works out mathematically because no matter how we represent the voltage (in volts or in digital units), these units cancel out top and bottom in the fraction, leaving a dimensionless number. Then, multiply by a resistance to yield an answer in ohms.
Dmax for us will be 1023 since this is the highest number generated by our 10 bit ADC. Dmeasured will be the measured ADC value, which could be as low as zero and as high as 1023.
Phew! Onward to building it!
Wiring It Up
I used a TH10K thermistor.
I also used a 10k ohm resistor for Rbalance in our voltage divider. There was no β given so I needed to calculate that, myself.
The code here has been laid out with much thought and has a copious amount of comments to help you get through the logic.
Basically, it measures the divider's voltage, calculates the temperature, and then shows this in the serial terminal.
For fun, there are also some "if…then" statements to show how you can act upon a range of temperatures and a single data point.
Possible Next Steps
Everything in this article shows a pretty simple way of measuring temperature with a cheap thermistor. There are a couple of ways you could improve on the setup:
Put a small capacitor in parallel with the output voltage. This would stabilize the voltage and might even eliminate the need to average many samples (as in the code)—or at least you could average fewer samples.
Use precision resistors (better than 1%) to have a more consistent and predictable measurement. If you need absolute critical temperature measurement, keep in mind that self-heating of the thermistor can influence measurements; this project does not compensate for self-heating.
Of course, thermistors are just one sensor used for temperature measurements. Another popular choice is to use a temperature IC like this one (PDF). That way you never need to deal with linearization or complicated equations. Two other options are a thermocouple and an IR type sensor; the latter can measure temperature without physical contact, but they're not cheap.