一般说来,单片机演奏音乐基本都是单音频率,它不包含相应幅度的谐波频率,也就是说不能象电子琴那样能奏出多种音色的声音。因此单片机奏乐只需弄清楚两个概念即可,也就是“音调”和“节拍”。音调表示一个音符唱多高的频率,节拍表示一个音符唱多长的时间。
1)音调的确定
音调就是我们常说的音高。它是由频率来确定的!我们可以查出各个音符所对应的相应的频率,那么现在就需要我们来用51来发出相应频率的声音!
我们常采用的方法就是通过单片机的定时器定时中断,将单片机上对应蜂鸣器的I/O口来回取反,或者说来回清零,置位,从而让蜂鸣器发出声音,为了让单片机发出不同频率的声音,我们只需将定时器予置不同的定时值就可实现。那么怎样确定一个频率所对应的定时器的定时值呢?
以标准音高A为例:
A的频率f = 440 Hz,其对应的周期为:T = 1/ f = 1/440 =2272μs
那么,单片机上对应蜂鸣器的I/O口来回取反的时间应为:
t = T/2 = 2272/2 = 1136μs,也就是清零、置位在一个周期内完成.
这个时间t也就是单片机上定时器应有的中断触发时间。一般情况下,单片机奏乐时,其定时器为工作方式1,它以振荡器的十二分频信号为计数脉冲。设振荡器频率为f0,则定时器的予置初值由下式来确定:
t = 12 *(TALL – THL)/ f0
式中TALL = 216 = 65536,THL为定时器待确定的计数初值。因此定时器的高低计数器的初值为:
TH = THL / 256 = ( TALL – t* f0/12) / 256
TL = THL % 256 = ( TALL – t* f0/12) %256
将t=1136μs代入上面两式(注意:计算时应将时间和频率的单位换算一致),即可求出标准音高A在单片机晶振频率f0=12Mhz,定时器在工作方式1下的定时器高低计数器的予置初值为 :
TH440Hz = (65536 – 1136 * 12/12) /256 = FBH
TL440Hz = (65536 – 1136 * 12/12)%256 = 90H
就这样,我们通过延时,发出了我们所需要的频率
以单片机12MHZ晶振为例,例出高中低音符与单片机计数T0相关的计数值如下表所示
音符 | 频率(HZ) | 简谱码(T值) | <?XML:NAMESPACE PREFIX = O /> | 音符 | 频率(HZ) | 简谱码(T值) |
低1 DO | 262 | 63628 | # 4 FA# | 740 | 64860 | |
#1 DO# | 277 | 63731 | 中 5 SO | 784 | 64898 | |
低2 RE | 294 | 63835 | # 5 SO# | 831 | 64934 | |
#2 RE# | 311 | 63928 | 中 6 LA | 880 | 64968 | |
低 3 M | 330 | 64021 | # 6 | 932 | 64994 | |
低 4 FA | 349 | 64103 | 中 7 SI | 988 | 65030 | |
# 4 FA# | 370 | 64185 | 高 1 DO | 1046 | 65058 | |
低 5 SO | 392 | 64260 | # 1 DO# | 1109 | 65085 | |
# 5 SO# | 415 | 64331 | 高 2 RE | 1175 | 65110 | |
低 6 LA | 440 | 64400 |
| # 2 RE# | 1245 | 65134 |
# 6 | 466 | 64463 | 高 3 M | 1318 | 65157 | |
低 7 SI | 494 | 64524 | 高 4 FA | 1397 | 65178 | |
中 1 DO | 523 | 64580 | # 4 FA# | 1480 | 65198 | |
# 1 DO# | 554 | 64633 | 高 5 SO | 1568 | 65217 | |
中 2 RE | 587 | 64684 | # 5 SO# | 1661 | 65235 | |
# 2 RE# | 622 | 64732 | 高 6 LA | 1760 | 65252 | |
中 3 M | 659 | 64777 | # 6 | 1865 | 65268 | |
中 4 FA | 698 | 64820 | 高 7 SI | 1967 | 65283 |
下面我们要为这个音符建立一个表格,有助于单片机通过查表的方式来获得相应的数据
低音0-19之间,中音在20-39之间,高音在40-59之间
TABLE: DW 0,63628,63835,64021,64103,64260,64400,64524,0,0
DW 0,63731,63928,0,64185,64331,64463,0,0,0
DW 0,64580,64684,64777,64820,64898,64968,65030,0,0
DW 0,64633,64732,0,64860,64934,64994,0,0,0
DW 0,65058,65110,65157,65178,65217,65252,65283,0,0
DW 0,65085,65134,0,65198,65235,65268,0,0,0
DW 0
音乐的音拍,一个节拍为单位(C调)
曲调值 | DELAY |
| 曲调值 | DELAY |
调4/4 | 125ms |
| 调4/4 | 62ms |
调3/4 | 187ms |
| 调3/4 | 94ms |
调2/4 | 250ms |
| 调2/4 | 125ms |
通过上面关于一个音符音调和节拍的确定方法,我们就可以在单片机上实现演奏音乐了。具体的实现方法为:将乐谱中的每个音符的音调及节拍变换成相应的音调参数和节拍参数,将他们做成数据表格,存放在存储器中,通过程序取出一个音符的相关参数,播放该音符,该音符唱完后,接着取出下一个音符的相关参数……,如此直到播放完毕最后一个音符,根据需要也可循环不停地播放整个乐曲。另外,对于乐曲中的休止符,一般将其音调参数设为FFH,FFH,其节拍参数与其他音符的节拍参数确定方法一致,乐曲结束用节拍参数为00H来表示。
附上:
//挥着翅膀的女孩
unsigned char code Music_Girl[]={ 0x17,0x02, 0x17,0x03, 0x18,0x03, 0x19,0x02, 0x15,0x03,
0x16,0x03, 0x17,0x03, 0x17,0x03, 0x17,0x03, 0x18,0x03,
0x19,0x02, 0x16,0x03, 0x17,0x03, 0x18,0x02, 0x18,0x03,
0x17,0x03, 0x15,0x02, 0x18,0x03, 0x17,0x03, 0x18,0x02,
0x10,0x03, 0x15,0x03, 0x16,0x02, 0x15,0x03, 0x16,0x03,
0x17,0x02, 0x17,0x03, 0x18,0x03, 0x19,0x02, 0x1A,0x03,
0x1B,0x03, 0x1F,0x03, 0x1F,0x03, 0x17,0x03, 0x18,0x03,
0x19,0x02, 0x16,0x03, 0x17,0x03, 0x18,0x03, 0x17,0x03,
0x18,0x03, 0x1F,0x03, 0x1F,0x02, 0x16,0x03, 0x17,0x03,
0x18,0x03, 0x17,0x03, 0x18,0x03, 0x20,0x03, 0x20,0x02,
0x1F,0x03, 0x1B,0x03, 0x1F,0x66, 0x20,0x03, 0x21,0x03,
0x20,0x03, 0x1F,0x03, 0x1B,0x03, 0x1F,0x66, 0x1F,0x03,
0x1B,0x03, 0x19,0x03, 0x19,0x03, 0x15,0x03, 0x1A,0x66,
0x1A,0x03, 0x19,0x03, 0x15,0x03, 0x15,0x03, 0x17,0x03,
0x16,0x66, 0x17,0x04, 0x18,0x04, 0x18,0x03, 0x19,0x03,
0x1F,0x03, 0x1B,0x03, 0x1F,0x66, 0x20,0x03, 0x21,0x03,
0x20,0x03, 0x1F,0x03, 0x1B,0x03, 0x1F,0x66, 0x1F,0x03,
0x1B,0x03, 0x19,0x03, 0x19,0x03, 0x15,0x03, 0x1A,0x66,
0x1A,0x03, 0x19,0x03, 0x19,0x03, 0x1F,0x03, 0x1B,0x03,
0x1F,0x00, 0x1A,0x03, 0x1A,0x03, 0x1A,0x03, 0x1B,0x03,
0x1B,0x03, 0x1A,0x03, 0x19,0x03, 0x19,0x02, 0x17,0x03,
0x15,0x17, 0x15,0x03, 0x16,0x03, 0x17,0x03, 0x18,0x03,
0x17,0x04, 0x18,0x0E, 0x18,0x03, 0x17,0x04, 0x18,0x0E,
0x18,0x66, 0x17,0x03, 0x18,0x03, 0x17,0x03, 0x18,0x03,
0x20,0x03, 0x20,0x02, 0x1F,0x03, 0x1B,0x03, 0x1F,0x66,
0x20,0x03, 0x21,0x03, 0x20,0x03, 0x1F,0x03, 0x1B,0x03,
0x1F,0x66, 0x1F,0x04, 0x1B,0x0E, 0x1B,0x03, 0x19,0x03,
0x19,0x03, 0x15,0x03, 0x1A,0x66, 0x1A,0x03, 0x19,0x03,
0x15,0x03, 0x15,0x03, 0x17,0x03, 0x16,0x66, 0x17,0x04,
0x18,0x04, 0x18,0x03, 0x19,0x03, 0x1F,0x03, 0x1B,0x03,
0x1F,0x66, 0x20,0x03, 0x21,0x03, 0x20,0x03, 0x1F,0x03,
0x1B,0x03, 0x1F,0x66, 0x1F,0x03, 0x1B,0x03, 0x19,0x03,
0x19,0x03, 0x15,0x03, 0x1A,0x66, 0x1A,0x03, 0x19,0x03,
0x19,0x03, 0x1F,0x03, 0x1B,0x03, 0x1F,0x00, 0x18,0x02,
0x18,0x03, 0x1A,0x03, 0x19,0x0D, 0x15,0x03, 0x15,0x02,
0x18,0x66, 0x16,0x02, 0x17,0x02, 0x15,0x00, 0x00,0x00};
//同一首歌
unsigned char code Music_Same[]={ 0x0F,0x01, 0x15,0x02, 0x16,0x02, 0x17,0x66, 0x18,0x03,
0x17,0x02, 0x15,0x02, 0x16,0x01, 0x15,0x02, 0x10,0x02,
0x15,0x00, 0x0F,0x01, 0x15,0x02, 0x16,0x02, 0x17,0x02,
0x17,0x03, 0x18,0x03, 0x19,0x02, 0x15,0x02, 0x18,0x66,
0x17,0x03, 0x19,0x02, 0x16,0x03, 0x17,0x03, 0x16,0x00,
0x17,0x01, 0x19,0x02, 0x1B,0x02, 0x1B,0x70, 0x1A,0x03,
0x1A,0x01, 0x19,0x02, 0x19,0x03, 0x1A,0x03, 0x1B,0x02,
0x1A,0x0D, 0x19,0x03, 0x17,0x00, 0x18,0x66, 0x18,0x03,
0x19,0x02, 0x1A,0x02, 0x19,0x0C, 0x18,0x0D, 0x17,0x03,
0x16,0x01, 0x11,0x02, 0x11,0x03, 0x10,0x03, 0x0F,0x0C,
0x10,0x02, 0x15,0x00, 0x1F,0x01, 0x1A,0x01, 0x18,0x66,
0x19,0x03, 0x1A,0x01, 0x1B,0x02, 0x1B,0x03, 0x1B,0x03,
0x1B,0x0C, 0x1A,0x0D, 0x19,0x03, 0x17,0x00, 0x1F,0x01,
0x1A,0x01, 0x18,0x66, 0x19,0x03, 0x1A,0x01, 0x10,0x02,
0x10,0x03, 0x10,0x03, 0x1A,0x0C, 0x18,0x0D, 0x17,0x03,
0x16,0x00, 0x0F,0x01, 0x15,0x02, 0x16,0x02, 0x17,0x70,
0x18,0x03, 0x17,0x02, 0x15,0x03, 0x15,0x03, 0x16,0x66,
0x16,0x03, 0x16,0x02, 0x16,0x03, 0x15,0x03, 0x10,0x02,
0x10,0x01, 0x11,0x01, 0x11,0x66, 0x10,0x03, 0x0F,0x0C,
0x1A,0x02, 0x19,0x02, 0x16,0x03, 0x16,0x03, 0x18,0x66,
0x18,0x03, 0x18,0x02, 0x17,0x03, 0x16,0x03, 0x19,0x00,
0x00,0x00 };
//两只蝴蝶
unsigned char code Music_Two[] ={ 0x17,0x03, 0x16,0x03, 0x17,0x01, 0x16,0x03, 0x17,0x03,
0x16,0x03, 0x15,0x01, 0x10,0x03, 0x15,0x03, 0x16,0x02,
0x16,0x0D, 0x17,0x03, 0x16,0x03, 0x15,0x03, 0x10,0x03,
0x10,0x0E, 0x15,0x04, 0x0F,0x01, 0x17,0x03, 0x16,0x03,
0x17,0x01, 0x16,0x03, 0x17,0x03, 0x16,0x03, 0x15,0x01,
0x10,0x03, 0x15,0x03, 0x16,0x02, 0x16,0x0D, 0x17,0x03,
0x16,0x03, 0x15,0x03, 0x10,0x03, 0x15,0x03, 0x16,0x01,
0x17,0x03, 0x16,0x03, 0x17,0x01, 0x16,0x03, 0x17,0x03,
0x16,0x03, 0x15,0x01, 0x10,0x03, 0x15,0x03, 0x16,0x02,
0x16,0x0D, 0x17,0x03, 0x16,0x03, 0x15,0x03, 0x10,0x03,
0x10,0x0E, 0x15,0x04, 0x0F,0x01, 0x17,0x03, 0x19,0x03,
0x19,0x01, 0x19,0x03, 0x1A,0x03, 0x19,0x03, 0x17,0x01,
0x16,0x03, 0x16,0x03, 0x16,0x02, 0x16,0x0D, 0x17,0x03,
0x16,0x03, 0x15,0x03, 0x10,0x03, 0x10,0x0D, 0x15,0x00,
0x19,0x03, 0x19,0x03, 0x1A,0x03, 0x1F,0x03, 0x1B,0x03,
0x1B,0x03, 0x1A,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x03,
0x16,0x0D, 0x17,0x01, 0x17,0x03, 0x17,0x03, 0x19,0x03,
0x1A,0x02, 0x1A,0x02, 0x10,0x03, 0x17,0x0D, 0x16,0x03,
0x16,0x01, 0x17,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x03,
0x19,0x02, 0x1F,0x02, 0x1B,0x03, 0x1A,0x03, 0x1A,0x0E,
0x1B,0x04, 0x17,0x02, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E,
0x1B,0x04, 0x1A,0x03, 0x19,0x03, 0x17,0x03, 0x16,0x03,
0x17,0x0D, 0x16,0x03, 0x17,0x03, 0x19,0x01, 0x19,0x03,
0x19,0x03, 0x1A,0x03, 0x1F,0x03, 0x1B,0x03, 0x1B,0x03,
0x1A,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x03, 0x16,0x03,
0x17,0x01, 0x17,0x03, 0x17,0x03, 0x19,0x03, 0x1A,0x02,
0x1A,0x02, 0x10,0x03, 0x17,0x0D, 0x16,0x03, 0x16,0x01,
0x17,0x03, 0x19,0x03, 0x19,0x03, 0x17,0x03, 0x19,0x03,
0x1F,0x02, 0x1B,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,
0x17,0x02, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,
0x17,0x16, 0x1A,0x03, 0x1A,0x03, 0x1A,0x0E, 0x1B,0x04,
0x1A,0x03, 0x19,0x03, 0x17,0x03, 0x16,0x03, 0x0F,0x02,
0x10,0x03, 0x15,0x00, 0x00,0x00 };
用户194501 2009-9-18 13:12
用户116683 2008-10-13 08:51