摘要
随着时代的进步,电子信息技术被广泛运用于生活的各方面,人们越来越重视视觉、听觉以及音质的享受。音乐信号频谱因其自身有众多优点,目前在很多领域得到广泛普及。
音乐频谱显示器可以直接观察待显示信号的输入状况,还可以给人以视觉上的享受,可以赋予音乐动态美。本次设计的电路可以分为三个部分:它们分别是滤波电路、音频输入电路、LED灯驱动电路。音乐信号通过音频输入电路输送到单片机,经过A/D采样的音频信号通过FFT运算之后获得某个时刻所需要的频率分量,驱动LED灯的显示。
通过本次音乐频谱的制作,提升了我们的焊接技术与绘图能力。同时,我们与同伴合作,共同完成作品,提升了我们的团队协作能力。更重要的是,我学到了很多相关知识,个人能力更是得到了锻炼,为日后的课程学习奠定了基础。
Abstract
Along with the progress of the era, theelectricity information technology dominated almost the whole of thedevelopment of the electronics industry, people pay more and more attention tothe enjoyment of visual, audio and sound quality. Audio signal spectrum displaybecause of its many advantages, has been widely used in many fields areinvolved in at the moment.
Music spectrum display not onlycan be observed directly with display signal input condition, and give people agood visual enjoyment on aesthetics, on the one hand the spectrum display givesthe dynamic beauty of music. The design of the circuit can be divided intothree parts: Respectively is an audio input circuit, filter circuit and LEDdriver circuit . Music signal after the A/D sampling of audio signal by audioinput circuit for sometime after FFT computation to the frequency of thecomponent, LED display driver.
Through the spectrum of music making, improve welding technology,drawing ability, atthe same time, we work with partners, finish the works together, improve theteam cooperation ability .More importantly, I learn a lot about it, Personalability is even more exercised, It lays the foundation for future courses.
二、单片机介绍
2.1 单片机介绍
本系统采用STC12C5A60S2系列单片机。
STC12C5A60S2系列单片机是宏晶科技生产的单时钟、机器周期(1T)的单片机。它是高速、低功耗、超强抗干扰的新一代8051单片机,指令代码完全兼容传统8051,但速度快8-12倍。内部集成MAX810专用复位电路,2路PWM,8路高速10位A/D转换(250K/S),针对电机控制,强干扰场合。
2.2 产品优势
在众多的51系列单片机中,要算国内STC公司的1T增强系列更具有竞争力,因他不但和8051指令、管脚完全兼容,而且其片内的具有大容量程序存储器且是FLASH工艺的,如STC12C5A60S2单片机内部就自带高达60K FLASHROM,这种工艺的存储器用户可以用电的方式瞬间擦除、改写。而且STC系列单片机支持串口程序烧写。显而易见,这种单片机对开发设备的要求很低,开发时间也大大缩短。写入单片机内的程序还可以进行加密,这又很好地保护了劳动成果。
3.1 系统电路设计
该系统从功能上可分为以下三个部分:
1. 音频数据采集电路实现模拟音频信号的采集,并将采集到的模拟信号转换为数字信号并将其量化处理,包括音频采集电路和AD转换电路。
2. 频谱显示电路实现模拟音频信号频谱的分段显示,它将音频信号频谱分为11段,每段按照11级量化,驱动LED显示。
3. 主控制器采用STC12C5A60S2单片机,在完成系统其他控制任务的条件下,充分利用单片机的剩余资源,采用优化FFT算法计算音频信号频谱,并将计算结果输入到频谱显示电路。
3.2音乐频谱性能
1. 由于音频信号的频率范围为300Hz-3400Hz或20Hz-20kHz,根据采样定理,为保证信息不失真,确定系统的采样频率为8kHz或96kHz。
2. 结合系统采用STC12C5A60S2单片机的处理速度以及信号采样频率的要求,采用STC12C5A60S2单片机作为系统的A/D转换模块。
3. 根据上述技术指标确定系统的外围接口方式
3.3主要原理
本系统的工作原理是由P0口接收电压信号的输入,音频信号通过音频线输送到STC12C5A60S2单片机中,对输入的音频信号进行AD转换,调用电路中的滤波和单片机中的FFT变换程序对音频数字信号进行分析,单片机将信号幅度量化,驱动led显示。
四、算法分析与设计
4.1核心算法FFT
在制作中使用FFT的方法为:首先,我们用ADC去采样一个模拟信号之后,使之变为数字信号。其次,将采样得到的数字信号,送入FFT进行变换处理。通常,若我们取N个采样点,经过FFT运算之后,就可以得到N个点的FFT结果。设Fs为ADC的采样频率,N为傅立叶变换的点数,则有最小分辨频率f=Fs/N,因此频谱显示的最低频率就是fHZ.
4 .2 单片机实现FFT
程序核心就是将采集的音频信号运用FFT算法处理读得的AD数据,同时经过FFT公式处理,然后取出频率的幅度值,将这些值量化为LED亮起的相应个数显示出来,这就是此算法的主要运用。
4.3 自动增益控制
为了避免声音过小不显示,声音过大全屏显示的问题,在程序中添加了一个自动增益程序,可以根据声音大小调整频谱显示幅度。
五、电路设计
5.1 滤波模块
电源采用+5V电压,在电源的正负极分别加上一个220uf的电容,使音频输出更加稳定。
5.2 单片机处理模块
STC12C5A60S2单片机进行了AD 转换,,以及FFT(快速傅立叶变换)对信号进行处理,让音频信号转化,处理,输出到显示模块。
5.3 音频输入模块
音频输入模块主要完成输入音频信号的采样并且将收集到的声音信号进行A/D转换,语音采样编解码及滤波处理。音频频谱值得计算采用快速傅立叶算法FFT,该模块的工作原理是: 音频信号通过音频线输送到STC12C5A60S2单片机中,对输入的音频信号进行AD转换,调用电路中的滤波和单片机中的FFT变换程序对音频数字信号进行分析。
4.4 LED音乐频谱显示模块
显示部分为5*11排列,5种颜色,各11颗,共计55颗LED彩灯,所有的灯都为并联,当音频接口有音乐输入并且供电模块正常时,可以模拟显示音乐播放器的音乐柱。
六、 系统调试与测试
6.1系统调试
1.检查电路设计的原理图,确定线路连接与原理图一致。
2.检查线路是否存在断路,用数字万用表打到合适的档位,测试各线路对应的按点是否通路。
3.检查器材是否完好,电源5v直流电源输出正常。发光二极管全都可以正常发光,电阻电容全部正常。当插上音频插口,播放音乐时,LED灯可以随音乐正常跳动。
电路连接后,试验现象均正常,调试成功。
6.2系统测试
连接USB口,连接音频接口,播放音乐,效果如图:
6.3在调试与测试中遇到的问题
由于第一次调试时,电路中未添加滤波模块,导致LED灯无法亮起。后在正负极分别添加一个220uf的电容后,LED灯可随音乐正常跳动。
附:主程序
#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 6
#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[21];
ucharkeep,keepnum,anum,timernum,timernum2,lednum3,Ltime;//用于分离
/*加入数组用于显示相应led灯数目*/
ucharlednum[]={0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff};//0-7的显示数组 P2组控制
int xdata FftReal[SAMPLE_NUM];
int xdata FftImage[SAMPLE_NUM];
sbit p30=P3^0;//定义p3_0为p3口的第一位
sbit p31=P3^1;
sbit p32=P3^2;
sbit p33=P3^3;
sbit p34=P3^4;
sbit p35=P3^5;//9-11的led控制
sbit p36=P3^6;
sbit p37=P3^7;
void timerinit()//定时器 初始化函数
{
TMOD=0x01;//设置定时器0为工作方式1
TH0=(65536-6000)/256; //装初值11.0592M晶振定时50ms数为6000
TL0=(65536-6000)%256;
EA=1; //开总中断
ET0=1;//开定时器0中断
TR0=1; //启动定时器0
}
void disp()
{
timernum++;
if(timernum==6)timernum=1;
P2=0;//显示前先关闭
P3=P3&0x1f;
switch(timernum)
{
case1:anum=a[0];p34=0;p33=1;p32=1;p31=1;p30=1;break;
case2:anum=a[1];p34=1;p33=0;p32=1;p31=1;p30=1;break;
case3:anum=a[2];p34=1;p33=1;p32=0;p31=1;p30=1;break;
case4:anum=a[3];p34=1;p33=1;p32=1;p31=0;p30=1;break;
case5:anum=a[4];p34=1;p33=1;p32=1;p31=1;p30=0;break;
}
//anum=a[10];/*修改可以改变光柱高度 (anum值分开几个部分用定时器区分显示)(a[]内逐加) */
if(anum<=8){P2=lednum[anum];P3=P3&0xff;}//屏蔽高三位 1f
//else{P2=0xff;P3=lednum2[anum-9];}
if(anum==9){P2=0xff;p35=1;p36=0;p37=0;}
if(anum==10){P2=0xff;p35=1;p36=1;p37=0;}
if(anum==11){P2=0xff;p35=1;p36=1;p37=1;}
}
uchar STC_ADC() //!!根据数据手册写一个ad读取函数
{
uchar i;
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = BIN(10001000);
i=3;
while(i--);
while (1)
{
if (ADC_CONTR & BIN(10000))
{
break;
}
}
ADC_CONTR = BIN(10000000);
return( ADC_RESL<<2) ;
}
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
{
FftReal[BRTable
]= STC_ADC()< FftImage = 0;
}
keepnum=FftReal[2]/32;//提取等级数
if((7
elseif((4
elseif((2
else {keep=5;}
for( i=1; i<=NUM_2_LOG; i++)
{
bb=1;
bb <<= (i-1);
for( j=0; j<=bb-1; j++)
{
p=1;
p <<= (NUM_2_LOG-i);
p = p*j;
for( k=j; k
{
TR = FftReal[k]; TI =FftImage[k]; temp = FftReal[k+bb];
FftReal[k] = FftReal[k] +((FftReal[k+bb]*cos_tabb[p])>>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<5; i++)//5
{
ulReal = FftReal[i+1];
ulReal *= ulReal;
ulImage = FftImage[i+1];
ulImage *= ulImage;
a = sqrt_16( ulReal + ulImage ); //修改
if( a < FFT_OUT_MIN )
a = 0;//修改
else
a = a-FFT_OUT_MIN;
if( a >max)
max =a;
//disp();
}
if(max>11) //11
{
max/=11;
for( i=0; i<5; i++) //输出a的5个分离数值
{
a/=max;
}
}
}
void main()
{
P2M0=0xff;// BIN(11111111);//P2组设置为推挽输出
P2M1=0;
P3M0=0xe0;// BIN(11111111);
P3M1=0;
P1M0=0x00;
P1M1=0x01;
P1ASF =1; //设置P1.0为AD口
AUXR1 =BIN(100);
keep=0;
keepnum=0;
timerinit();//定时器初始化
timernum=3;//从3开始
timernum2=0;
while(1)
{
FFT();
}
}
void timer0() interrupt 1
{
TH0=(65536-6000)/256; //6000
TL0=(65536-6000)%256;
disp();
}