fft_led/main.c

185 lines
3.9 KiB
C

#include<avr/power.h>
#include<util/delay.h>
#include<avr/io.h>
#include"fix_fft.h"
#include"avr_adc.h"
#include"light_ws2812_AVR/Light_WS2812/ws2812_config.h"
#include"light_ws2812_AVR/Light_WS2812/light_ws2812.h"
#include"main.h"
#define STARTADC ADCSRA |= (1<<ADSC)
#define PB_mic PB0
#define NOISE 100
#define SCALE_FACTOR 10
//resolution fft calc:
//https://3roam.com/fft-resolution-bandwidth-calculator/
//128 samples , 1kSPS = 7.8Hz
//interested in 0-10000 Hz
//
//128 bins a 7.8hz = 0...1000Hz
//
//we have 8 leds:
//bands 125hz/band -> 16 bins
//
//1-7.8 - ca 130hz
//2- 255hz
//3- 380
//4- 505
//5- 630
//6- 755
//7- 880
//8- 1kHz
//
int sec;
uint16_t ticks;
int ticks_sample;
ISR(TIMER1_OVF_vect)
{
ticks_sample++;
if(ticks < 65000)
{
ticks++;
}
if(ticks >= 65000)
{
ticks=0;
if(sec<255)
{
sec++;
}
else
{
sec=0;
}
}
}
int main (void)
{
int i,i2;
int i4=0;
int sum,avg;
char sample[64];
char buff[64];
float fac_r=0.1;
float fac_g=0.5;
float fac_b=0.7;
sec=0;
ticks=0;
ticks_sample=0;
struct cRGB led_bar1[8];
Fader fader1[4]={{5,5,5},{7,3,2},{3,7,2},{2,3,7}};
//DDRB = (1<<mic);//would be setting output, default is input so no need for setting
setupADC();
setupTimer();
//OSCCAL = 250;//overclock!!! to 30MHz
for(i=0;i<8;i++)
{
led_bar1[i].r=0;
led_bar1[i].g=0;
led_bar1[i].b=0;
}
for(i=0;i<64;i++)
{
buff[i]=0;
}
sei();
while(1)
{
//######RECORD SAMPLES######
sum = 0;
ticks_sample=0;
if(sec>3)
{
fac_r=(float)fader1[i4].r/10;
fac_g=(float)fader1[i4].g/10;
fac_b=(float)fader1[i4].b/10;
if(i4<3) {i4++;}
else {i4=0;}
sec=0;
}
for(i=0;i<64;i++)
{
STARTADC;
sample[i] = (ADCH-128); //read Analog value register 8bit center -128
//sample[i] = (sample[i] <= NOISE) ? 0 : (sample[i] - NOISE); //noise reduction
sum+=sample[i];//dc-bias
}
avg = sum/64;//calculate bias
for(i=0;i<64;i++)
{
sample[i]-=avg;//remove bias
}
fix_fftr(sample,6,0);
//####Averaging Data####
for(i=0;i<64;i++)
{
if(sample[i]<0) sample[i] = 0;
if(sample[i]>64) sample[i]=64; //define upper limit
sample[i] = sample[i] *SCALE_FACTOR;
sample[i] = (sample[i]*0.7 + buff[i]*0.3); //influence of last sample on current sample
buff[i] = sample[i]; //store sample for next round
}
for(i=0;i<8;i++) //we store 8 frequency domains acros the whole 64 stpectrum
{
for(i2=1;i2<=4;i2++)
{
sample[i] = ((sample[i] + sample[i*8+i2])/2);//average each 4 following spectrums, write results to sample[0..7]
}
if(sample[i]<20)
{
led_bar1[i].r=(char)sample[i]*fac_r;
led_bar1[i].g=(char)sample[i]*fac_g;
led_bar1[i].b=(char)sample[i]*fac_b;
}
else if(sample[i]<30)
{
led_bar1[i].r=(char)sample[i]*fac_r*2;
led_bar1[i].g=(char)sample[i]*fac_g/2;
led_bar1[i].b=(char)sample[i]*fac_b/2;
}
else if(sample[i]<50)
{
led_bar1[i].r=(char)sample[i]*fac_r*2;
led_bar1[i].g=(char)sample[i]*fac_g*2;
led_bar1[i].b=(char)sample[i]*fac_b*2;
}
}
ws2812_setleds(led_bar1,8);
while(ticks_sample<60){asm("");}//workaround for stoping gcc optimizing
}
return 0;
}
void setupTimer(void)
{
clock_prescale_set(0);
TCCR1 = (1<<CS10);//|(1<<CS10)|(1<<CTC1); /8 //clear timer on compare match
GTCCR = 0; //default values should be ok
//OCR1C = 117; //Compare value of timer / overflow , sets OCF1A
//OCR1A = 117;
TIMSK |= (1<<TOIE1);//|(1<<TOIE1); //timer0 ovf
TIFR |= (1<<TOV1); //flag register "aka when to interrupt
}
/*
* 1/(30Mhz/16384) *255 = 0.139264s Time for one overflow
* 1024 = 0.008704s
* 2024 = 0.017204s
* 255/0.017204*0.001=15 counts = 1ms
* 256 gives 1ms
*/