Page 1 of 1

ATMega8 auto-calibratable photosensor

Posted: Sun Feb 09, 2014 8:05 pm
by SemiconductorCat
Hi I'm using ATMega8 on this project.

Code: Select all

/* 
    TO COMPILE 
     avr-gcc -g -Os -mmcu=atmega8 -c serial.c
     avr-gcc -g -mmcu=atmega8 -o serial.elf serial.o
     avr-objcopy -j .text -j .data -O ihex serial.elf serial.hex

   TO FLASH:
      avrdude -p m8 -P usb -c usbasp -Uflash:w:serial.hex:i 
      [@Mr. Thisara: please ignore the warning messages , refer drawing 1 for schematic.]
      Turns on the impression solonoid when paper cut the photo-resistor.
      Replace the old analog preset and auto calibrate .

     (c) Udara Type Setting Panadura.

*/
#define F_CPU 16000000UL 

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


void bit_set_portb(int bit)
{
  int mask = (1<<bit);
  PORTB = PORTB | mask;

}



int is_bit_set_portb(int bit)
{
  
  int mask = (1<<bit);
  int val = PINB & mask ;
  if( val ==0)
  {
    return 0; 
  }
  
  return 1;
}



void adc_init(void){
 
 ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0));    //16Mhz/128 = 125Khz the ADC reference clock
 ADMUX |= (1<<REFS0);                //Voltage reference from Avcc (5v)
 ADCSRA |= (1<<ADEN);                //Turn on ADC
 ADCSRA |= (1<<ADSC);                //Do an initial conversion because this one is the slowest and to ensure that everything is up and running
}

uint16_t read_adc(uint8_t channel){
 ADMUX &= 0xF0;                    //Clear the older channel that was read
 ADMUX |= channel;                //Defines the new ADC channel to be read
 ADCSRA |= (1<<ADSC);                //Starts a new conversion
 while(ADCSRA & (1<<ADSC));            //Wait until the conversion is done
 return ADCW;                    //Returns the ADC value of the chosen channel
}



void main()
{
   adc_init();

  /* set port B I/O directions */
  /* PB1 - calibration progress LED */
  /* PB2 - calibration finished LED */
  /* PB3 - going to solonoid */
  /* PB4 - input , calibration switch */
  /* ADC0 - going to LDR input , LDR is pulled up with a 10K */
  DDRB = 0b00000111;
  bit_clear_portb(1);
  bit_set_portb(0);
  

  int idle_value ;
  int delta ; 
  _delay_ms(500);
  idle_value = read_adc(0);
  _delay_ms(500);  
  bit_set_portb(1);
  bit_clear_portb(0);
  
      static int analog_reading ;
  while(1){
    if(is_bit_set_portb(3)) /* PB3 is the calibration push button */
    {
      bit_clear_portb(1);
      bit_set_portb(0);
      _delay_ms(500);
      idle_value = read_adc(0);
      _delay_ms(500);  
      bit_set_portb(1);
      bit_clear_portb(0);
      continue;
    }
    

    /* read the analog again */
    analog_reading = read_adc(0);

    delta = analog_reading ^ idle_value ;
    if( delta >70){ /* magic value 70 means ,if we found more than 70 delta it should trigger */
      bit_set_portb(2); // PB2 is going to solonoid //
    }else{
      bit_clear_portb(2); 
    }
    _delay_ms(50); // * avoid some race conditions and bouncing effects */
  }
}

My question are bellow.

* ATMega8 costs around 160/-Rs on the local market. What I need is a cheaper device , I know I could do this with pure analog design. But I also heard that there are very cheap micro-controllers there too. I'm planing on ATiny series.
I just need 3 GPIO and one analog input for this. I also need to know how much ?

* My second question is to implement the soft start solenoid algorithm. Where I could have two thread , one thread would read the analog value on that LDR connected pin and then change the state variable on thread 2. Then thread 2 will generate soft PWM on the solonoid. Is that a good design? So that I need to keep a sine table inside the micro-controller?
Any other better way to do this?

* As you could see I have hardcoded the delta value to trigger and the debouncing time too.
I've taken these values by experimenting. Is any dynamic method to get these values like auto calibration?