Skip to main content

Making a simple temperature sensor

After a whole lot of posts written out of sheer frustration, here is something you can really do. In this post, I explain how to build a simple temperature sensor.

The temperature sensor is a LM35 chip. This is a easy to use 3 pin package. The pins are Vcc, Gnd and Vout. The output voltage (in millivolts) is the temperature in degrees centigrade * 10.

I am using an Atmel ATmega8 micro-controller. There really is no specific reason for choosing this micro-controller, except for easy availability (I had one) and previous experience.

The third and last major component is the LCD display for displaying the temperature.

Now for some quick calculations. My temperature shall not in general exceed 100C. A diode drops 0.6V when it is on. Putting two diodes in series, I get an almost constant voltage of 1.200V. I have a 10 bit ADC. Hence, the temperature in Celsius*10 is ADC*1200/1024, or (ADC*1200)>>10.

The final touch is a simple push-button for cycling through day average, day maximum and day minimum. However, a simple tact switch does not debounce the output, so it was my job to debounce the switch. The ATmega8, in the input mode with the pull up resistors gives around 10k pullup, so I simply added a 10uF capacitor at the INT0 pin. This gives a debouncing time of around 0.1s, good enough for our purpose.

Once these specs were complete, I sat to make the schematic. The completed schematic is shown below:

A PCB was made based on this schematic.

While programming the micro-controller, an important question was how to define a day. In the end, I decided to define a day as the previous 24 hours. Due to the limited number of pins on the ATmega8, I decided to ditch the crystal oscillator, after all, accuracy in timekeeping is hardly what the user wants. Instead, I used the internal 8MHz oscillator.

For the LCD interface, I used the libraries provided by Peter Fleury. To display the degree symbol correctly, I simply output the character 223. I shall not give any more information than this, because I don't really want to create a manual on a hardware kit that you can assemble. The fun really is in designing the thing yourself.

PCB made, micro-controller flashed, I set up this circuit for the first test run!

Here are some images of the temperature sensor in action:






The source code for the ATmega8 has been listed below. The LCD libraries are by Peter Fleury and can be found here.


#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include "lcd.h"

#define SetBit(x,b) (x)|=(b)
#define GetBit(x,b) ((x)&(b))
#define ToggleBit(x,b) (x)^=(b)
#define ResetBit(x,b) (x)&=~(b)
#define isLow(x,b) (!GetBit(x,b))
#define isHigh(x,b) GetBit(x,b)

#define DISPLAY_DAY_AVG 1
#define DISPLAY_DAY_MAX 2
#define DISPLAY_DAY_MIN 3

typedef struct
{
	uint16_t avg;
	uint16_t min;
	uint16_t max;
	uint8_t valid;
} hour_struct;

char buffer[10];

uint8_t display_wait = 0;
uint8_t current_display = 0;

uint16_t min_avg = 0;
uint8_t second_count = 0;
uint8_t min_count = 0;
uint8_t current_hour = 0;
uint16_t current_temp = 0;

uint16_t hour_avg;
uint16_t hour_max;
uint16_t hour_min;

hour_struct hours[23];

uint8_t is_first = 1;

uint16_t day_avg()
{
	uint8_t valid_hours = 1;
	uint32_t sum = hour_avg;
	for(uint8_t i=0; i<23; i++)
		if(hours[i].valid)
		{
			sum += hours[i].avg;
			valid_hours++;
		}
	return sum/valid_hours;
}

uint16_t day_min()
{
	uint16_t min = hour_min;
	for(uint8_t i=0; i<23; i++)
		if(hours[i].valid)
			if(hours[i].min < min)
				min = hours[i].min;
	return min;
}

uint16_t day_max()
{
	uint16_t max = hour_max;
	for(uint8_t i=0; i<23; i++)
		if(hours[i].valid)
			if(hours[i].max > max)
				max = hours[i].max;
	return max;
}

void temp_to_string(uint16_t temp, char* str_buffer)
{
	uint8_t strlen = 4;
	str_buffer[0] = 'C';
	str_buffer[1] = (char)(223);
	str_buffer[2] = (char)(temp%10)+'0';
	temp /= 10;
	str_buffer[3] = '.';
	while(temp)
	{
		str_buffer[strlen++] = (char)(temp%10)+'0';
		temp /= 10;
	}
	str_buffer[strlen] = '\0';
	uint8_t l = (strlen)/2-1;
	
	for(int i=0; i<=l; i++)
	{
		str_buffer[strlen-i-1] ^= str_buffer[i];
		str_buffer[i] ^= str_buffer[strlen-i-1];
		str_buffer[strlen-i-1] ^= str_buffer[i];
	}
}

ISR(TIMER1_COMPA_vect)
{
	current_temp = (uint32_t)(ADC)*1200/1024;
	uint16_t temp = min_avg*second_count;
	temp += current_temp;
	second_count++;
	min_avg = temp/second_count;
	SetBit(ADCSRA, _BV(ADSC));
	
	if(is_first)
	{
		is_first = 0;
		hour_min = hour_max = hour_avg = current_temp;
		SetBit(MCUCR, _BV(ISC01));
		SetBit(GICR, _BV(INT0));
	}
	
	if(second_count == 60)
	{
		second_count = 0;
		temp = hour_avg*min_count;
		temp += min_avg;
		min_count++;
		hour_avg = temp/min_count;	
		if(min_avg > hour_max)
			hour_max = min_avg;
		else if(min_avg < hour_min)
			hour_min = min_avg;
	
		if(min_count == 60)
		{
			min_count = 0;
			hours[current_hour].avg = hour_avg;
			hours[current_hour].min = hour_min;
			hours[current_hour].max = hour_max;
			hours[current_hour].valid = 1;
			current_hour++;
			if(current_hour == 23)
			{
				current_hour = 0;
			}
			hour_min = min_avg;
			hour_max = min_avg;
		}
	}
	if(display_wait)
		display_wait--;
	else
	{
		current_display = 0;
		lcd_clrscr();
		lcd_puts("Temperature\n");
		//itoa(current_temp, buffer, 10);
		temp_to_string(current_temp, buffer);
		lcd_puts(buffer);
	}
}

ISR(INT0_vect)
{
	display_wait = 5;
	current_display++;
	current_display &= 0x03;
	lcd_clrscr();
	if(current_display == DISPLAY_DAY_AVG)
	{
		lcd_puts("Day Average\n");
		temp_to_string(day_avg(), buffer);
		lcd_puts(buffer);
	}
	else if(current_display == DISPLAY_DAY_MAX)
	{
		lcd_puts("Day Maximum\n");
		temp_to_string(day_max(), buffer);
		lcd_puts(buffer);
	}
	else if(current_display == DISPLAY_DAY_MIN)
	{
		lcd_puts("Day Minimum\n");
		temp_to_string(day_min(), buffer);
		lcd_puts(buffer);
	}
	else
	{
		display_wait = 0;
		lcd_puts("Temperature\n");
		temp_to_string(current_temp, buffer);
		lcd_puts(buffer);
	}
}

int main(void)
{
	for(int i=0; i<23; i++)
		hours[i].valid = 0;
	
	DDRC = 0x00;                  //Set Port A as input(for ADC)
	PORTC = 0x00;                 //Disable internal pullups for Port A
	DDRD = 0x00;
	PORTD = 0xFF;
	ADCSRA = _BV(ADEN)|6;
	SetBit(ADCSRA, _BV(ADSC));
	while(isHigh(ADCSRA, _BV(ADSC)));
	SetBit(ADCSRA, _BV(ADSC));
	while(isHigh(ADCSRA, _BV(ADSC)));
	TCCR1B = _BV(WGM12)|_BV(CS12);
	OCR1A = 31250;
	TIMSK = _BV(OCIE1A);
	sei();
	lcd_init(LCD_DISP_ON);
	lcd_clrscr();
	lcd_puts("Temperature\nSensor");
	while(1);
	return 0;
}

Comments

Popular posts from this blog

On Harry Potter and why I dislike the series

There could not be a better time for this post. There could not have been a worse time for this post. Now that the penultimate movie of the series is out, and my facebook wall filled with people who loved the movie. But this is something I really wanted to say, and I shall say it anyway. Harry Potter is pathetic literature. Now, you must be wondering why I say that. There are many reasons. Firstly, the storyline itself is flawed. When a writer sits down to write anything, he/she must set up some essential rules about what is happening. These rules must remain constant irrespective of how many times he/she changes his/her mind. This is so that the readers are allowed to have some sensibility in what they are reading. In the fourth book, Rowling goes ahead and kills Cedric. Then, at the end of the book, the horseless carriages are there again. Nothing special. We all knew that they are horseless. But then comes the fifth book, and BAM, the horses are actually winged beasts that only thos...

On the Dvorak Simplified Keyboard

This is a post that I have been meaning to write from quite some time. Long hours spent typing code on my computer left my hands fatigued, and left me with a lot of pain in my wrists and fingers. That is when I decided to use the Dvorak. But I have got the same bad habit as Dr. Watson, to tell a story backwards. Of course, you must be wondering what the Dvorak is. The story of keyboards starts with the invention of the typewriter. Christopher Sholes, the inventor of the typewriter, tried with a two row piano style keyboard. But then, he got into many difficulties with the design. Then he finally settled for a four row design. This was similar to the QWERTY layout that most computers and typewriters today possess. The engineers at Remington, to whom Sholes had presented his design modified the layout a little further, and then the QWERTY was born. As typewriters became popular, people got used to the layout, and started practising touch typing, i.e. typing without looking at the keys...

The paradox of government

I'm fascinated by the concept of government, and the paradoxes it presents. On one hand, governments grant us a certain set of rights or liberties. On the other hand, they work to strip us of the very liberties they promise. Now, I don't mean that all governments strip people of liberties, but there are liberal regimes, and there are sufficiently restrictive and dictatorial ones. Both models may have results to show, it does not mean that people in a restrictive regime are unhappy (refer to Dan Dennett's TED talk , where he states that ideas or memes can be dangerous when taken from one part of the world, where they are widespread, and, using the virus analogy, where people are immune to the memes; to a part of the world where they are foreign, where people may not be immune to the memes and where people may get infected). History has shown that people were sufficiently satisfied with autocratic governments with a benevolent dictator, and that people in other parts of the ...