如何用51单片机实现音频信号的频谱显示(在LCD上显示)

用51很难做FFT。您可以使用带有增强型RAM的51机器进行参考程序:# include

#定义uchar无符号字符

#定义uint无符号整数

#定义通道0x01 //将AD通道设置为P1.1。

//-sbit sda_r=p1^2;

sbit sda_r_top=p1^3;

sbit sda_g=p1^4;

sbit sda_g_top=p1^5;

sbit stcp=p1^6;

sbit shcp=p1^7;

// -

// -

//sin整数表放大128倍(128)

code char SIN_TAB[128] = { 0,6,12,18,24,30,36,42,48,54,59,65,70,75,80,85,89,94,98,102,105,165438 -70, -75, -80, -85, -89, -94, -98, -102, -105, -108, -112, -114, -117, -119, -121, -123, -124, -125, -126, -126, -126, -126, -126, -125, -124, -123, -121, -119, -117, -114, -112, -108, -105, -102, -98, -94, -89, -85, -80, -75, -70, -65, -59, -54, -48, -42, -36, -30, -24, -18, -12, -6 }; //cos整数表放大128倍(128)

code char COS _ TAB[128]= { 127,126,126,125,124,123,121,119,117 -105, -102, -98, -94, -89, -85, -80, -75, -70, -65, -59, -54, -48, -42, -36, -30, -24, -18, -12, -6, 0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 59, 65, 70, 75, 80, 85, 89, 94, 98, 102, 105, 108, 112, 114, 117, 119, 121, 123, 124, 125, 126, 126 }; //样本存储序列表

code char LIST_TAB[128] = { 0,64,32,96,16,80,48,112,

8, 72, 40, 104, 24, 88, 56, 120,

4, 68, 36, 100, 20, 84, 52, 116,

12, 76, 44, 108, 28, 92, 60, 124,

2, 66, 34, 98, 18, 82, 50, 114,

10, 74, 42, 106, 26, 90, 58, 122,

6, 70, 38, 102, 22, 86, 54, 118,

14, 78, 46, 110, 30, 94, 62, 126,

1, 65, 33, 97, 17, 81, 49, 113,

9, 73, 41, 105, 25, 89, 57, 121,

5, 69, 37, 101, 21, 85, 53, 117,

13, 77, 45, 109, 29, 93, 61, 125,

3, 67, 35, 99, 19, 83, 51, 115,

11, 75, 43, 107, 27, 91, 59, 123,

7, 71, 39, 103, 23, 87, 55, 119,

15, 79, 47, 111, 31, 95, 63, 127

};

uchar COUNT=0,COUNT1=0,ADC_Count=0,LINE=15,G,T;

uchar i,j,k,b,p;

int Temp_Real,Temp_Imag,Temp;//中间临时变量

uint temp 1;

int xdata Fft _ Real[128];

int xdata Fft _ Image[128];FFT的虚部

uchar xdata LED _ tab 2[64];//记录漂浮物需要暂停吗?

uchar xdata LED _ TAB[64];//记录红色列

uchar xdata LED _ tab 1[64];//记录浮点

无效延迟

{

while(a-);

}void FFT()

{//uchar X;

for(I = 1;我& lt=7;i++) /* for(1) */

{

b = 1;

b & lt& lt=(I-1);//Dish操作,用来计算行数。例如,计算第一个极点1和2行,第二个阶段。

for(j = 0;j & lt= b-1;j++) /* for (2) */

{

p = 1;

p & lt& lt=(7-I);

p = p * j;

for(k = j;k & lt128;K=k+2*b) /*对于(3)基二fft */

{

temp _ Real = Fft _ Real[k];temp _ Imag = Fft _ Image[k];temp = Fft _ Real[k+b];

Fft _ Real[k]= Fft _ Real[k]+((Fft _ Real[k+b]* COS _ TAB[p])& gt;& gt7)+((Fft _ Image[k+b]* SIN _ TAB[p])& gt;& gt7);

Fft _ Image[k]= Fft _ Image[k]-((Fft _ Real[k+b]* SIN _ TAB[p])& gt;& gt7)+((Fft _ Image[k+b]* COS _ TAB[p])& gt;& gt7);

Fft _ Real[k+b]= Temp _ Real-((Fft _ Real[k+b]* COS _ TAB[p])& gt;& gt7)-((Fft _ Image[k+b]* SIN _ TAB[p])& gt;& gt7);

FFT _ Image[k+b]= Temp _ Imag+((Temp * SIN _ TAB[p])& gt;& gt7)-((Fft _ Image[k+b]* COS _ TAB[p])& gt;& gt7);

//Shift。防止溢出。结果已经是这个值的1/64。

FFT _ Real[k]& gt;& gt= 1;

FFT _ Image[k]& gt;& gt= 1;

FFT _ Real[k+b]& gt;& gt= 1;

FFT _ Image[k+b]& gt;& gt= 1;

}

}

}

//X =((((Fft _ Real[1]* Fft _ Real[1])+((Fft _ Image[1]* Fft _ Image[1]))& gt;& gt7);

Fft _ Real[0]= Fft _ Image[0]= 0;//删除DC组件

//Fft _ Real[63]= Fft _ Image[63]= 0;

for(j = 0;j & lt64;j++)

{

temp 1 =((((Fft _ Real[j]* Fft _ Real[j])+((Fft _ Image[j]* Fft _ Image[j])))& gt;& gt1);//找到力量

if(temp 1 & gt;1)temp 1-;

else temp 1 = 0;

if(temp 1 & gt;31)temp 1 = 31;

if(temp 1 & gt;(LED _ TAB[j]))LED _ TAB[j]= temp 1;

if(temp 1 & gt;(LED_TAB1[j])

{ LED _ tab 1[j]= temp 1;

LED _ tab 2[j]= 18;//提顿速度=12

}

}

}void Init()

{

// -

p 1 ASF = 0x 02;//0000,0010,设置P1.1为模拟端口。

auxr 1 & amp;= 0xFB//1111,1011,使得ADRJ=0。

EADC = 1;//AD中断打开

ADC _ CONTR = ADC _ POWER | ADC _ SPEEDHH | ADC _ START | channel;

//11101011打开A/D (ADC_POWER)转换电源;11速度是每70个周期一次;

//0中断标志被清除;1启动ADC(ADC _ START);001AD通道打开(这里是p 1.1);

// -

p2m 0 = 1;

p0m 0 = 1;

TMOD = 0x 12;

TH0 = 0x30//采样率在20K左右(需要40K以上才能完成频段。但是音频大多在10k以下,所以我选择20K采样,比较好看)。

TL0 = 0x30

th 1 = 0x ee;

TL 1 = 0xc 0;

ET0 = 1;//定时器0开启。

TR0 = 0;//关闭计时器

et 1 = 1;

tr 1 = 1;

pt 1 = 0;

PT0 = 1;

IPH =帕奇;

IP = PADC;//中断优先级

EA = 1;//总中断打开

}

无效ADC_Finish()中断5

ADC _ CONTR & amp= !ADC _ FLAG

FFT _ Real[LIST _ TAB[ADC _ Count]]=(int)((ADC _ RES)& lt;& lt1)+(ADC _ RESL & gt;& gt1)-256;//-512;//根据LIST_TAB表中的顺序,存储采样值,

//ADC _ CONTR = ADC _ POWER | ADC _ speed hh | ADC _ START | channel;//为了采集负电压,采用偏置采集。电压增加到1/2 vcc,所以减去256。

if(ADC _ Count & lt;= 127)ADC _ count++;

else { EADC = 0;TR0 = 0;}

} Voided _ display()中断3//一次中断一行。。。

{

th 1 = 0x F3;

TL 1 = 0x 00;

for(G = 0;G & lt64;G++) //将一行数据填入点阵屏。

{

if(LED _ TAB[G]& lt;= LINE+16)SDA _ R _ TOP = 1;

else SDA _ R _ TOP = 0;

if(LED _ TAB[G]& lt;= LINE)SDA _ R = 1;

否则SDA _ R = 0;if(LED _ tab 1[G]= = LINE){ SDA _ G _ TOP = 1;SDA _ G = 0;}

else if(LED _ tab 1[G]= =(LINE+16)){ SDA _ G _ TOP = 0;SDA _ G = 1;}

else SDA _ G = SDA _ G _ TOP = 1;

SHCP = 1;SHCP = 0;

}

STCP = 1;STCP = 0;

P2=15线;

if(LINE & gt;0)行-;

else LINE = 15;

//////////////////////////

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;//柱状减少,

count++;

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;

count++;

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;

count++;

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;

count++;

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;//柱状减少,

count++;

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;

count++;

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;

count++;

if(LED _ TAB[COUNT]& gt;0)LED _ TAB[COUNT]-;

count++;

if(COUNT & gt;=64)计数= 0;//浮动对象减少。

if(led _ tab 2[count 1]= = 0)//判断是否需要暂停。

{

if(LED _ tab 1[count 1]>;LED _ TAB[count 1])LED _ TAB 1[count 1]-;//如果比列大,就减少(保持列上面的浮动对象)

}

else LED _ tab 2[count 1]-;

count 1++;

if(LED_TAB2[COUNT1]==0)

{

if(LED _ tab 1[count 1]>;LED _ TAB[count 1])LED _ TAB 1[count 1]-;

}

else LED _ tab 2[count 1]-;

count 1++;

if(led _ tab 2[count 1]= = 0)//判断是否需要暂停。

{

if(LED _ tab 1[count 1]>;LED _ TAB[count 1])LED _ TAB 1[count 1]-;//如果比列大,就减少(保持列上面的浮动对象)

}

else LED _ tab 2[count 1]-;

count 1++;

if(LED_TAB2[COUNT1]==0)

{

if(LED _ tab 1[count 1]>;LED _ TAB[count 1])LED _ TAB 1[count 1]-;

}

else LED _ tab 2[count 1]-;

count 1++;

if(count 1 & gt;= 64)count 1 = 0;

} void ad _ control()中断1//控制采样率。

{

ADC _ CONTR = ADC _ POWER | ADC _ speed hh | ADC _ START | channel;//开始广告采集

}

//==============================================================================================================

//* * * * * * * * * * * * * * * * * * main()* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *。

//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = void main()

{

init();

while(1)

{

ADC _ Count = 0;

TR0 = 1;

EADC = 1;//启动定时器中断0,并启动ADC。

while(ADC _ Count & lt;128);

FFT();

//FFT运算。并将其转换成功率值。。。

//tr 1 = 1;

}

}