Monday, March 30, 2009

Digital Thermometer

This is where I was heading to. With the last module, I was ready with 2 digit 7segment LED which could be used to show the current ambient temperature.

The only remaining part is to integrate the temperature sensor into the system, read, decode, and display the reading. I used the LM35 temperature sensor which is quite simple and handy to use (at the size of a transistor). LM35 is a centigrade temperature sensor and has 3 terminals -- VCC, Vout and GND. Connect VCC and GND with a 5V across, and you can calculate the current ambient temperature based on the potential available at Vout. Based on the datasheet of LM35, Vout is set to (0mV + 10 mV/degree). So a 100mV at Vout means a 10 degree centigrade temperature sensed.

Now, the remaining task is to make the micro controller (I use ATMega8) read this reading. uC deals only with digital data. This being an analog data, it has to ideally be fed through a Analog-to-Digital-Convertor (ADC). Incidentially, ATMega8 has an inbuilt ADC (with 6 channels in PDIP package). For the ADC to decode the analog data properly, the ARef (Pin 21 in PDIP) terminal has to be set to a reference voltage. To give an example, if the reference voltage is 5V, one unit in a 10bit ADC is defined as (5/1024) volt ie., ~5mV. So for every 5mV from the analog input (in our case, LM35), the reading from ADC goes up by 1 unit.

In my case, the ARef is set to 4.85V. Hence one ADC unit is (4.85/1024) volt ie., 4.736 mV. As discussed earlier LM35 outputs 10mV per degree Centigrade; so my temperature reading is (adc_reading * 4.736 / 10) or (adc_reading * 0.4736) deg. Centigrade.

Hardware:
The hardware part is just connecting the LM35 to my previous module. The output of LM35 is connected to ADC channel-2 (PIN 25 in PDIP) -- as channel 0,1 are shared with PORTC's 0-1 bits which I have been using as control bits for selecting the 7segment digit in TDM mode.

Software:
After enabling ADC channel-2, the ADC's current value is read and the temperature is calculated using the above derived formula. The value is stored in a global volatile variable which is displayed in the 7segs as in my previous module. The temperature is read every 2 seconds (just arbitrary).

Here is the code:

// Author : Gerald Naveen A (ageraldnaveen at gmail dot com)

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

#define F_CPU 1000000

#include <util/delay.h>

static volatile uint16_t g_temp_c = 99;

// insert TDM based seven segment code here... interrupt handling etc.,
// didn't want to bloat the codespace while publishing.

void initialize_adc()
{
ADMUX = (1 << REFS0);
ADCSRA = (1 << ADEN) | 7; // enable && prescaler /128
}

uint16_t read_adc_channel(unsigned int ch)
{
uint16_t result;

ADMUX |= (ch & 0x07); // enable ADC channel 7

ADCSRA |= (1 << ADSC); // start conversion

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

result = ADC; // read the result

ADCSRA |= (1 << ADIF); // signal done to ADC

return result;
}

int main()
{
sei();

initialize_adc();
// initialize timer etc., as my previous module

while(1) {
// reading from channel 2
uint16_t val = (uint16_t) read_adc_channel(2) * 0.4736;
if(val < 100) // just to avoid noise, have a upper limit (100 too big?)
g_temp_c = val; // send it for display

_delay_ms(2000);
}
return 0;
}
Here is a snapshot of my setup showing the temperature inside my refrigerator :) I could not shoot a meaningful video, as the project shows an almost constant number. The temperature was actually showing 8 degrees when I opened the fridge after putting my project inside for around 5 minutes; when I opened the door and while I was trying to place the breadboard upright for the digits to be visible and clicked, the temperature had shot up by a few degrees due to the door being open :D


2 comments:

  1. Good thing you're using the Centigrade scale . Had you used Fahrenheit, considering the rate at which temperature is rising in Chennai, you'd quickly have to move to 3 digit LEDs :).

    BTW, how does the temperature sensor indicate temperatures below zero? Is it calibrated such that 0V is a large negative temperature reading?

    ReplyDelete
  2. Hehe.. true (about fahrenheit).

    Actually in this setup I cannot measure negative temperatures. To measure -ve temperatures, I need to provide a negative (potential: -Vcc) pull down at Vout through a resistor. If connected that way, I would get negative readings too. I didn't find a need to do it because it is almost impossible to test at home -- anyways I also need one more digit if I need to display -ve reading :)

    ReplyDelete