Lightweight AVR temperature sensor interface

I have made a class “ChipTemp“ for reading out the temperature sensor inside the ATmega328. This class is inspired on the library “InternalTemp” from SpikedCola and marcello.romani. The class ChipTemp is kept as small and simple as possible. It requires only between 166 and 204 bytes program memory. See here for an article:

Both the offset and the gain can be calibrated and set in decimals

Test software
Connect an ATmega328 Arduino board and run ChipTempTest.pde to print the internal temperature in degrees Celsius, Fahrenheit, deci-Celsius and deci-Fahrenheit to the screen.

#include "ChipTemp.h"
#include <WProgram.h>

ChipTemp::ChipTemp()
{ 
}

inline void ChipTemp::initialize() 
{ ADMUX = 0xC8; // select reference, select temp sensor
  delay(10); // wait for the analog reference to stabilize
  readAdc(); // discard first sample (never hurts to be safe)  
}

inline int ChipTemp::readAdc()
{ ADCSRA |= _BV(ADSC); // start the conversion  
  while (bit_is_set(ADCSRA, ADSC)); // ADSC is cleared when the conversion finishes    
  return (ADCL | (ADCH << 8)); // combine bytes 
}

int ChipTemp::deciCelsius() 
{ long averageTemp=0; 
  initialize(); // must be done everytime
  for (int i=0; i<samples; i++) averageTemp += readAdc();
  averageTemp -= offsetFactor;
  return averageTemp / divideFactor; // return deci degree Celsius
}

int ChipTemp::celsius() 
{ return deciCelsius()/10;
}

int ChipTemp::deciFahrenheit() 
{ return (9 * deciCelsius()+1600) / 5;
}

int ChipTemp::fahrenheit() 
{ return (9 * deciCelsius()+1600) / 50; // do not use deciFahrenheit()/10;
}

ChipTemp.cpp

#include "ChipTemp.h"
#include <WProgram.h>

ChipTemp::ChipTemp()
{ 
}

inline void ChipTemp::initialize() 
{ ADMUX = 0xC8; // select reference, select temp sensor
  delay(10); // wait for the analog reference to stabilize
  readAdc(); // discard first sample (never hurts to be safe)  
}

inline int ChipTemp::readAdc()
{ ADCSRA |= _BV(ADSC); // start the conversion  
  while (bit_is_set(ADCSRA, ADSC)); // ADSC is cleared when the conversion finishes    
  return (ADCL | (ADCH << 8)); // combine bytes 
}

int ChipTemp::deciCelsius() 
{ long averageTemp=0; 
  initialize(); // must be done everytime
  for (int i=0; i<samples; i++) averageTemp += readAdc();
  averageTemp -= offsetFactor;
  return averageTemp / divideFactor; // return deci degree Celsius
}

int ChipTemp::celsius() 
{ return deciCelsius()/10;
}

int ChipTemp::deciFahrenheit() 
{ return (9 * deciCelsius()+1600) / 5;
}

int ChipTemp::fahrenheit() 
{ return (9 * deciCelsius()+1600) / 50; // do not use deciFahrenheit()/10;
}

ChipTemp.h

#ifndef ChipTemp_H
#define ChipTemp_H

// ATmega328 temperature sensor interface 
// Rev 1.0 Albert van Dalen www.avdweb.nl
// Based on "InternalTemp"
// Requires 166 ... 204 bytes program memory
// Resolution 0.1 degree

// Calibration values, set in decimals
static const float offset = 335.2; // change this!
static const float gain = 1.06154;

static const int samples = 1000; // must be >= 1000, else the gain setting has no effect

// Compile time calculations
static const long offsetFactor = offset * samples;
static const int divideFactor = gain * samples/10; // deci = 1/10

class ChipTemp 
{
public:
  ChipTemp();
  int deciCelsius(); 
  int celsius(); 
  int deciFahrenheit();
  int fahrenheit(); 
  
private:   
  inline void initialize(); 
  inline int readAdc();
};

#endif

The rest can be read on the article about it on my website: