//Lightstrip Controller //Adam Greig, 2008-06-04 //CC BY-SA-NC 3.0 #define F_CPU 1200000UL #include <avr/interrupt.h> #include <avr/delay.h> //Converge - how fast the average will converge to the current value. Default: 10 #define CONVERGE 10 //Peak - what multiple of the average will be considered a peak. Default: 1.3 #define PEAK 1.3 int main() { //Initialise registers. Note that the compiler optimises each to an integer, so the 0s just make life easier. ADMUX = (0<<REFS0) | (1<<ADLAR) | (1<<MUX1) | (1<<MUX0); ADCSRA = (1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (1<<ADPS0); DIDR0 = (0<<ADC0D) | (0<<ADC1D) | (0<<ADC2D ) | (1<<ADC3D); DDRB = (0<<PB0) | (0<<PB1) | (0<<PB2) | (0<<PB3) | (1<<PB4); //Initialise ADC, ignore first result ADCSRA |= (1<<ADSC); while( ADCSRA & (1<<ADSC) ) {} //Store duty cycle, background average, current result, difference between result and average. unsigned char duty; unsigned char avg; unsigned char result; signed char diff; //Main loop for( ;; ) { //Take a reading ADCSRA |= (1<<ADSC); while( ADCSRA & (1<<ADSC) ) {} result = ADCH; //Find the difference and converge the average diff = result - avg; avg += diff / CONVERGE; //Determine if it's a peak if( result > avg * PEAK ) duty = (100*result)/avg; else duty = 0; //Execute the duty cycle if (duty != 0 ) PORTB = 1<<PB4; for( int j=0; j<duty; j++ ) asm( "nop\n\t" "nop\n\t" "nop\n\t" :: ); PORTB = 0<<PB4; for( int j=100; j>duty; j-- ) asm( "nop\n\t" "nop\n\t" "nop\n\t" :: ); } }