By interfacing different types of sensors with our MCU we can sense the environment
and take decisions, in this way we can create "smart" applications.
There are wide variety of sensors available. In this tutorial we will learn
about a popular sensor LM35 which is precision centigrade temperature sensor.
It can be used to measure temperature with accuracy of 0.5 degree centigrade.
We can interface it easily with AVR MCUs and can create thermometers, temperature
controller, fire alarms etc.

Things Required

 

S. No. Item Image
1

28 PIN AVR Dev Board

Contains the core AVR circuit including 5v regulator, reset, ISP.

AVR Development Board
2

Seven Segment Display Module

Four common anode displays multiplexed with driver transistors and current limiting resistors.

Seven Segment Board
3

Single Pin Female to Female Burg Wires

Used to interconnect the two boards. And the sensor.

 

Burg Wires
4

USB AVR Programmer

To upload the program to the development board.

USB AVR Programmer
5 LM35 Temperature Sensor
lm35 temp sensor

 

LM35

LM35 by National Semiconductor is a popular and low cost temperature sensor.
It is also easily available. You
can buy one from here online
. It has three pins as follows.

lm35 temperature sensor pin out

Fig – LM35 Pin Configuration

 

 

The Vcc can be from 4V to 20V as specified by the datasheet. To use the sensor
simply connect the Vcc to 5V ,GND to Ground and the Out to one of the ADC (analog
to digital converter channel). The output linearly varies with temperature.
The output is

10MilliVolts per degree centigrade.

So if the output is 310 mV then temperature is 31 degree C. To make this project
you should be familiar with the ADC of AVRs and also using seven segment displays.
Please refer to following articles.

The resolution of AVRs ADC is 10bit and for reference voltage we are using
5V so the resolution in terms of voltage is

5/1024 = 5mV approximatly

So if ADC’s result corresponds to 5mV i.e. if ADC reading is 10 it means

10 x 5mV = 50mV

You can get read the value of any ADC channel using the function

ReadADC(ch);

Where ch is channel number (0-5) in case of ATmega8. If you have connected
the LM35′s out put to ADC channel 0 then call

adc_value = ReadADC(0)

this will store the current ADC reading in variable adc_value. The data type
of adc_value should be int as ADC value can range from 0-1023.

As we saw ADC results are in factor of 5mV and for 1 degree C the output of
LM35 is 10mV, So 2 units of ADC = 1 degree.

So to get the temperature we divide the adc_value by two

temperature = adc_value/2;

Finally you can display this value in either the 7 segment displays by using
the Print() function we developed in last tutorial or you can display it in
LCD Module. To know how to display integer in 7 segment displays and LCD Modules
see the articles.

In this tutorial I have used four 7 segment displays to show the temperature.

Program (AVR GCC)


/*

Description:   Program to demonstrate the use of LM35
            Temperature Sensor.
            
            The temperature is display on seven
            segment display.
________________________________________________________

Author:     Avinash Gupta
Date:    14 Dec. 2012
Updated: 
Web:     www.eXtremeElectronics.co.in

   
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>


#define SEVEN_SEGMENT_PORT PORTD
#define SEVEN_SEGMENT_DDR  DDRD

volatile uint8_t digits[3];

void SevenSegment(uint8_t n,uint8_t dp)
{
/*
This function writes a digits given by n to the display
the decimal point is displayed if dp=1

Note:

n must be less than 9
*/
   if(n<10)
   {
      switch (n)
      {
         case 0:
                          //.gfedcba
         SEVEN_SEGMENT_PORT=0b00111111;
         break;

         case 1:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b00000110;
         break;

         case 2:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b01011011;
         break;

         case 3:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b01001111;
         break;

         case 4:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b01100110;
         break;

         case 5:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b01101101;
         break;

         case 6:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b01111101;
         break;

         case 7:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b00000111;
         break;

         case 8:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b01111111;
         break;

         case 9:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b01101111;
         break;
      }
      if(dp)
      {
         //if decimal point should be displayed

         //make 7th bit high
         SEVEN_SEGMENT_PORT|=0b10000000;
      }
   }
   else
   {
      //This symbol on display tells that n was greater than 9
      //so display can't handle it

      SEVEN_SEGMENT_PORT=0b11111101;
   }
}

void Wait()
{
   uint8_t i;
   for(i=0;i<10;i++)
   {
      _delay_loop_2(0);
   }
}

void Print(uint16_t num)
{
   /* 

   
   This function breaks apart a given integer into separate digits
   and writes them to the display array i.e. digits[]
   
   */
   uint8_t i=0;
   uint8_t j;

   if(num>9999) return;


   while(num)
   {
      digits[i]=num%10;
      i++;

      num=num/10;
   }
   for(j=i;j<4;j++) digits[j]=0;
}


void InitADC()
{
   ADMUX=(1<<REFS0);// For Aref=AVcc;
   ADCSRA=(1<<ADEN)|(7<<ADPS0);
}

uint16_t ReadADC(uint8_t ch)
{
   //Select ADC Channel ch must be 0-7
   ch=ch&0b00000111;
   ADMUX|=ch;

   //Start Single conversion

   ADCSRA|=(1<<ADSC);

   //Wait for conversion to complete
   while(!(ADCSRA & (1<<ADIF)));

   //Clear ADIF by writing one to it
   ADCSRA|=(1<<ADIF);

   return(ADC);
}

void main()
{
   uint16_t adc_value;
   uint8_t t;

   // Prescaler = FCPU/1024
   TCCR0|=(1<<CS02);

   //Enable Overflow Interrupt Enable
   TIMSK|=(1<<TOIE0);

   //Initialize Counter

   TCNT0=0;

   //Port B[3,2,1,0] as out put
   DDRB|=0b00001111;

   PORTB=0b00000001;

   //Port D
   SEVEN_SEGMENT_DDR=0XFF;

   //Turn off all segments
   SEVEN_SEGMENT_PORT=0X00;

   //Enable Global Interrupts
   sei();

   //Enable ADC
   InitADC();

   //Infinite loop
   while(1)
   {
      //Read ADC

      adc_value=ReadADC(0);

      //Convert to degree Centrigrade
      t=adc_value/2;

      //Print to display
      Print(t);

      //Wait some time
      Wait();

   }
}

ISR(TIMER0_OVF_vect)
{
   /*

   This interrupt service routine (ISR)
   Updates the displays

   */
   static uint8_t i=0;

   if(i==3)
   {
      //If on last display then come
      //back to first.
      i=0;
   }
   else
   {
      //Goto Next display
      i++;
   }

   //Activate a display according to i
   PORTB&=(0b11110000);
   PORTB|=(1<<i);

   //Write the digit[i] in the ith display.
   SevenSegment(digits[i],0);
}

Hardware

The hardware of the project is simple you first make the last project (Multiplexed
Seven Segment Displays)
and then add the LM35 as stated above. Connect output pin of LM35 to ADC0 (PIN 23) of ATmega8.

seven segment board and 28pin avr dev board

Fig. LM35 Temperature Sensor Demo

 

Downloads