如何用51单片机实现音频信号的频谱显示(在LCD上显示)
#定义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;
}
}