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?