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:
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
Post a Comment