看到很多朋友做了音樂(lè )頻譜,感覺(jué)很炫,于是也模仿著(zhù)做了一個(gè)。在制作過(guò)程中,從網(wǎng)上查了很多資料,得到很多幫助。我要非常感謝那些辛勤付出的網(wǎng)友們,是你們無(wú)私的付出讓我們可以站在更高的起點(diǎn)奔跑。詩(shī)經(jīng)有云:投我以木桃,報之以瓊瑤。如果一味的索取,泉源也會(huì )枯竭。故將我制作的所有資料傳上來(lái),以作為對那些幫助過(guò)我的網(wǎng)友的答謝,也希望看到此貼的人能將此一做法傳承下去, 為論壇貢獻自己的一份力量。
效果圖:
視頻:
這個(gè)作品的制作可以分為三個(gè)過(guò)程:1、焊接LED點(diǎn)陣;2、設計控制電路;3、編程
所謂音樂(lè )頻譜就是將音樂(lè )的各個(gè)頻率分量顯示出來(lái),LED點(diǎn)陣的水平軸代表各個(gè)頻率,豎直軸代表強度。從下面的圖中可以看出,該點(diǎn)陣大小為16*30(本來(lái)要做16*32,限于萬(wàn)用板大小只能容下30列)。每?jì)闪袨橐唤M,共15組,由于是陰極接在一起,姑且稱(chēng)之為共陰極組;同理,每一行的陽(yáng)極接在一起,稱(chēng)為共陽(yáng)極組,共16組。
點(diǎn)陣接線(xiàn)圖:
正面:
(圍成圓圈的燈是七彩快閃LED,只要接上電源,其顏色自動(dòng)變換。)
背面:
從圖中可以看到,所有的陰極線(xiàn)(15根)、陽(yáng)極線(xiàn)(16根) 都用排針引出來(lái),再用杜邦線(xiàn)就可以和控制板相連。
控制電路圖:
單片機用的是ATMEGA324PA(內部晶振,8MHZ),只用到通用IO功能,移植到其他單片機上也很方便?;究刂扑悸罚簰呙?。每一時(shí)刻只讓一個(gè)共陰極組接地,其它接高電平,從左至右依次選通每個(gè)共陰極組。每次選中共陰極組后,需要對其陽(yáng)極寫(xiě)入數據,由于有16行,需要寫(xiě)入兩個(gè)字節。假如以上方為高字節,我想讓選中的共陰極組下面的9行燈亮,則應往陽(yáng)極段寫(xiě)入的兩個(gè)字節為:0x01,0xff??刂齐娐凡捎昧?個(gè)鎖存器74HC573,2個(gè)ULN2803(八路達林頓管,其實(shí)是一個(gè)8路反向器,可以承受大電流 ) 。左邊兩個(gè)573用來(lái)對陽(yáng)極寫(xiě)入數據,右邊兩個(gè)573和2803接在一起,用來(lái)選通共陰極組。4個(gè)573的數據輸入端都連到一起,接在單片機的PB口。573還有一個(gè)選通端LE,當其為高電平時(shí),可以對其寫(xiě)入數據,低電平時(shí)輸出鎖存。將其作為片選(SS0,SS1,SS2,SS3)依次接單片機PA0,PA1,PA2,PA3。每次只讓一個(gè)片選為1,就可以對每個(gè)573分開(kāi)寫(xiě)入數據了。
最后說(shuō)說(shuō)編程。用了一個(gè)聲音模塊采集聲音,聲音模塊 原理為:麥克接收聲音,OUT端輸出聲音信號波形。OUT端接在單片機的PA7(AD轉換端口)上。程序的循環(huán)中,先進(jìn)行32次AD采樣,得到32(必須是2的n次方)個(gè)采樣值,做快速傅里葉變換,得到32個(gè)頻率的強度,由于是前后對稱(chēng)的,只取其前15個(gè)頻率的強度,經(jīng)過(guò)幅值調整(調為0~16),在15個(gè)共陰極組上依次顯示出來(lái)。
上程序:
1、 主函數(AD轉換,FFT變換) #define F_CPU 8 //可定義為你所用的晶振頻率(單位Mhz) #include #include 'delay.h' #include 'data.h' #include 'display.h' #define DATA PORTB #define SS0 PORTA_Bit0 #define SS1 PORTA_Bit1 #define SS2 PORTA_Bit2 #define SS3 PORTA_Bit3 #define pi 3.141592654 #include //定義復數結構 struct compx { float real; float imag; }; //定義復數乘法 struct compx EE(struct compx a,struct compx b) { struct compx c; c.real=a.real*b.real-a.imag*b.imag; c.imag=a.real*b.imag+a.imag*b.real; return(c); } //定義復數求模 float cmplxabs(struct compx a) { float b; b=sqrt(a.real*a.real+a.imag*a.imag); return(b); } //FFT子程序 //入口:復數數組指針和點(diǎn)數。 //出口:原復數數組,取模后為強度,可用于頻譜。 void FFT(struct compx *xin,unsigned int N) { int f,m,nv2,nm1,i,k,j=1,l; int le,lei,ip; struct compx v,w,t; nv2=N/2; f=N; for(m=1;(f=f/2)!=1;m++); nm1=N-1; for(i=1;i<> { if(i<> { t=xin[j-1]; xin[j-1]=xin[i-1]; xin[i-1]=t; } k=nv2; while(k j=j+k; } /* FFT*/ for(l=1;l<> { le=(int)pow(2.0,l); lei=le/2; v.real=1.0;v.imag=0.0; w.real=cos(pi/lei);w.imag=-sin(pi/lei); for(j=1;j<> { for(i=j;i<> { ip=i+lei; t=EE(xin[ip-1],v); xin[ip-1].real=xin[i-1].real-t.real; xin[ip-1].imag=xin[i-1].imag-t.imag; xin[i-1].real=xin[i-1].real+t.real; xin[i-1].imag=xin[i-1].imag+t.imag; } v=EE(v,w); } } } void ADC_Init() { ADCSRA=0xE3;//ADC使能,開(kāi)始轉換,自動(dòng)觸發(fā)轉換,中斷bit3,8分頻 ADCSRB=0x00;//自由轉換模式 ADMUX=0x47;//基準電壓Internal 1.1V Voltage,通道0 4n通道n } char s[15][2]={0}; void start() { flash2(1); flash4(1); flash5(5); } void end() { scroll(67,word,1); flash2(1); while(1)xiaolian(5); } char counter=0; #pragma vector=TIMER1_OVF_vect __interrupt void TIMER1_OVF_ISR() { TCNT1=0;//8.4s counter++; if(counter==28) end(); } void TIMER1_INIT()//TIMER1 16位定時(shí)器 { TCNT1=0; TIMSK1=0x01;//T1溢出中斷使能 SREG=0x80;//總中斷使能 TCCR1A=0x00; TCCR1B=0x05;//1024分頻,開(kāi)始計數 } struct compx ss[32]; char w=0,bar[15]={0}; unsigned int t,tL,tH; void main() { PORTA=0x00; DDRA=0x0f; PORTB=0x00; DDRB=0xFF; ADC_Init(); start(); TIMER1_INIT(); while(1) { tL=ADCL; tH=ADCH<> t=tH+tL; ss[w].real=(float)t;//采樣結果送實(shí)部,注意數據類(lèi)型轉換 ss[w].imag=0; w++; for(char i=1;i<> if(w==32) { w=0; clear(); FFT(ss,32); unsigned int sum; for(char i=1;i<> sum/=15;//平均值 for(char i=0;i<> { char temp=(char)(cmplxabs(ss[i+1])/250); if(temp>16)temp=16; if(bar>temp) bar-=1; else { bar=temp; } } } } } 2、 底層驅動(dòng)函數、動(dòng)畫(huà)顯示函數、刷新函數 #define F_CPU 8 //可定義為你所用的晶振頻率(單位Mhz)#include #include 'delay.h' #include 'data.h' #define DATA PORTD #define SS0 PORTA_Bit0 #define SS1 PORTA_Bit1 #define SS2 PORTA_Bit2 #define SS3 PORTA_Bit3 void clear() { PORTA&=0XF0; PORTD=0X00; PORTA|=0X03;//SS0,SS1 PORTA&=0XF0; } void clear_all()//全部清除 { for(char i=0;i<> { s[0]=0; s[1]=0; } } void refresh(char *p)//刷新頻譜 { char k=0,tempU,tempD; k=0; PORTA&=0XF0; PORTD=0X00; PORTA|=0X02;//SS1 for(char i=0;i<> { tempU=0;tempD=0; if(p[k]>8) { for(char j=0;j<><> tempD=0xff; } else { tempU=0; for(char j=0;j<><> } PORTA&=0XF0; PORTD=0X00; PORTA|=0X0c;//SS2,SS3 PORTA&=0XF0; PORTD=(1<> PORTA|=0X01;//SS0 PORTA&=0XF0; PORTD=tempD; PORTA|=0X04;//SS2 下8行 PORTA&=0XF0; PORTD=tempU; PORTA|=0X08;//SS3 上8行 //delay_ms(500); k++; } delay_us(30); PORTA&=0XF0; PORTD=0X00; PORTA|=0X0c;//SS2,SS3 PORTA&=0XF0; PORTD=0X00; PORTA|=0X01;//SS0 for(char i=0;i<> { tempU=0;tempD=0; if(p[k]>8) { for(char j=0;j<><> tempD=0xff; } else { tempU=0; for(char j=0;j<><> } PORTA&=0XF0; PORTD=0X00; PORTA|=0X0c;//SS2,SS3 PORTA&=0XF0; PORTD=(1<> PORTA|=0X02;//SS1 PORTA&=0XF0; PORTD=tempD; PORTA|=0X04;//SS2 下8行 delay_us(10); PORTA&=0XF0; PORTD=tempU; PORTA|=0X08;//SS3 上8行 k++; } delay_us(30); } } void show(char p[15][2])//顯示圖片 { char k=0; k=0; PORTA&=0XF0; PORTD=0X00; PORTA|=0X02;//SS1 for(char i=0;i<> { PORTA&=0XF0; PORTD=0X00; PORTA|=0X0c;//SS2,SS3 PORTA&=0XF0; PORTD=(1<> PORTA|=0X01;//SS0 PORTA&=0XF0; PORTD=p[k][0]; PORTA|=0X08;//SS3 上8行 PORTA&=0XF0; PORTD=p[k][1]; PORTA|=0X04;//SS2 下8行 k++; } PORTA&=0XF0; PORTD=0X00; PORTA|=0X0c;//SS2,SS3 PORTA&=0XF0; PORTD=0X00; PORTA|=0X01;//SS0 for(char i=0;i<> { PORTA&=0XF0; PORTD=0X00; PORTA|=0X0c;//SS2,SS3 PORTA&=0XF0; PORTD=(1<> PORTA|=0X02;//SS1 PORTA&=0XF0; PORTD=p[k][0]; PORTA|=0X08;//SS3 上8行 PORTA&=0XF0; PORTD=p[k][1]; PORTA|=0X04;//SS2 下8行 k++; } } } void clear_dot(char x,char y)//x:0~14 y:0~15清除點(diǎn) { if(y>=8) { s[x][0]&=~(1<> } else { s[x][1]&=~(1<> } } void set_dot(char x,char y)//x:0~14 y:0~15顯示點(diǎn) { if(y>=8) { s[x][0]|=1<> } else { s[x][1]|=1<> } } void set_dot(char x,char y,char q[15][2])//x:0~14 y:0~15 { if(y>=8) { q[x][0]|=1<> } else { q[x][1]|=1<> } } void rise(char p[15][2],char n)//n:1~15 圖像上移n行 { unsigned int temp; char q[15][2]={0}; for(char j=0;j<> { temp=(int)p[j][0]*256+p[j][1]; temp<> q[j][0]=temp/256; q[j][1]=temp%256; } for(long i=0;i<> clear(); } void flash1(int t)//列右移 { for(int v=0;v<> { clear_all(); s[0][0]=0xff; s[0][1]=0xff; for(char j=0;j<> { s[(j+1)%15][0]=s[j][0]; s[(j+1)%15][1]=s[j][1]; s[j][0]=0x00; s[j][1]=0x00; for(long i=0;i<> } } } void flash2(long t)//縮小的圈 { signed char x=0,y=15; for(int v=0;v<> { clear_all(); x=0;y=15; for(char i=0;i<> { while(x<> { set_dot(x,y); x++; for(int i=0;i<> } x--; while(y>=i) { set_dot(x,y); y--; for(int i=0;i<> } y++; while(x>=i) { set_dot(x,y); x--; for(int i=0;i<> } x++; while(y<> { set_dot(x,y); y++; for(int i=0;i<> } y--; } } } void xiaolian(int t)//笑臉 { for(int v=0;v<> { for(long i=0;i<> for(long i=0;i<> } //for(long i=0;i<> } void flash3(long t)//“RUN”垂直落下 { for(int v=0;v<> { for(signed char i=15;i>=0;i--)rise(run,i); for(long i=0;i<> } } void flash4(long t)//“RUN”筆畫(huà)書(shū)寫(xiě) { int dd=200; for(int v=0;v<> { clear_all(); for(signed char i=15;i>=1;i--) { set_dot(0,i); for(int i=0;i<> } for(signed char i=1;i<> { set_dot(i,15); for(int i=0;i<> } for(signed char i=14;i>=9;i--) { set_dot(3,i); for(int i=0;i<> } for(signed char i=3;i>=1;i--) { set_dot(i,9); for(int i=0;i<> } for(signed char i=8;i>=7;i--) { set_dot(1,i); for(int i=0;i<> } for(signed char i=7;i>=5;i--) { set_dot(2,i); for(int i=0;i<> } for(signed char i=5;i>=1;i--) { set_dot(3,i); for(int i=0;i<> } for(int i=0;i<> for(signed char i=15;i>=2;i--) { set_dot(5,i); for(int i=0;i<> } for(signed char i=6;i<> { set_dot(i,1);set_dot(i,2); for(int i=0;i<> } for(signed char i=2;i<> { set_dot(8,i); for(int i=0;i<> } for(int i=0;i<> for(signed char i=15;i>=1;i--) { set_dot(10,i); for(int i=0;i<> } for(signed char i=13;i>=11;i--) { set_dot(11,i); for(int i=0;i<> } for(signed char i=10;i>=7;i--) { set_dot(12,i); for(int i=0;i<> } for(signed char i=6;i>=3;i--) { set_dot(13,i); for(int i=0;i<> } for(signed char i=1;i<> { set_dot(14,i); for(int i=0;i<> } for(int i=0;i<> } } void scroll(char l,char p[][2],char t)//滾屏 { for(char j=0;j<> { for(int i=0;i<> p+=2; } } void flash5(long t)//“RUN”閃爍 { for(int v=0;v<> { for(int i=0;i<> clear(); delay_ms(50); } } 3、 存放需要顯示的漢字字模 char word[][2]= { 0x08,0x08,0x0b,0x30,0x08,0xc2, 0xff,0xff,0x08,0xc0,0x2b,0x30, 0x18,0x08, 0x00,0x00, 0x02,0x03,0xfa,0x7c, 0xaa,0x0c,0xab,0xfe,0xaa,0x63, 0xfa,0x63,0x02,0x01,0x00,0x01,//求是 0x00,0x00, 0x04,0x00,0x1b,0xff,0xe4,0x03, 0x33,0xc3,0x08,0x07,0x0f,0xf8, 0x00,0x02,0xff,0xff, 0x00,0x00, 0x32,0x48,0x2a,0x52,0xe7,0xff, 0x2a,0x50,0x32,0x48,0x0f,0xff, 0x12,0x00,0x23,0xff,0x42,0x00,//創(chuàng )新 0x00,0x00,0x00,0x00,0x00,0x00, 0x21,0x04,0xff,0xff,0x00,0x04, 0x3f,0xfa,0x65,0x12,0xa5,0x11, 0x3d,0xf1, 0x00,0x00, 0x00,0x01,0x08,0x08, 0x0b,0x30,0x08,0xc2,0xff,0xff, 0x08,0xc0,0x2b,0x30,0x18,0x08,//追求 0x00,0x00, 0x00,0x08,0x0f,0xc8,0x09,0x48, 0xf9,0x7f,0x49,0x48,0x4f,0xc8, 0x00,0x00, 0x02,0x0c,0x12,0x38,0xff,0xfc, 0x12,0x44,0x02,0x04,0x1f,0xfa, 0x10,0x92,0xff,0xe2,0x52,0x19,//卓越 0x00,0x00,0x00,0x00,0x00,0x00, 0x24,0x10,0x24,0x22,0x7f,0xff, 0x84,0x88,0x7f,0xf0,0x24,0x3e, 0x14,0xc3, 0x00,0x00, 0x08,0x00,0x3f,0xff, 0xc0,0x00,0x17,0xff,0x28,0x00, 0x20,0x00,0x20,0x02,0x3f,0xff,//我們 0x00,0x00, 0x02,0x03,0xfa,0x7c, 0xaa,0x0c,0xab,0xfe,0xaa,0x63, 0xfa,0x63,0x02,0x01,0x00,0x01,//是 0x00,0x00, 0xff,0xfe,0x83,0x80,0x82,0xe0, 0xfe,0x3e,0x00,0x00,0xff,0xfc, 0x00,0x06,0x00,0x06,0xff,0xfc, 0x00,0x00,0xff,0xfe,0x38,0x00, 0x07,0x80,0x00,0x78,0xff,0xfe,//RUN 0x00,0x00,0x00,0x00, 0x7f,0xfe,0x44,0x12,0x44,0x62, 0x44,0x8a,0x7f,0xfe,0x44,0x02, 0x7f,0xfe,0x00,0x00,0x7f,0xfe, 0x44,0x82,0x7b,0x0c,0x00,0x30, 0x7f,0xc0,0x00,0x30,0x00,0x0e,//團隊 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00, }; 4、頭文件 (1) #ifndef __IAR_DELAY_H#define __IAR_DELAY_H #include #define delay_us(x) __delay_cycles ((unsigned long)(x * F_CPU)) #define delay_ms(x) __delay_cycles ((unsigned long)(x * F_CPU*1000UL)) #define delay_s(x) __delay_cycles ((unsigned long)(x * F_CPU*1000000UL)) #endif (2) #ifndef __IAR_DATA_H #define __IAR_DATA_H extern char s[15][2]; extern char run[15][2]; extern char tuandui[15][2]; extern char chuanxin1[15][2]; extern char chuanxin2[18][2]; extern char qiushi[15][2]; extern char women[15][2]; extern char zhuiqiu[15][2]; extern char zhuoyue[15][2]; extern char xiaolian1[15][2]; extern char xiaolian2[15][2]; extern char word[][2]; #endif (3) #ifndef __IAR_DISSPLAY_H #define __IAR_DISPLAY_H extern void refresh(char *p); extern void clear_all(); extern void clear(); extern void show(char p[15][2]); extern void refresh1(char *p); extern void clear_dot(char x,char y,char q[15][2]);//x:0~14 y:0~15 extern void set_dot(char x,char y,char q[15][2]);//x:0~14 y:0~15 extern void clear_dot(char x,char y);//x:0~14 y:0~15 extern void set_dot(char x,char y);//x:0~14 y:0~15 extern void rise(char p[15][2],char n);//n:1~15 extern void flash1(int t); extern void flash2(long t); extern void xiaolian(int t); extern void flash3(long t); extern void flash4(long t); extern void scroll(char l,char p[][2],char t); extern void flash5(long t); #endif
聯(lián)系客服