Interfacing Temperature Sensor – LM35
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.
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.
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 Gnd 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.
- Using the ADC of AVRs
- Using Seven Segment Displays.
- Using Seven Segment Displays in Multiplexed Mode.
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 approx
So if ADCs 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 to
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 three 7 segment displays to show the temperature. I have used the xBoard MINI - ATmega8 board to make the project. The complete program is given below.
Program (AVR GCC)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>
#define SEVEN_SEGMENT_PORT PORTD
#define SEVEN_SEGMENT_DDR DDRD
uint8_t digits[3]; //Holds the digits for 3 displays
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:
SEVEN_SEGMENT_PORT=0b00000011;
break;
case 1:
SEVEN_SEGMENT_PORT=0b10011111;
break;
case 2:
SEVEN_SEGMENT_PORT=0b00100101;
break;
case 3:
SEVEN_SEGMENT_PORT=0b00001101;
break;
case 4:
SEVEN_SEGMENT_PORT=0b10011001;
break;
case 5:
SEVEN_SEGMENT_PORT=0b01001001;
break;
case 6:
SEVEN_SEGMENT_PORT=0b01000001;
break;
case 7:
SEVEN_SEGMENT_PORT=0b00011111;
break;
case 8:
SEVEN_SEGMENT_PORT=0b00000001;
break;
case 9:
SEVEN_SEGMENT_PORT=0b00001001;
break;
}
if(dp)
{
//if decimal point should be displayed
//make 0th bit Low
SEVEN_SEGMENT_PORT&=0b11111110;
}
}
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)
{
uint8_t i=0;
uint8_t j;
if(num>999) return;
while(num)
{
digits[i]=num%10;
i++;
num=num/10;
}
for(j=i;j<3;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 C[2,1,0] as out put
DDRB|=0b00000111;
PORTB=0b00000110;
//Port D
SEVEN_SEGMENT_DDR=0XFF;
//Turn off all segments
SEVEN_SEGMENT_PORT=0XFF;
//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)
{
static uint8_t i=0;
if(i==2)
{
i=0;
}
else
{
i++;
}
PORTB=~(1<<i);
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. You can use the Homemade AVR Devboard or the low cost and fully assembled and tested xBoard MINI. xBoard MINI can be a great tool to learn AVR MCUs at low cost, it can be used to quickly prototype AVR based projects. You can program the xBoard MINI with our USB AVR Programmer.
![]() |
Fig - Final Digital Thermometer. Temperature read out = 29 C |
|


Hello Gupta,
I’m a beginner with AVRs, so great thanks for the very useful series!
As I see the LM35 provides -1V to +6V representing the temperature. What is the best practice in this case to convert negative voltages with ADC? Here in Hungary now we have less than -15°C at night
)
Thanks in advance!
January 12th, 2009 at 2:06 amZsolt
@Zsolt
Hello.)
In response to your question i have posted a topic in forum, see it for answers.
http://forum.extremeelectronics.co.in/viewtopic.php?f=2&t=29
January 12th, 2009 at 9:22 amI have a question?
February 6th, 2009 at 6:00 pmMay I have PCB & diagram of this project.
cas I’m not sure about the circuit!!!!!
Hello Avinash
Do you have any tutorials to send AT commands via C program
March 10th, 2009 at 2:56 pmhi i m a student of third yr electonics i have recetly made a project using LM35.The name of project is temperature sensor i jst wanted to know what r the advantages of this project and application areas where i can use this project pratically
April 17th, 2009 at 7:47 pmHello Monika,
Are u talking abt the above project or u got it from some where else?
Your question seems to be too academic !
Well Digital Temperature sensors are used every where, from monitoring CPU temperature in PC to Space stations !!!
Also in modern refrigerators and Ovens.
April 18th, 2009 at 7:44 amHi avinash,
May 11th, 2009 at 10:50 ami tried the above code on my board by deccan robots.When the program is burned its showing b.b.b .I am not able to trace what the problem is.I am using atmega16 Mcu.I have connected lm35 to pin0 of portA,data lines of portD to seven segment display,and portC [2,1,0]to display control lines.Kindly tell what is the problem?Also can u explain what happens once the adc values are read?
I will explain what i have understood.Once print (t)is executed,it will go to that subroutine and check if no is less than 999 or not.If yes it will calculate digits[o]=(suppose)255%10=5 and num=25,now i will be incremented by 1.After this digits[j]=digits[0]=0. Now it will go to timer overflow rotine and and display the digit by using SevenSegment(digits[i],0);mean while next display is also detected.But i am not able to find out why u have used digits[j].Please explain me?
hiii avinash,
May 16th, 2009 at 12:36 pmin this ADC conversion u have sex REFERENCE voltage to AVcc i.e REFS0 as 1, and REFS1 as 0, and in the data sheet of ATMEGA8 i have found that, if the reference voltage is set like this, we need to use an oscillator should be connected externally to Aref terminal , is that required? if it is required plzzz tell me from which terminal to terminal v need to connect that oscillator…..thanx for posting all this stuff for us…..
@Teja
It is not OSCILLATOR but an INDUCTOR of 10uH
and YES it is necessary to put that for perfect,clean and noise free performance.
You can find one here
http://shop.extremeelectronics.co.in/product_info.php?cPath=24_31&products_id=55
May 16th, 2009 at 12:48 pmHi, Avinash can you just help in the CODE to make ADC conversion at slow speed so that the bits doesn’t fluctute while displaying the LM35 value on the seven segment display
May 30th, 2009 at 12:32 amHi Avinash
pls give mail me the whole circuit connection of the above project(interfacing LM35 and 3 digit LED display with ATMEGA)
November 13th, 2009 at 10:55 pmHi avinash
I’m a beginner with AVRs, so great thanks for the very useful series i tried this it works display the temperature but in rotating i want continuous (3 digits SAME time) Where can i to change in program pl help me
November 17th, 2009 at 4:50 pm@manikandan
This is because the CPU is running slow. Make it fast by attaching an external 16MHz crystal and write FUSE BYTE as high=C9 and low=FF
November 17th, 2009 at 5:03 pmHi Avinash,
November 18th, 2009 at 11:56 amThanks for ur kind help… i changed the oscillator as 16MHz and got a stable display with slit blinking… pls guide me where to change the FUSE BYTE.
hi Avinash,
November 27th, 2009 at 2:51 pmI’m a beginner with AVRs, so great thanks for the very useful series, pls help me how to stop the flickering of LED displays… i hav used 16MHZ externally and the digits are visible to eyes but have some flickering.
Quote
“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.”
can’t figure out ,how the declaration is made.
can anybody explain me the above declaration taken from the tutorial.
Regards,
January 26th, 2010 at 4:40 pm-Gaurav Parida
Hey, was just looking through your web site and decided to add the RSS feed, however it’s not working with my webbrowser (I am viewing it with Opera) any kinda way to get around this?
February 16th, 2010 at 4:17 pmhi Avinash,
March 26th, 2010 at 11:33 ami am doing the project using humidity sensor HTF3226 its o/p is in frequency so can u help me to display humidity on lcd
bt how to manage the flickering of the display?pls give details…….otherwise its ok,program is allright.
March 30th, 2010 at 12:12 am@Sayantan
March 30th, 2010 at 6:28 amTo reduce flickering set fuse bit as
Low = ff
High = c9
thnx for your ans,bt can you pls tell me how to set fuse bit low & high as ff & c9 respectively?
April 1st, 2010 at 1:49 pmok,now I have reduced the flickering by vanishing the bc557 transistor frm the circuit,and it looks fine without any flickering.But I know that it may be harmfull to mcu to connect
April 5th, 2010 at 5:58 pmthe display directly to the port,as it can make oveload.So I have to put the transistors again in the circuit.Now my question is what is the reason behind that flickering behaviour of transistors,is that for their internal delay or anything else?Still wating for any further assistance to reduce the flickering and get a perfect steady display.Thanx.
hello
April 5th, 2010 at 10:11 pmnice tutorial
am interfacing nte7052 7 segment display which has input current rating of 160 mA. where as the output current of 4511 is only 25mA.
Do I need amplification somewhere in the circuit?
Please provide the transistor number or ic number and the circuit
Hey,
I have a question. If I am using LM35 with ATMEGA8, do i need a voltage divider or something to amplify the voltage coming from the LM35 or can it detect the changes in temperature on its own?
Regards,
April 27th, 2010 at 7:45 pmMayank.
Hello Avinash and electronics enthusiasts,
I’m curious how to display temperature not in seven segment displays, but simply on Hyperterminal. Of course I understand that it’s necessary convert character to string, but I have no idea how to display digits… Should I use itoa() function?
Thanks for any comments
Regards,
May 1st, 2010 at 3:40 pmJon
@Jon
May 1st, 2010 at 3:59 pmYes you can use itoa() function. Or write a function to convert int to string.
Hi Avinash,
There’s a flaw. your code will work fine UNLESS one doesnt use more than 1 channel in a row.
uint16_t ReadADC(uint8_t ch)
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch; //>>> This is just wrong!!!
.
.
}
imagine you read channel 2 after ch 1, then with your code ch 1 to ADMUX would still be written there since you havent cleared it & you would be just ‘appending’ ch 2 to ADMUX, so you end up reading channel 3! (If one uses a loop to cycle thru channels, then ultimately he would always get value from channel 7)
This is enough to give a newbie headache worth of days if he decides to upgrade to >1 channels. I wonder no one has seen this yet.
Use this instead:
ADMUX=(ADMUX & 0xF0)|ch;
Similarly, I would suggest changing
void InitADC()
{
ADMUX=(1<<REFS0);// For Aref=AVcc;
ADCSRA=(1<<ADEN)|(7<<ADPS0);
}
to
void ADC_init(void)
{
ADMUX = (ADMUX & ~(1<<REFS1)) | (1<<REFS0); // For Aref = AVcc
ADCSRA |=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //slowest possible rate
}
which I think is the proper way.
May 13th, 2010 at 4:02 pm@Munish
I knew the bug in above code but due to laziness did not updated the code!
The correct code can be found in this article
May 14th, 2010 at 8:30 amhttp://extremeelectronics.co.in/robotics/obstacle-avoiding-robot-using-avr-atmega32-%e2%80%93-part-ii/
then atleast you should add a caveat that do not use this code for more than 1 channels! or better yet update the code itself. its just 1 line ! this can be just a matter of laziness to you or me but think about a newbie who would be totally clueless about it. if you decide to ‘guide’ newbies, you must assume minimum responsibilities like these. anyways i appriciate your efforts otherwise
May 14th, 2010 at 11:21 am[...] Interfacing Temperature Sensor LM35 [...]
July 21st, 2010 at 1:09 pm