I know, this subject can be found all over the web, but the calculations sometimes are presented a bit cryptic as if the author wanted to put as many nested calculations on one line, so I just wanted to write something that explains it step by step, especially where the actual calculations are concerned. Lady Ada does a good job explaining the use of the thermistor, but I added some more explicit calculations.
The Arduino has several ADC ports that we can use to read
a voltage, or rather an ‘ADC value’. If the Analog port is connected to Vcc, the max value one reads is 1023 and of course when connected to ground it is 0.
If the temperature goes down, the value of the resistor increases and so will the reading on the analog port.
Suppose we have a 10k Seriesresistor and an NTC that for now we call ‘R’.
Then the voltage that can
be measured in the middle is
Vo=R/(R+10K) * Vcc
The analogPort readings however don’t give a voltage but an ADC value that can easily be calculated
ADC value= Vo*1023/Vcc // if for instance the Vo=4Volt the ADC = 818
or
ADC value= 1023 *(Vo/Vcc)
If we now combining the two formulas or as it is called ‘substitute’ Vo in the formula for ADC we get the following:
ADC value= (R/(R+10K))*Vcc*1023/Vcc
As we multiply by Vcc but also divide by Vcc we can take that
out of the equation and end up with
ADC value= (R/(R+10k))*1023
ADC value= 1023*R/(10+R)
if we want to get the value of R out of that equation, that becomes
R=10k/(1023/ADC-1)
If that goes a bit too fast, here is the equation worked out. I prefer pictures over the ‘in line’ formulas as some people have problems understanding the PEMDAS / BODMAS order of operation.
This becomes
subtraction of R
The ’10’ stood for ’10k’
and as we don’t always use a 10k we just make it more general:
Rntc = Rseries*(1023/ADC-1);// for pull down
Rntc = Rseries/(1023/ADC – 1)); // for pull-up configuration
So what would that look like in a program?
//Measure NTC valuebyte NTCPin = A0;const int SERIESRESISTOR = 10000;void setup(){ Serial.begin(9600);}void loop(){ float ADCvalue; float Resistance; ADCvalue = analogRead(NTCPin); Serial.print("Analoge "); Serial.print(ADCvalue); Serial.print(" = ");//convert value to resistance Resistance = (1023 / ADCvalue) - 1; Resistance = SERIESRESISTOR / Resistance; Serial.print(Resistance); Serial.println(" Ohm"); delay(1000);}//end programKnowing the resistance of the NTC is nice but it doesn’t tell us much about the temperature… or does it?
Well many NTC’s have a nominal value that is measured at 25 degrees Centigrade, so if you have a 10k NTC and you measure it
to be 10k, that means it is 25 degrees at that moment. That doesn’t help you much when the measurement is different.
You could keep a table in which every resistance value stands for a temperature. Those tables are very accurate but require a lot of work and memory space.
However, there is a formula, the Steinhart-Hart equation, that does a good approximation of converting resistance values of an NTC to temperature. Its not as exact as the thermistor table ( after all it is an approximation) but its fairly accurate.
The Steinhart-Hart equation looks like this:
but fortunately there is a
simplification of this formula, called the B-parameter Equation. That one looks as follows:
The program looks as follows:
//---------------byte NTCPin = A0;#define SERIESRESISTOR 10000#define NOMINAL_RESISTANCE 10000#define NOMINAL_TEMPERATURE 25#define BCOEFFICIENT 3950void setup(){Serial.begin(9600);}void loop(){float ADCvalue;float Resistance;ADCvalue = analogRead(NTCPin);Serial.print("Analoge ");Serial.print(ADCvalue);Serial.print(" = ");//convert value to resistanceResistance = (1023 / ADCvalue) - 1;Resistance = SERIESRESISTOR / Resistance;Serial.print(Resistance);Serial.println(" Ohm");float steinhart;steinhart = Resistance / NOMINAL_RESISTANCE; // (R/Ro)steinhart = log(steinhart); // ln(R/Ro)steinhart /= BCOEFFICIENT; // 1/B * ln(R/Ro)steinhart += 1.0 / (NOMINAL_TEMPERATURE + 273.15); // + (1/To)steinhart = 1.0 / steinhart; // Invertsteinhart -= 273.15; // convert to CSerial.print("TemperatureSerial.print(steinhart);Serial.println(" oC");delay(1000);}//-------------This ofcourse is not an ideal program. It is always good to take a few samples and to average them.
The
following function can do that for you:
Feedint the series resistor and NTC from the 5 Volt supply from the Arduino is possible. The Arduino power line does have glitches though. For accurate measurements it is better to use the 3.3Volt line as analog reference and feed the resistor from there.
for that add the following code in the setup
// connect AREF to 3.3V and use that as VCC for the resistor and NTC!
analogReference(EXTERNAL);