1、 蜂鸣器唱歌-生日快乐下面是我单片机入门的时候写的一个蜂鸣器唱歌的程序,用的是 stc89c52 的单片机和 12MHZ 的晶振。它大致是这样工作的。我们知道歌曲都是由最基本的音调和节拍组成的。音调就是该音符的频率,节拍就是该音符持续的时间。也就是说发出一个最基本的音我们需要两个参数,一个是频率,一个是节拍。那么在单片机中如何产生这两个参数呢?首先我们需要知道该音符的频率,然后用单片机的 I/O 口不断地变高变低来产生这个频率。比如 1 这个音在低音,中音,高音三种情况下会有 3 种频率,至于到底是哪种音,在歌曲的乐谱中会给出详细的标识。现在我们假设 1 这个音为低音, 在 d 调(什么是 d
2、 调?看文章尾附录)下频率为 293hz,一个周期为 T=1/293 s。那么 I/O 口被置 1 和置 0 的时间各占一半也就是 T/2。然后算出相应的定时器初值,那么单片机就可以发出这个音了。接下来就是一个音符要唱多久,那就要看这个音符占据多少个节拍了,同样在歌曲的乐谱中会给出详细的标示。那么一拍是多长呢,下面有说明。慢节奏一般 600ms 一拍,快节奏一般 400ms 一拍。如果你要知道更准确的节拍时长,只有拿着乐谱去听歌了,记下唱一拍的时间就行了。我用的是定时器 0 控制节拍长度,在每个音符开始时开启它,它是10ms 中断一次,并且让里面的计数值增加 1。如果我要唱一拍的话(假设为 6
3、00ms),那么我只需要判断计数值是否达到 60,如果达到那么就停止计时然后跳到下一拍。以上就是蜂鸣器唱歌的基本原理了,希望能对你有所帮助。#include #define uchar unsigned char#define uint unsigned intsbit sound=P37;uint counter=0;uchar code FREQH38= /音符定时器初值,三个 8 度音的高八位/注意每行起始都为 0xff,因为音调中没有 0 这个音 ,所以随便填了个数字,后面不不会引用它/ 低音:/ 1 2 3 4 5 6 70xff,0xf9, 0xfa, 0xfa, 0xfb, 0x
4、fb, 0xfc, 0xfc,/中音:/1 2 3 4 5 6 70xff,0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe,/高音:/1 2 3 4 5 6 70xff,0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0x00/0x00;uchar code FREQL38= /音符定时器初值,三个 8 度音的低八位/ 低音:/ 1 2 3 4 5 6 70xff,0x5b, 0x15, 0xb9, 0x04, 0x90, 0x0c, 0x79,/中音:/ 1 2 3 4 5 6 70xff,0xac, 0x09, 0x5c, 0x82
5、, 0xc8, 0x05, 0x3c,/高音:/1 2 3 4 5 6 70xff,0x55, 0x84, 0xad, 0xc0, 0xe3, 0x02, 0x00/0x00;uchar code MUSIC=/生日快乐/歌曲代码,每三个表示一个音符及节拍,第一个表示音符 1234567,第二个表示音高,0表示低音,1 表示中音,2 表示高音,第三个表示节拍长度,1 表示半拍,2 表示一拍,以此类推。6,1,3, 5,1,1, 3,1,2, 5,1,2, 1,2,2, 6,1,1, 5,1,1, 6,1,4, 3,1,1, 5,1,1, 6,1,1, 5,1,2, 3,1,2, 1,1,1,
6、6,0,1, 5,1,1, 3,1,1, 2,1,4, 2,1,3, 3,1,1, 5,1,2, 5,1,1, 6,1,1, 3,1,2, 2,1,2, 1,1,4, 5,1,4, 3,1,1, 2,1,1, 1,1,1, 6,0,1, 1,1,1, 5,0,8, 0;void init()/定时器初始化TMOD=0x11;TH0=0xd8;TL0=0xef;EA=1;ET0=1; void timer0(void) interrupt 1 using 3 /timer0 中断服务程序,中断一次延时 10mscounter+;/节拍次数计数 TH0=0xd8; /定义单位节拍的延时大小 TL0
7、=0xef;void delay(uchar n) /延时 n 毫秒uchar i;while(n-)for(i=0;i125;i+); void sound_delay(uchar sound_signalhigh,uchar sound_signallow)/产生一定频率的音调 TH1=sound_signalhigh;TL1=sound_signallow;TR1=1;while(TF1=0);TR1=0;TF1=0; void main()uint i,j,k=0;uchar sound_signalhigh,sound_signallow;/定时器的高 8 位与低 8 位uchar
8、sound_pace;/定义节拍计数器 init();while(1)k=0;while(MUSICk!=0)/因为歌曲的结尾处人为的加入了 结束标示符 0 j=MUSICk+; /从表中取得 音符大小 i=MUSICk+; /*从表中取得 音符音高,也就是这个音符是低音,中音还是高音,有了这两个参数我们就可以确定音符对应的定时器初值在表中的位置了。sound_signalhigh=FREQHij;sound_signallow=FREQLij;/从表中取得 节拍大小 sound_pace=60*MUSICk+;/600 为一拍的时长 ,在此修改一拍的时长。TR0=1;/当节拍数未达到时候,继
9、续循环,产生该音调的声音 while(counter!=sound_pace) sound=sound;sound_delay(sound_signalhigh,sound_signallow);counter=0;/节拍计数器置 0,进入下一个音调 TR0=0;delay(100); /歌曲演唱完毕后,延时一段时间 注意:不同调下的音符频率也不一样,比如有些歌的音调非常高,而 c 调下都没有这么高的音符。那怎么办呢,只有升调,也就是在 c 调的基础上再加上某个特定频率使整个音符频率都被拉高。这就是所谓的 d 调。不过大多数歌曲都是用 d 调唱的。音符频率及定时器初值表(c 调) /12mhz
10、低音:1 2 3 4 5 6 7f88c f95b fa15 fa67 fb04 fb90 fc0c中音:1 2 3 4 5 6 7fc44 fcac fd09 fd34 fd82 fdc8 fe05高音:1 2 3 4 5 6 7fe21 fe55 fe84 fe9a fec0 fee3 ff02附录 :音符频率及定时器初值表(d 调) 12mhz低音:1 2 3 4 5 6 7f95b fa15 fab9 fb04 fb90 fc0c fc79中音:1 2 3 4 5 6 7fcac fd09 fd5c fd82 fdc8 fe05 fe3c高音:1 2 3 4 5 6 7fe55 fe84 fead fec0 fee3 ff02 2212hz