|
自己寫的一個(gè)項(xiàng)目,基于FFT算法實(shí)現(xiàn)的音樂(lè)頻譜,利用OLED實(shí)現(xiàn)顯示,需要在32M晶振運(yùn)行
單片機(jī)源程序如下:
- #include"OLED.H"
- sbit sb0=P3^6;//定義按鈕位置
- sbit sb1=P3^5;
- idata uchar fft_shuzu[2][32];
- uint s_time;
- struct compx //定義復(fù)數(shù)結(jié)構(gòu)體
- {
- float real;
- float imag;
- };
- xdata struct compx s[ 64 ]; //FFT數(shù)據(jù)緩存放在XDATA空間
- struct compx EE(struct compx,struct compx); //復(fù)數(shù)乘法函數(shù)的聲明
- void FFT(struct compx xin[],int N); //FFT函數(shù)的聲明
- struct compx EE(struct compx a1,struct compx b2) //復(fù)數(shù)乘法
- {
- struct compx b3;
- b3.real=a1.real*b2.real-a1.imag*b2.imag;
- b3.imag=a1.real*b2.imag+a1.imag*b2.real;
- return(b3);
- }
- /*FFT函數(shù)*/
- void FFT(struct compx xin[],int N)
- {
- int f,m,nv2,nm1,i,k,j=1,l;
- struct compx v,w,t;
- nv2=N/2;
- f=N;
- for(m=1;(f=f/2)!=1;m++){;}
- nm1=N-1;
- for(i=0;i<nm1;i++) //倒序操作
- {
- if(i<j)
- {
- t=xin[j];
- xin[j]=xin[i];
- xin[i]=t;
- }
- k=nv2; //k為倒序中相應(yīng)位置的權(quán)值
- while(k<j)
- {
- j=j-k;
- k=k/2;
- }
- j=j+k;
- }
- {
- int le,lei,ip;
- float pi;
- for(l=1;l<=m;l++)
- {
- le=pow(2,l); //乘方
- lei=le/2;
- pi=3.14159265;
- v.real=1.0;
- v.imag=0.0;
- w.real=cos(pi/lei); //旋轉(zhuǎn)因子
- w.imag=-sin(pi/lei);
-
- for(j=1;j<=lei;j++) //控制蝶形運(yùn)算的級(jí)數(shù)
- {
- for(i=j-1;i<N;i=i+le) //控制每級(jí)蝶形運(yùn)算的次數(shù)
- {
- ip=i+lei;
- t=EE(xin[ ip ],v);
- xin[ ip ].real=xin[ i ].real-t.real; //蝶形計(jì)算
- xin[ ip ].imag=xin[ i ].imag-t.imag;
- xin[ i ].real=xin[ i ].real+t.real;
- xin[ i ].imag=xin[ i ].imag+t.imag;
- }
- v=EE(v,w);
- }
- }
- }
- }
- void showbar0()//延時(shí)跳帽函數(shù)
- {
- unsigned char i,j,x,p,high,tigh,temp,itemp;
- xdata unsigned char dis_rdata[16];
- for(i=0;i<16;i++) //讀取FFT轉(zhuǎn)換數(shù)據(jù)
- {
- float t0=0;
- t0=sqrt(pow((s[i ].real+s[i+1].real),2)+pow((s[i ].imag+s[i+1].imag),2))/2;
- dis_rdata[i]=(unsigned char)t0;
- }
- // OLED_Display_On();
- for(i=0;i<16;i++)//16個(gè)條形柱控制
- {
- itemp=high=0;
- itemp=high=dis_rdata[i];//對(duì)處理變量賦值
- // high=high/1;
- for(x=0;x<8;x++)//清空當(dāng)前條形柱空間
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0x00;
- for(j=0;j<8;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
-
- if(high>64)high=64;//溢出值限制
- if(fft_shuzu[0][i]<=high)//檢測(cè)當(dāng)前大小
- {
- fft_shuzu[0][i]=high;//大于賦值當(dāng)前頻譜帽為此值
- fft_shuzu[1][i]=10;//重新設(shè)置當(dāng)前延時(shí)
- }
- fft_shuzu[1][i]--;//當(dāng)前延時(shí)自減
- if(fft_shuzu[1][i]==0)//如果當(dāng)前延時(shí)為0
- {
- fft_shuzu[0][i]=high;//強(qiáng)度等于當(dāng)前大小
- }
-
- p=high/8; //掃描圖形生成
- tigh=high%8;
- for(x=0;x<p;x++)//填滿單元區(qū)域
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0xff;
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
-
- p=fft_shuzu[0][i]/8;//生成延時(shí)帽所在位置函數(shù)
- tigh=fft_shuzu[0][i]%8;
- if((itemp/8)==p)//如果與所在位置重合
- {
- OLED_Set_Pos(i*8,7-p);//到達(dá)所在位置
- temp=0x80>>tigh;//生成延時(shí)帽
- temp=temp|~0xff>>(high%8);//合并當(dāng)前位置
- for(j=0;j<7;j++)//發(fā)送屏幕
- {
- OLED_WR_Byte(temp,1);
- }
- }
- else//如果不重合
- {
- OLED_Set_Pos(i*8,7-p);//到達(dá)生成位置
- temp=0x80>>tigh;//生成延時(shí)帽
- for(j=0;j<7;j++)//發(fā)送屏幕
- {
- OLED_WR_Byte(temp,1);
- }
-
- OLED_Set_Pos(i*8,7-(high/8));//到達(dá)非滿數(shù)單元
- temp=~0xff>>(itemp%8);//生成條形柱
- for(j=0;j<7;j++)//發(fā)送
- {
- OLED_WR_Byte(temp,1);
- }
- }
- }
- }
- /*----以下生成函數(shù)原理差不多----*/
- void showbar1()//條形柱函數(shù)
- {
- unsigned char i,j,x,p,high,tigh,temp;
- xdata unsigned char dis_rdata[16];
- for(i=0;i<16;i++) //讀取FFT轉(zhuǎn)換數(shù)據(jù)
- {
- float t0=0;
- t0=sqrt(pow((s[i ].real+s[i+1].real),2)+pow((s[i ].imag+s[i+1].imag),2))/2;
- dis_rdata[i]=(unsigned char)t0;
- }
- // OLED_Display_On();
- for(i=0;i<16;i++)
- {
- high=0;
- high=dis_rdata[i];
- // high=high/1;
- for(x=0;x<8;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0x00;
- for(j=0;j<8;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- if(high>64)high=64;
- if(high==0)high=1;
- p=high/8;
- tigh=high%8;
- for(x=0;x<p;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0xff;
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- OLED_Set_Pos(i*8,7-(high/8));
- temp=~0xff>>(high%8);
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- }
- void showbar2()//等號(hào)指示函數(shù)
- {
- unsigned char i,j,x,p,high,tigh,temp,itemp;
- xdata unsigned char dis_rdata[16];
- for(i=0;i<16;i++) //讀取FFT轉(zhuǎn)換數(shù)據(jù)
- {
- float t0=0;
- t0=sqrt(pow((s[i ].real+s[i+1].real),2)+pow((s[i ].imag+s[i+1].imag),2))/2;
- dis_rdata[i]=(unsigned char)t0;
- }
- // OLED_Display_On();
- for(i=0;i<16;i++)
- {
- itemp=high=0;
- itemp=high=dis_rdata[i];
- // high=high/1;
- for(x=0;x<8;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0x00;
- for(j=0;j<8;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- if(high>64)high=64;
- p=high/8;
- tigh=high%8;
- if(p==0)
- {
- p=1;
- temp=0x80;
- }
- else temp=0x88;
- for(x=0;x<p;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- }
- }
- void showbar3()//延時(shí)跳帽函數(shù)取反
- {
- unsigned char i,j,x,p,high,tigh,temp,itemp;
- xdata unsigned char dis_rdata[16];
- for(i=0;i<16;i++) //讀取FFT轉(zhuǎn)換數(shù)據(jù)
- {
- float t0=0;
- t0=sqrt(pow((s[i ].real+s[i+1].real),2)+pow((s[i ].imag+s[i+1].imag),2))/2;
- dis_rdata[i]=(unsigned char)t0;
- }
- // OLED_Display_On();
- for(i=0;i<16;i++)
- {
- itemp=high=0;
- itemp=high=dis_rdata[i];
- // high=high/1;
- for(x=0;x<8;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0xFF;
- for(j=0;j<8;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
-
- if(high>64)high=64;
- if(fft_shuzu[0][i]<=high)
- {
- fft_shuzu[0][i]=high;
- fft_shuzu[1][i]=10;
- }
- fft_shuzu[1][i]--;
- if(fft_shuzu[1][i]==0)
- {
- fft_shuzu[0][i]=high;
- }
-
- p=high/8;
- tigh=high%8;
- for(x=0;x<p;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0x00;
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
-
- p=fft_shuzu[0][i]/8;
- tigh=fft_shuzu[0][i]%8;
- if((itemp/8)==p)
- {
- OLED_Set_Pos(i*8,7-p);
- temp=~0x80>>tigh;
- temp=temp|0xff>>(high%8);
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- else
- {
- OLED_Set_Pos(i*8,7-p);
- temp=~0x80>>tigh;
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
-
- OLED_Set_Pos(i*8,7-(high/8));
- temp=0xff>>(itemp%8);
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- }
- }
- void showbar4()//條形柱取反函數(shù)
- {
- unsigned char i,j,x,p,high,tigh,temp;
- xdata unsigned char dis_rdata[16];
- for(i=0;i<16;i++) //讀取FFT轉(zhuǎn)換數(shù)據(jù)
- {
- float t0=0;
- t0=sqrt(pow((s[i ].real+s[i+1].real),2)+pow((s[i ].imag+s[i+1].imag),2))/2;
- dis_rdata[i]=(unsigned char)t0;
- }
- // OLED_Display_On();
- for(i=0;i<16;i++)
- {
- high=0;
- high=dis_rdata[i];
- // high=high/1;
- for(x=0;x<8;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0xff;
- for(j=0;j<8;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- if(high>64)high=64;
- if(high==0)high=1;
- p=high/8;
- tigh=high%8;
- for(x=0;x<p;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0x00;
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- OLED_Set_Pos(i*8,7-(high/8));
- temp=0xff>>(high%8);
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- }
- void showbar5()//等號(hào)指示函數(shù)
- {
- unsigned char i,j,x,p,high,tigh,temp,itemp;
- xdata unsigned char dis_rdata[16];
- for(i=0;i<16;i++) //讀取FFT轉(zhuǎn)換數(shù)據(jù)
- {
- float t0=0;
- t0=sqrt(pow((s[i ].real+s[i+1].real),2)+pow((s[i ].imag+s[i+1].imag),2))/2;
- dis_rdata[i]=(unsigned char)t0;
- }
- // OLED_Display_On();
- for(i=0;i<16;i++)
- {
- itemp=high=0;
- itemp=high=dis_rdata[i];
- // high=high/1;
- for(x=0;x<8;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- temp=0xff;
- for(j=0;j<8;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- if(high>64)high=64;
- p=high/8;
- tigh=high%8;
- if(p==0)
- {
- p=1;
- temp=~0x80;
- }
- else temp=~0x88;
- for(x=0;x<p;x++)
- {
- OLED_Set_Pos(i*8,7-x);
- for(j=0;j<7;j++)
- {
- OLED_WR_Byte(temp,1);
- }
- }
- }
- }
- /*主函數(shù)*/
- void main()
- {
- int N=64,i,k; //變量初始化,64點(diǎn)FFT運(yùn)算
- float offset;
- s_time=0;
-
- TMOD=0X01; //定時(shí)器開(kāi)到模式1
- TH0=(65535-10000)/256; //設(shè)置延時(shí)時(shí)間
- TL0=(65535-10000)%256;
- TR0=1; //啟動(dòng)定時(shí)器0
- ET0=1; //開(kāi)啟定時(shí)器0中斷
- EA=1; //開(kāi)啟中斷
-
- oled_init(); //OLED
- OLED_Clear();
-
- P1ASF=0x01; //P10口做AD 使用
- P1M0 = 0x01; //0000,0001用于A/D轉(zhuǎn)換的P1.x口,先設(shè)為開(kāi)漏
- P1M1 = 0x01; //0000,0001 P1.0先設(shè)為開(kāi)漏。斷開(kāi)內(nèi)部上拉電阻
- ADC_CONTR=0xC8; //40.96K采樣率
- while(!(ADC_CONTR&0x10));
- offset=((float)ADC_RES*4+(float)(ADC_RESL%0x04)); //AD結(jié)果高8位左移2位,低2位不變,然后相加
- while(1)
- { if(P3==(P3&0xFE))IAP_CONTR=0x60;
- for(i=0;i<N;i++) //采集音頻信號(hào)
- {
- ADC_CONTR=0xC8; //40.96K采樣率
- while(!(ADC_CONTR&0x10));
- s[i].real=((float)ADC_RES*4+(float)(ADC_RESL%0x04)-offset);//((((int)ADC_DATA-128)/2))*4;
- s[i].imag=0;
- }
- FFT(s,N); //調(diào)用FFT函數(shù)進(jìn)行變換
- EA=0;
- if(sb0==0) //模式調(diào)節(jié)按鈕控制
- {
- delay(100);
- if(sb0==0)
- {
- while(!sb0);
- delay(100);
- k+=1;
- if(k==6)k=0;
- }
- }
- if(sb1==0) //延時(shí)調(diào)節(jié)按鈕控制
- {
- delay(100);
- if(sb1==0)
- {
- while(!sb1);
- delay(100);
- s_time+=100;
- if(s_time==1100)s_time=0;
- }
- }
- switch(k) //顯示頻譜
- {
- case 0:showbar0();break; //延時(shí)跳帽函數(shù)
- case 1:showbar1();break; //條形柱函數(shù)
- case 2:showbar2();break; //等號(hào)條函數(shù)
- case 3:showbar3();break; //延時(shí)跳帽函數(shù)取反
- case 4:showbar4();break; //條形柱函數(shù)取反
- case 5:showbar5();break; //等號(hào)條函數(shù)取反
- }
- EA=1;
- delay(s_time);//顯示延時(shí)函數(shù)
- }
- }
- void yp_l()interrupt 1
- {
-
- TH0=(65535-10000)/256; //設(shè)置延時(shí)時(shí)間
- TL0=(65535-10000)%256;
- }
復(fù)制代碼
所有程序51hei提供下載:
OLED FFT.rar
(72.2 KB, 下載次數(shù): 152)
2019-6-23 13:41 上傳
點(diǎn)擊文件名下載附件
源碼
|
評(píng)分
-
查看全部評(píng)分
|