NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Control PC5 by temperature

March 13, 2011
by Bigforky
Bigforky's Avatar

Nerds,

I’m working on my second nerdkit project and I am a little confused by the behavior of how the ADC is reacting when I add the use of PC5 turning on a switch.

The project is a refrigerator heater – I know, this project sounds silly, but we live in a part of the US where the outside temperature regularly reaches temperatures well below freezing. We have a second refrigerator in the garage to keep milk and other groceries that don’t fit inside. When we get into the colder months the temperature in the garage quite regularly reaches temperatures below 0F and after a few days milk, beverages, and food begin to freeze.

My plan for the atmega168 is to switch on and off a small heating element (like a small light bulb) and a small fan that would cycle on when the temp inside the refrigerator reaches about 34 degrees, and back off when it reaches 38 degrees. PC5 would drive a solid state relay to handle the fan and heater at 120vac.

I started by using the tempsensor code and modified it by adding the snippets from ledblink to turn on and off PC5, and am testing with temperatures easily obtained in the man-chamber.

The result is odd behavior with the ADC having values MUCH higher the instant the logic to switch on PC5 is true – which drives the temperature value on the LCD to over 380 degrees. Can anyone spot my pitfall?

// tempsensor.c
// for NerdKits with ATmega168
// mrobbins@mit.edu

//modified for refrigerator warmer project

#define F_CPU 14745600

#include <stdio.h>
#include <math.h>

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

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// PIN DEFINITIONS:
//
// PC0 -- temperature sensor analog input

void adc_init() {
  // set analog to digital converter
  // for external reference (5v), single ended input ADC0
  ADMUX = 0;

  // set analog to digital converter
  // to be enabled, with a clock prescale of 1/128
  // so that the ADC clock runs at 115.2kHz.
  ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);

  // fire a conversion just to get the ADC warmed up
  ADCSRA |= (1<<ADSC);
}

uint16_t adc_read() {
  // read from ADC, waiting for conversion to finish
  // (assumes someone else asked for a conversion.)
  // wait for it to be cleared
  while(ADCSRA & (1<<ADSC)) {
    // do nothing... just hold your breath.
  }
  // bit is cleared, so we have a result.

  // read from the ADCL/ADCH registers, and combine the result
  // Note: ADCL must be read first (datasheet pp. 259)
  uint16_t result = ADCL;
  uint16_t temp = ADCH;
  result = result + (temp<<8);

  // set ADSC bit to get the *next* conversion started
  ADCSRA |= (1<<ADSC);

  return result;
}

double sampleToFahrenheit(uint16_t sample) {
  // conversion ratio in DEGREES/STEP:
  // (5000 mV / 1024 steps) * (1 degree / 10mV)
  //    ^^^^^^^^^^^      ^^^^^^^^^^
  //     from ADC         from LM34
  return sample * (5000.0 / 1024.0 / 10.0);  
}

int main() {
  // start up the LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

  // start up the Analog to Digital Converter
  adc_init();

  // start up the serial port
  uart_init();
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdin = stdout = &uart_stream;

  // holder variables for temperature data
  uint16_t last_sample = 0;
  double this_temp;
  double temp_avg;
  uint8_t i;
  int heat;

  while(1) {
    // take 100 samples and average them!

    temp_avg = 0.0;
    for(i=0; i<100; i++) {
      last_sample = adc_read();
      this_temp = sampleToFahrenheit(last_sample);

      // add this contribution to the average
      temp_avg = temp_avg + this_temp/100.0;
      }

 ///////////////////////////////////////////////
 //code added to make the heater turn on/off  //
 ///////////////////////////////////////////////

 // pin28 for output to heater led
 DDRC |= (1<<PC5);

 //logic to turn on off heat
 if (temp_avg>77){heat=0;}  //sets info for LCD
 if (temp_avg>77) {PORTC &= ~(1<<PC5);}

 //logic to turn on off heat
 if (temp_avg<74){heat=1;}  //sets info for LCD
 if (temp_avg<74){PORTC |= ~(1<<PC5);}

 ///////////////////////////////////////////////
 //        End code for heater on/off         //
 ///////////////////////////////////////////////

    // write message to LCD
    lcd_home();
    lcd_write_string(PSTR("ADC: "));
    lcd_write_int16(last_sample);
    lcd_write_string(PSTR(" of 1024   "));
    lcd_line_two();
    fprintf_P(&lcd_stream, PSTR("Current Temp:%.1f"), temp_avg);
    lcd_write_data(0xdf);
    lcd_write_string(PSTR("F      "));
    lcd_line_three();
    lcd_write_string(PSTR("Heater - "));
    lcd_write_int16(heat);
    lcd_line_four();
    lcd_write_string(PSTR("Milk is - OK "));

    // write message to serial port
    printf_P(PSTR("%.2f degrees F\r\n"), temp_avg);
  }

  return 0;
}
March 13, 2011
by Bigforky
Bigforky's Avatar

Found my mistake....I had a tilde where there shouldn't be.

March 13, 2011
by Ralphxyz
Ralphxyz's Avatar

Oh that's NOT a good thing to do, glad you found it.

Ralph

Post a Reply

Please log in to post a reply.

Did you know that an analog comparator can tell when one voltage input crosses another? Learn more...