Introduction: Hidden Arduino Thermometer
Did you know that many Arduinos and ATtiny chips have a built-in thermometer? The temperature is not calibrated, so you must take a couple of readings to characterize it. I found the original idea in the article - Secret Thermometer . I have added support for the Leonardo as well as several ATtinys, and provided a function for characterizing it.
Reading the Temperature Sensor
Here is the code for reading the raw data:
Massaging the Raw Data
Once you have the raw data, you can calibrate it by measuring two known temperatures and scaling as appropriate. Here is a simple little function to perform that normalization:
Calibrating
To get the four constants needed, simply run the sketch/program calling the
I have tested this code on the Leonardo, but it should also work on the Uno, and ATtinyx4 & ATtinyx5 series chips as well. If you like this trick, there is a companion instructable/article on measuring Vcc using the internal 1.1 volt reference that may be of interest as well.
Reading the Temperature Sensor
Here is the code for reading the raw data:
long readTemp() { // Read temperature sensor against 1.1V reference #if defined(__AVR_ATmega32U4__) ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); ADCSRB = _BV(MUX5); // the MUX5 bit is in the ADCSRB register #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(REFS1) | _BV(MUX5) | _BV(MUX1); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0); #else ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3); #endif delay(2); // Wait for ADMUX setting to settle ADCSRA |= _BV(ADSC); // Start conversion while (bit_is_set(ADCSRA,ADSC)); // measuring uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both long result = (high << 8) | low; // combine the two return result; }
Massaging the Raw Data
Once you have the raw data, you can calibrate it by measuring two known temperatures and scaling as appropriate. Here is a simple little function to perform that normalization:
float normalizeTemperature(long rawData) { // replace these constants with your 2 data points // these are sample values that will get you in the ballpark (in degrees C) float temp1 = 0; long data1 = 274; float temp2 = 25.0; long data2 = 304; // calculate the scale factor float scaleFactor = (temp2 - temp1) / (data2 - data1); // now calculate the temperature float temp = scaleFactor * (rawData - data1) + temp1; return temp; }
Calibrating
To get the four constants needed, simply run the sketch/program calling the
readTemp()
function at room temperature. Note the temperature and the raw data point. Enter these values for either set of data points. Next, either put your Arduino in the fridge or the oven (at a really low setting) and measure your second two data points. Replace the four constants with your data. It does not matter which order you list them. You can also enter your data in either Celsius or Fahrenheit. The linear calculation is independent of units as long as you are consistent in which system you use.I have tested this code on the Leonardo, but it should also work on the Uno, and ATtinyx4 & ATtinyx5 series chips as well. If you like this trick, there is a companion instructable/article on measuring Vcc using the internal 1.1 volt reference that may be of interest as well.

Participated in the
Electronics Tips and Tricks
4 Comments
10 years ago on Introduction
All by itself, the above temperature reading works fine on my ATmega328 chip and I get values in the 365range for ~ 70 degrees F. I'm also able to get very good analog *voltage* readings by using the "Secret Voltmeter" instructable listed above. However, when I combine the two, the "raw" temperature reading is greatly lowered - from about 365-> 160.
I can see that after the readVcc subroutine is called, the raw reading is different, so I'm assuming that something is set in the chip by the readVcc routine which affects the readTemp routine, but unfortunately I'm no where near smart enough to figure that out. I'm able to re-calibrate using this new scale, so this isn't exactly a show-stopper, but it would be nice if I didn't have to recalibrate the temperature readings when using the readVcc function.
Is there any way that either of the two routines could be adjusted so that they always produced consistent results, regardless of which got called first?
Thanks!
Dave O
Reply 10 years ago on Introduction
Well, I might not be smart enough to figure it out, but I'm definitely stubborn enough to beat it into submission! :-)
Through some trial and error, I discovered that adjusting the line:
delay(2); // Wait for ADMUX setting to settle
to use a delay value of 5 resolved the issue. My theory is that the multiple calls to readTemp and readVcc were unsettling the ADMUX reading. Adding in the extra few milliseconds resolved the issue. I just kept pushing the delay up until I got consistent readings.
Dave O
10 years ago on Introduction
the question is...is it possible to add/change something to this code to show on a display that temperature sended to the serial monitor? thanks
11 years ago on Introduction
Hi,
Great example. Any limitations if I re-use the code my projects ?
Regards,
Brendan