Arduino Nano v3 internal temperature sensor

Calibration data:

Download data & formulas in excel.
Atmega documentation says:
The voltage sensitivity is approximately 1 mV/°C and the accuracy of the temperature measurement is +/- 10°C.
Measured temperature is a sum of ambient temperature and chip’s TDP. In fact it rises up for few minutes after the chip is powered and may change in base of load.

// Read Atmega328P internal temperature sensor //
long read_temp()
  // Read temperature sensor against 1.1V reference
  ADMUX = _BV(REFS1) | _BV(REFS0) | _BV(MUX3);
  // Start AD conversion
  // Detect end-of-conversion
  while (bit_is_set(ADCSRA,ADSC));
  // return raw data
  return ADCL | (ADCH << 8);

// Convert raw temperature data to °C
double conv_temp(long raw_temp)
  // f(x) = (raw - offset) / coeff
  return((raw_temp - 324.31) / 1.22);

void setup()
void loop()
  Serial.println(conv_temp(read_temp()), 1);

Atmega 328P – Datasheet

It is a curious fact that putting chips in the freezer, after a few minutes when the temperature drops below zero, the chip stops working.

This entry was posted in Arduino, C++, Electronics. Bookmark the permalink.

8 Responses to Arduino Nano v3 internal temperature sensor

  1. su-n says:

    It is a very wonderful experiment.
    How was the temperature measured?

  2. Sis says:

    Hey I am using this micro. i saw that i could use the internal temp sensor to save space in our board. I don’t really understand how to read the conversion…meaning the number we get. I looked at your excel sheet but how do you compare the numbers to the C degrees?…i did use your same formula which is the same supplied in the datasheet.

    So at the moment what my micro does is to take a force sensor readoing from pin 28 an ADC reading and I send it through BT to my PC. I want to read the temp to send that through BT also. So far I can send both. I see it on my screen. Problem is that when the pressure is too high the readings from the temp will not show and sort of skip over it then go to the force readings. Hope that makes sense.

    Hope to hear from you soon.

  3. iwi says:

    Hi Lopez! I do not understand your question. That kind of pressure you have?
    Please note that this is very approximate temperature sensor!
    This sensor was made to detect the cpu overtemperature!
    Would make sense to use a more accurate sensor like LM35 or DS18

  4. iwi says:

    Hi su-n. It’s very simple!
    Because the sensor is linear, we use a linear equation to estimate temperature.


    x = raw temperature
    y = temperature in °C
    m = temperature coefficient
    b = temperature offset

  5. Patrick says:

    My values are about the same as yours.
    They differ a lot from the datasheet. So I think they changed something, and didn’t update the datasheet.

    Thanks !
    I wandered what I did wrong. Now I know that the sensor is not according the values in the datasheet.

  6. iwi says:

    Thank You Too.
    Or the manufacturer wanted to get wide on the specifications because the temperature depends on the load of the MCU. The factors such as the working frequency and the amount of current, vary the temperature of the MCU. The measuring the environment temperature with internal sensor under different loads produces a considerable measurement error. It is practically almost unusable for measuring the ambient temperature. At most it can detect overheating or excessive cooling.
    Did you try the freezer?

  7. Patrick says:

    No, I didn’t try the freezer (and I have lack of time to try it right now)

    Your values were accurate for me.
    But I did change the formula. I changed it for integer values:

    int nTemperature, rawADC; // 16-bits integers
    // temperature = (rawADC – 324.31) / 1.22
    // temperature = (rawADC – (rawADC / 5) + (rawADC / 50.83 )) – 265.827
    nTemperature = rawADC – (rawADC / 5) + (rawADC / 51) – 266;

  8. Ad Francois says:

    I was also confronted that the code won’t work below zero ‘C.
    To solve this, I am reading the ADCL register and use this value instead of the ADCW.
    You should change the offset and the formula. The offset I used is now 89.
    When I ignored to read the ADCH, it didn’t work either, so I left this in.

    double GetTemp(void)
    long int wADC;
    double t;

    // The internal temperature has to be used
    // with the internal reference of 1.1V.
    // Channel 8 can not be selected with
    // the analogRead function yet.

    // Set the internal reference and mux.
    ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
    ADCSRA |= _BV(ADEN); // enable the ADC

    delay(20); // wait for voltages to become stable.

    ADCSRA |= _BV(ADSC); // Start the ADC

    // Detect end-of-conversion
    while (bit_is_set(ADCSRA,ADSC));
    t0 = ADCL;
    t1 = ADCH; //apparently you need to read ADCH too to get results in t0
    // Reading register “ADCW” takes care of how to read ADCL and ADCH.
    // The offset of 324.31 could be wrong. It is just an indication.
    // t = (ADCW – tempOffset ) / 1.22; this didn’t work below zero! Now reading ADCL only with the following formula. The tempoffset in my case is 89.
    t = (t0 – tempOffset) * 0.82;

    // The returned temperature is in degrees Celcius.
    return (t);

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.