10色音乐频谱led

        做这个东西也是心血来潮,正好专业课接触到数字信号处理,也正在学习DTFT和FFT,

加上已有的单片机基础和电路常识,硬件部分算不上什么难事,需要注意的也就只是声音

信号的滤波吧,因为本身就是拿来玩的,所以滤波没太在意,单纯用电容滤一些杂波,播放

的时候影响不是很大,但没有声音的时候,明显会出现杂波的频谱,这就很尴尬了。

        好了,废话不多说了,直接上图,DIY非在前人基础上增加了一些功能,并非原创。

10色音乐频谱led_第1张图片

这是主控板的的正面图,下面的是led正面效果,当然是没有焊接完成的

10色音乐频谱led_第2张图片

10色音乐频谱led_第3张图片

黑暗中的运行效果,怎么样,效果还是可以的呢。

下面粘上程序代码,参考的部分比较多,C语言版本的FFT算法不是很明白,也是复制粘贴过来的

#include //"stc12c5620ad.h"
#include
#define LongToBin(n) (((n>>21)&0x80)|((n>>18)&0x40)|((n>>15)&0x20)|((n>>12)&0x10)|((n>>9)&0x08)|((n>>6)&0x04)|((n>>3)&0x02)|((n)&0x01))
#define BIN(n) LongToBin(0x##n##)
#define uchar  unsigned char
#define uint  unsigned int
#define SAMPLE_NUM 64
#define NUM_2_LOG 7
#define FFT_OUT_MIN 3


uchar code BRTable[SAMPLE_NUM] ={ 0, 32, 16, 48, 8, 40, 24, 56,4, 36, 20, 52, 12, 44, 28, 60, 2, 34, 18, 50, 
																	10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62, 1, 33, 17, 49, 9, 41, 25, 57,
																	5, 37, 21, 53, 13, 45, 29, 61,3, 35, 19, 51, 11, 43, 27, 59,7, 39, 23, 55, 15, 47, 31, 63};
char code sin_tabb[SAMPLE_NUM] = { 0 ,12 ,25 ,37 ,49 ,60 ,71 ,81 ,90 ,98 ,106 ,112 ,117 ,122 ,125 ,126 ,127 ,126 ,125 ,122 ,117 ,112 ,106 ,98 ,90 ,81 ,71 ,60 ,49 ,37 ,25 ,12 ,0 ,-12 ,-25 ,-37 ,-49 ,-60 ,-71 ,-81 ,-90 ,-98 ,-106 ,-112 ,-117 ,-122 ,-125 ,-126 ,-127 ,-126 ,-125 ,-122 ,-117 ,-112 ,-106 ,-98 ,-90 ,-81 ,-71 ,-60 ,-49 ,-37 ,-25 ,-12  }; 
                                  
char code cos_tabb[SAMPLE_NUM] = {127 ,126 ,125 ,122 ,117 ,112 ,106 ,98 ,90 ,81 ,71 ,60 ,49 ,37 ,25 ,12 ,0 ,-12 ,-25 ,-37 ,-49 ,-60 ,-71 ,-81 ,-90 ,-98 ,-106 ,-112 ,-117 ,-122 ,-125 ,-126 ,-127 ,-126 ,-125 ,-122 ,-117 ,-112 ,-106 ,-98 ,-90 ,-81 ,-71 ,-60 ,-49 ,-37 ,-25 ,-12 ,0 ,12 ,25 ,37 ,49 ,60 ,71 ,81 ,90 ,98 ,106 ,112 ,117 ,122 ,125 ,126 };
uchar a[16];
uchar keep,keepnum,anum,timernum;//用于分离

/*加入数组用于显示相应led灯数目*/
uchar lednum[]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};//0-7的显示数组  P2组控制
int xdata FftReal[SAMPLE_NUM];
int xdata FftImage[SAMPLE_NUM];
sbit p20=P2^0;
sbit p27=P2^7;

void timerinit()//定时器 初始化函数
{
	 TMOD=0x01;
	 TH0=(65536-6000)/256;
	 TL0=(65536-6000)%256;
	 EA=1;
	 ET0=1;
	 TR0=1;
}
void disp()
{
	timernum++;
	if(timernum==12) timernum=1;
	P2=0;//显示前先关闭
	P2=P2&0x7e;
	switch(timernum)
	{
	case 1:anum=a[0];P2=0x3e;P3=0xff;break;
	case 2:anum=a[1];P2=0x5e;P3=0xff;break;
	case 3:anum=a[2];P2=0x6e;P3=0xff;break;
	case 4:anum=a[3];P2=0x76;P3=0xff;break;
	case 5:anum=a[4];P2=0x7a;P3=0xff;break;
	case 6:anum=a[5];P2=0x7c;P3=0xff;break;
	case 7:anum=a[6];P2=0x7e;P3=0xfe;break;
	case 8:anum=a[7];P2=0x7e;P3=0xfd;break;
	case 9:anum=a[8];P2=0x7e;P3=0xfb;break;
	case 10:anum=a[9];P2=0x7e;P3=0xf7;break;
	case 11:anum=a[10];P2=0x7e;P3=0xef;break;
	}
	//anum=a[10];/*修改可以改变光柱高度 (anum值分开几个部分用定时器区分显示)(a[]内逐加) */
  if(anum<=8){P0=lednum[anum];P2=P2&0x7e;}
  if(anum==9){P0=0xff;p27=1;p20=0;}
  if(anum==10){P0=0xff;p27=1;p20=1;}

}

uchar STC_ADC()		   //!!根据数据手册写一个ad读取函数
  {

        ADC_RES   = 0;
        ADC_RESL  = 0;
  ADC_CONTR = BIN(10001000);
       _nop_;_nop_;_nop_;
        while (1)                      
     {
         if (ADC_CONTR & BIN(10000))       
         { 
  	  break;
  	     }
     }
      ADC_CONTR = BIN(10000000);
      return(ADC_RESL<<1) ;
 }
short sqrt_16( unsigned long M)   
{
    unsigned int N, i;
    unsigned long tmp, ttp; 
    if( M == 0 )             
        return 0;
    
    N = 0;
    
    tmp = ( M >> 30 );        
    M <<= 2;
    if( tmp > 1 )            
    {
        N ++;               
        tmp -= N;
    }
    
    for( i=15; i>0; i-- )   
    {
        N <<= 1;           
        
        tmp <<= 2;
        tmp += (M >> 30);  
        
        ttp = N;
        ttp = (ttp<<1)+1;
        
        M <<= 2;
        if( tmp >= ttp )    
        {
            tmp -= ttp;
            N ++;
        }       
    }
    
    return N;
}
void FFT()
{
 register    uchar i,bb,j,k,p,max;
 register short TR,TI,temp;
    unsigned long ulReal;                             
    unsigned long ulImage;
    
    
                                                                 
 for(i=0; i>7) + ((FftImage[k+bb]*sin_tabb[p])>>7);
                FftImage[k] = FftImage[k] - ((FftReal[k+bb]*sin_tabb[p])>>7) + ((FftImage[k+bb]*cos_tabb[p])>>7);
                FftReal[k+bb] = TR - ((FftReal[k+bb]*cos_tabb[p])>>7) - ((FftImage[k+bb]*sin_tabb[p])>>7);
                FftImage[k+bb] = TI + ((temp*sin_tabb[p])>>7) - ((FftImage[k+bb]*cos_tabb[p])>>7); 
                
                FftReal[k]  >>= 1;             
                FftImage[k]  >>= 1; 
                FftReal[k+bb]  >>= 1;                 
                FftImage[k+bb]  >>= 1; 
                                                                               
            }  
        }
    }
    max=0;
    for( i=0; i<11; i++)//5
    {  
        ulReal = FftReal[i+1];
        ulReal *= ulReal;
        ulImage = FftImage[i+1];
        ulImage *= ulImage;
        
        a[i] = sqrt_16( ulReal + ulImage );   //修改
                         
        if( a[i] < FFT_OUT_MIN )     
            a[i] = 0;//修改
        else
          a[i] = a[i]-FFT_OUT_MIN;
        if( a[i] >max)
             max =a[i];
			 //disp();                      
    }
    if(max>10) //11
    {
       max/=10;	
        for( i=0; i<11; i++) //输出a的5个分离数值
        {      
             a[i]/=max;
            
        }  
    }
}             


void main()
{
	P0M0=0xff;//  BIN(11111111);//P2组设置为推挽输出
	P0M1=0;	  
	P2M0=0x81;//  BIN(11111111);
	P2M1=0;
	P1M0=0x00;
	P1M1=0x01;
 	P1ASF =1;	   //设置P1.0为AD口
    AUXR1 =BIN(000);

	keep=0;
	keepnum=0;

	timerinit();//定时器初始化

	timernum=3;//从3开始
	//timernum2=0;
    while(1)
 {
           FFT();
 }
 }

void timer0() interrupt 1
{
	TH0=(65536-3000)/256;	 //6000
	TL0=(65536-3000)%256;
	disp();
}

观看效果视频


你可能感兴趣的:(51,51单片机,信号,音乐)