音乐播放器:
实际运行效果:
51单片机Proteus仿真音乐播放器
音乐播放器原理图
音乐播放器代码链接:https://pan.baidu.com/s/1Yrjb2BtYoAcUZDdtUpbyMw
提取码:vhth
代码:
#include #include typedef unsigned char uchar; typedef unsigned int uint; sbit K1 = P3^2; sbit Beep = P3^7; uchar i; uchar song_Index,Tone_Index=0; uchar * song_Tone, *song_Time; const LED_tab[] = { 0xC0,0xF9,0xA4,0xB0,0x99,0x92, 0x82,0xF8,0x80,0x90,0x88,0x83, 0xC6,0xA1,0x86,0x81,0xBF,0xFF }; const Tone_tab[] = { 62018,62401,62491,62895,63184,63441,63506, 63773,63965,64137,64215,64360,64488,64603, 64654,64751,64836,64876,64948,65012,65067,65535}; /* 《送别》 */ uchar code song1_Tone[] = { 11,9,11,14,12,14,12,11,11,7,8,9,8,7,8, 11,9,11,14,13,12,14,11,11,7,8,9,6,7, 12,14,14,13,12,13,14,12,13,14,12,12,11,10,7,8, 11,9,11,14,13,12,14,11,11,8,9,10,6,7,0xff}; uchar code song1_Time[] = { 4,2,2,8,4,2,2,8,4,2,2,4,2,2,12, 4,2,2,4,2,4,4,8,4,2,2,4,2,12, 4,4,8,4,2,2,8,2,2,2,2,2,2,2,2,16, 4,2,2,4,2,4,4,8,4,2,2,4,2,12,0xff}; /* 《两只老虎》 */ uchar code song2_Tone[] = { 7,8,9,7,7,8,9,7,9,10,11,9,10,11, 11,12,11,10,9,7,11,12,11,10,9,7,7,4,7,7,4,7,0xff}; uchar code song2_Time[] = { 4,4,4,4,4,4,4,4,4,4,8,4,4,8, 2,2,2,2,2,2,2,2,2,2,4,4,4,4,8,4,4,8,0xff}; /* 《哈巴狗》 */ uchar code song3_Tone[] = { 7,7,7,8,9,9,9,9,10,11,12,12,11,10,9,11,11,8,9,7, 7,7,7,8,11,9,9,9,10,11,12,12,11,10,9,11,8,9,7,0xff}; uchar code song3_Time[] = { 2,2,2,2,4,2,2,2,2,4,2,2,2,2,4,2,2,2,2,4, 2,2,2,2,4,2,2,2,2,4,2,2,2,2,4,2,2,2,2,4,0xff}; /* 《兰花草》 */ uchar code song4_Tone[] = { 5,9,9,9,9,8,7,8,7,6,5,12,12,12,12,12,11, 2,11,11,10,9,9,12,12,11,9,8,7,8,7,6,5,9, 2,7,7,6,5,9,8,7,6,4,6,0xff}; uchar code song4_Time[] = { 2,2,2,2,2,2,2,2,2,2,8,2,2,2,2,4,2, 2,2,2,8,2,2,2,2,4,2,2,2,2,2,4,2, 2,2,2,2,4,2,2,2,2,2,8,0xff}; /* 《不倒翁》 */ uchar code song5_Tone[] = { 11,12,11,9,8,9,11,9,8,7,9,11,7,9,8, 11,12,11,9,8,9,11,9,8,7,8,7,8,9,7,0xff}; uchar code song5_Time[] = { 4,4,8,4,4,8,4,4,4,4,2,2,2,2,8, 4,4,8,4,4,8,4,4,4,4,2,2,2,2,8,0xff}; void delayms( uint ms ) { uchar a; while (ms--) { for (a=230; a>0; a--); } } void int0() interrupt 0 { delayms(100); if (INT0==0) { TR0 = 0; song_Index++; } if (song_Index==1) { song_Tone = song2_Tone; song_Time = song2_Time; } if (song_Index==2) { song_Tone = song3_Tone; song_Time = song3_Time; } if (song_Index==3) { song_Tone = song4_Tone; song_Time = song4_Time; } if (song_Index==4) { song_Tone = song5_Tone; song_Time = song5_Time; } if (song_Index==5) { song_Tone = song1_Tone; song_Time = song1_Time; } } void Timer0() interrupt 1 { TH0 = Tone_tab[Tone_Index]/256; TL0 = Tone_tab[Tone_Index]%256; Beep = ~Beep; } void display( void ) { P0 = LED_tab[song_Index]; } void Init( void ) { TMOD = 0x01; ET0 = 1; EX0 = 1; IT0 = 1; EA = 1; TR0 = 0; } void main() { Init(); song_Tone = song1_Tone; song_Time = song1_Time; while (1) { display(); Tone_Index = song_Tone[i]; if (Tone_Index==0xFF) { i = 0; TR0 = 0; } TR0 = 1; delayms(song_Time[Tone_Index]+100); TR0 = 0; i++; } } 代码及原理解释: 人耳在空气中能听得到声音是因为声源带动空气震动,达到人耳所能听到的范围(20~20Khz);当然通过其它介质也是可以传播的,这里就不做讨论了。 那么,要想产生声音,只要震动推动空气达到人耳听到的范围即可,常用的扬声器就是典型的转换设备,这里整个代码的核心思想是使用51单片机的定时器0中断产生音乐的音调,然后加上每个音调的发声长短就可以组成一首完整的音乐。 为了切换不同的音乐,我们可以事先对不同音乐的音调和实际演奏程中的音调发声时长进行编码。 音调和每个音符延时数组编码 定时器0中断,用于产生音调 每个音调延时长短处理部分 实际运行效果: 51单片机Proteus函数发生器仿真 函数发生器原理图 函数发生器代码链接:https://pan.baidu.com/s/1izoD5KOfXFZP2sgXjLin0g 提取码:1lbq 函数发生器代码: #include sbit UPKEY = P3^3; sbit DOWNKEY = P3^4; sbit SHKEY = P3^5; sbit FOUT = P3^2; unsigned char fun = 0; unsigned char th0_reg,tl0_reg; void delay_ms( unsigned int dt ); void main() { unsigned int f = 500; TMOD = 0x01; th0_reg = (unsigned int)(65539.0-(19531.25/f))>>8; tl0_reg = (unsigned int)(65539.0-(19531.25/f))&0x00ff; TH0 = th0_reg; TL0 = tl0_reg; TR0 = 1; IE = 0x82; P3 = 0xff; while (1) { if((UPKEY==0)&&(f<1000)) { f += (f/10)?(f/10):1; th0_reg = (unsigned int)(65539.0-(19531.25/f))>>8; tl0_reg = (unsigned int)(65539.0-(19531.25/f))&0x00ff; delay_ms(100); } if((DOWNKEY==0)&&(f>1)) { f -= (f/10)?(f/10):1; th0_reg = (unsigned int)(65539.0-(19531.25/f))>>8; tl0_reg = (unsigned int)(65539.0-(19531.25/f))&0x00ff; delay_ms(100); } if(SHKEY==0) { fun = !fun; delay_ms(100); } } } void delay_ms( unsigned int dt ) { register unsigned char bt,ct; for(;dt;dt--) for(ct=2; ct; ct--) for(bt=248; --bt;); } void intt0(void) interrupt 1 { unsigned char code sin_table[]={ 0,0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,4,4,5,5,6,6,6,7,8,8,9,9, 10,10,11,12,12,13,14,14,15,16,17,17,18,19,20,21,22,23,23,24,25, 26,27,28,29,30,31,32,33,34,35,37,38,39,40,41,42,43,45,46,47,48, 49,51,52,53,54,56,57,58,60,61,62,64,65,66,68,69,71,72,73,75,76, 78,79,81,82,84,85,87,88,90,91,93,94,96,97,99,100,102,103,105,106, 108,109,111,113,114,116,117,119,120,122,124,125,127,128,130,131, 133,135,136,138,139,141,142,144,146,147,149,150,152,153,155,156, 158,159,161,162,164,165,167,168,170,171,173,174,176,177,179,180, 182,183,184,186,187,189,190,191,193,194,195,197,198,199,201,202, 203,204,206,207,208,209,210,212,213,214,215,216,217,218,220,221, 222,223,224,225,226,227,228,229,230,231,232,232,233,234,235,236, 237,238,238,239,240,241,241,242,243,243,244,245,245,246,246,247, 247,248,249,249,249,250,250,251,251,252,252,252,253,253,253,253, 254,254,254,254,254,255,255,255,255,255,255,255,255 }; static unsigned char wave_index = 0; static bit index_sign = 1; TH0 = th0_reg; TL0 = tl0_reg; if(fun){ P2 = sin_table[wave_index]; } else { P2 = wave_index; } FOUT = !FOUT; if (index_sign==1){ if(++wave_index==255) index_sign = 0; } else { if(--wave_index==0) index_sign = 1; } } 代码及原理解释: 整个代码的核心部分是使用定时器0中断来完成的 其中方波产生部分相对比较简单,直接通过改变定时器的延时长度来控制P3.2引脚的方波产生。 方波引脚定义 方波产生引脚 三角波和正弦波发生部分使用DAC0832来产生,通过给P2端口加载不同数值,从而产生不同电压。 函数发生器: