Interrupt based Temperature Reading and Display with ATmega32

We can use temperature sensor like LM34 or LM35 and connect it a microcontroller like ATmega32, get data from sensor and display on a LCD. We can use interrupt facility of the microcontroller to check whether this is any new temperature reading from the ADC module and update the displayed temperature on LCD. In the last blog post Reading and displaying temperature using ATmega32 we used polling method to check whether there is any new sensor value in the ADC module and display the new value onto the LCD. Here we are using interrupt method to do the same.

Here we provide only schematic and programming code, for actual implementation of the circuit see LM35 Temperature Sensor with ATmega32 and LCD.

Below is the schematic of how you can connect LM34 temperature sensor with ATmega32 microcontroller.

LM34 interfacing with ATmega32

 Programming

The code for the microcontroller is written in C and was checked with the help of Proteus software.  Mainly we have 5 files- main.c, adc.c, adc.h, lcd.c and lcd.h. The main.c contains the main execution routine while adc.c and lcd.c and their associated header files contains supporting codes for running the ADC module of the MCU and LCD respectively. All codes are below.

In main.c file, in main() function, we first initialize the ADC and LCD using the adcinit() and lcdinit() functions. These functions- adcinit() and lcdinit() resides in the adc.c and lcd.c files.

C program code for main.c is below. We have used 8MHz as clock frequency and is defined by F_CPU if not specified elsewhere. We have to remember to include the interrupt.h  header file to use the interrupt feature of the ADC module. Also we have included the stdlib.h header file in order to use the dtostrf() function which converts float number to character array which is needed for display on LCD. The dtostrf() requires 4 parameters, the floating point number which is celsius in this program, the number of character to be stored in character array which includes the decimal point(dot) which in this case is 7, the number of numbers after the decimal point(after dot) which in this program is 3, and the name of the character array which in this case is temp.

In the main program, we first initialize the LCD and ADC module using the lcdinit() and adcinit() functions. Then we enable the global interrupt feature using the sei() function. After that we just print/send Temperature: word to the LCD for display using the lcdgoto() and lcdstr() function. Then at last we start the ADC conversion using the ADSC bit in the ADCSRA register before entering the endless while(1) loop. 

Whenever there is new temperature value in the ADC (ADCH and ADCL) data registers, interrupt occurs and the ISR routine(ISR(ADC_vect)) is invoked. This happens because the ADIF bit in the ADCSRA register will be set to 1. Once interrupt is invoked, the codes inside the ISR() routine are executed. There the ADC value is read using the adcread() function and it is converted to floating point number as celsius. This floating point number is converted to and stored in temp[10] character array which is send to LCD for display.


#ifndef F_CPU
#define F_CPU 8000000UL
#endif

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include "lcd.h"
#include "adc.h"

char temp[10];
float celsius;
char unit[]=" deg.C";

ISR(ADC_vect){		
	celsius = (adcread(0)*4.88);		
	celsius = (celsius/10.00);		
	dtostrf(celsius, 7, 3, temp);		
	lcdgoto(1,2);		
	lcdstr(temp);		
	lcdstr(unit);	//start ADC conversion	
	ADCSRA |= (1<<ADSC);
}

int main(){    
	lcdinit();	
	adcinit();	
	sei();	    
	char mydata[] = {"Temperature:"};	
	lcdgoto(1,1);    
	lcdstr(mydata);		
	ADCSRA |= (1<<ADSC);   
	while (1);   
	return 0; 
} 

C program code for ADC(adc.c and adc.h) are below.

adc.c
The adc.c contains adcinit() function which initializes the the ADC module of the ATmega32 microcontroller. The ADC needs to be turned on with the ADEN bit in the ADCSRA register. Also since we are using the interrupt for ADC we need to enable the ADC interrupt using the ADIE bit, also in the ADCSRA register. Then the next thing is to set the prescalar. In this work, the ADC is initialized with 128 prescalar value which reduces the clock frequency for ADC from 8MHz to 8Mhz/128 using the ADPS2, ADPS1 and ADPS0 bits which are all set to 1 in the ADCSRA register. The next thing we have to do is to set which ADC channel we want to use. For initialization purpose we have set ADC channel 0 using the MUX3, MUX2, MUC1 and MUX0 bits in the ADMUX register which are all set to 0. In the same ADMUX register we have set ADLAR bit to 0 meaning we want the result of ADC conversion stored in ADCH and ADCL registers to be right adjusted.


#include "adc.h"

void adcinit(){
		// set REFS1 = 0 |REFS0 = 1 (Vref as AVCC pin) | ADLAR = 0(right adjusted) |  MUX4 to MUX0 is 0000 for ADC0	
		ADMUX = 0b01000000; 
		//enable ADC module, enable interrupt, set prescalar of 128 which gives CLK/128 		
		ADCSRA |= (1<<ADEN) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);	
		}
		
int adcread(char channel){	
	/* set input channel to read */	
	ADMUX = 0x40 | (channel & 0x07);   // 0100 0000 | (channel & 0000 0100)            	
	_delay_ms(1);                      // Wait a little bit    		
	return ADCW;   //Return ADC word                    
	}

adc.h

The adc.h file contains the prototype function declaration to be used within adc.c file.


#include <avr/io.h>
#include <util/delay.h>

void adcinit();
int adcread(char);

The C program code for LCD(lcd.c and lcd.h) are same as in the last post Reading and displaying temperature using ATmega32 so you can get those code from there.

Post a Comment

Previous Post Next Post