单片机驱动蜂鸣器唱国歌的设计与原理

更新时间:2023-08-25 03:55:02 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

蜂鸣器演奏国歌

(11机自创新1班 王丽红 1110100736)

1 设计任务

本设计是以AT89C51芯片的电路为基础,外部加上三级管驱动蜂鸣器,以此来实现音乐演奏控制的硬件电路,通过软件程序来控制单片机内部的定时器使其演奏出优美动听的音乐。按照要求选择音乐,在本次设计中以演奏《国歌》为例,将其转化为机器码存入单片机的存储器中。

2 设计原理

蜂鸣器发声原理是电流通过电磁线圈,使电磁线圈产生磁场来驱动振动膜发声的,因此驱动需要一定的电流,单片机引脚输出的电流较小,基本上驱动不了蜂鸣器,因此需要增加一个电流放大的电路。三极管的发射极E接电源,集电极C接蜂鸣器正极,蜂鸣器负极接地,三极管的基级B经过限流电阻R后由单片机引脚控制。当输出高电平时,三极管T1截止,没有电流流过线圈,蜂鸣器不发声;当输出低电平时,三极管导通,这样蜂鸣器的电流形成回路,发出声音。 程序中改变单片引脚输出波形的频率,就可以调整控制蜂鸣器音调,产生各种不同音色、音调的声音。另外,改变输出电平的高低电平占空比,则可以控制蜂鸣器的声音大小,这些我们都可以通过编程实验来验证。

3 软件设计

3.1 音调、节拍以及编码的确定

一般说来,单片机演奏音乐基本都是单音频率,它不包含相应幅度的谐波频率,也就是说不能像电子琴那样能奏出多种音色的声音。因此单片机奏乐只需弄清楚两个概念即可,也就是“音调”和节拍表示一个音符唱多长的时间。

3.1.1 音调的确定

不同音高的乐音是用C、D、E、F、G、A、B来表示,这7个字母就是音乐的音名,它们一般依次唱成DO、RE、MI、FA、SO、LA、SI,即唱成简谱的1、2、3、4、5、6、7,这是唱曲时乐音的发音,所以叫“音调”。把C、D、E、F、G、A、B这一组音的距离分成12个等份,每一个等份叫一个“半音”。两个音

之间的距离有两个“半音”,就叫“全音”。

1) 要产生音频脉冲,只要算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。利用定时器计时这半个周期时间,每当计时到后就将输出脉冲的I/O反相,然后重复计时此半周期时间再对I/O反相,就可在I/O脚上得到此频率的脉冲。

2) 利用AT89C51的内部定时器使其工作在计数器模式MODE1下,改变计数值TH0及TL0以产生不同频率的方法。此外结束符和休止符可以分别用代码00H和FFH来表示,若查表结果为00H,则表示曲子终了;若查表结果为FFH,则产生相应的停顿效果。

3.1.2 节拍的确定

若要构成音乐,光有音调是不够的,还需要节拍,让音乐具有旋律,而且可以调节各个音的快慢度。音持续时间的长短即时值,一般用拍数表示。休止符表示暂停发音。一首音乐是由许多不同的音符组成的,而每个音符对应着不同频率,这样就可以利用不同的频率的组合,加以与拍数对应的延时,构成音乐。了解音乐的一些基础知识,我们可知产生不同频率的音频脉冲即能产生音乐。对于单片机来说,产生不同频率的脉冲是非常方便的,利用单片机的定时/计数器来产生这样的方波频率信号。因此,需要弄清楚音乐中的音符和对应的频率,以及单片机定时计数的关系。每个音符使用1个字节,字节的高4位代表音符的高低,低4位代表音符的节拍。如果1拍为0.4秒,1/4拍实0.1秒,只要设定延迟时间就可求得节拍的时间。假设1/4拍为1DELAY,则1拍应为4DELAY,以此类推。所以只要求得1/4拍的DELAY时间,其余的节拍就是它的倍数。

3.1.3 编码

do re mi fa so la si分别编码为1-7,重音do编为8,重音re编为9,停顿编为0。播放长度以十六分音符为单位(165ms),一拍即四分音符等于4个十六分音符,编为4,其它播放时间以此类推。音调作为编码的高4位,播放时间作为低4位,如此音调和节拍就构成了一个编码。以0xff作为曲谱的结束标志。

举例1:音调do,发音长度为两拍,即二分音符,将其编码为0x18。 举例2:音调re,发音长度为半拍,即八分音符,将其编码为0x22。

歌曲播放的设计。先将歌曲的简谱进行编码,储存在一个数据类型为unsigned

char的数组中。程序从数组中取出一个数,然后分离出高4位得到音调,接着找出相应的值赋给定时器0,使之定时操作蜂鸣器,得出相应的音调;接着分离出该数的低4位,得到延时时间,接着调用软件延时。

4 程序设计流程

图1 程序设计流程图

5 程序

#include <reg52.h>

sbit beep=P2^0;

unsigned char tl0,th0;

unsigned int code FreqTab1[]={

}; 64216,64360,64489,64547,64654,64752,64837, 64876,64948,65012,65042,65095,65144,65186, 65206,65242,65274,65289,65135,65340,65361,

unsigned int code FreqTab[]={ //简谱对应的简谱码、T值

65535,64260,64400,64524,64579,64685,64778,64860,

64898,64968,65030,65057,65110,65157,65198, 65217,65252,65283,65297,65323,65346,65367, };

unsigned char code yyjjxq[]={

8,0x08,0,0x04,5,0x04, 8,0x0c,8,0x04, 8,0x06,8,0x02,5,0x04,6,0x02,7,0x02, 8,0x08,8,0x08, 0,0x04,10,0x04,8,0x04,9,0x02,10,0x02, //10,0x04,10,0x04,8,0x04,9,0x02,10,0x02, 12,0x08,12,0x08, 10,0x06,10,0x02,8,0x06,10,0x02, 12,0x06,10,0x02,9,0x08, //12,0x10, 9,0x10, 13,0x08,12,0x08, 9,0x08,10,0x08, 12,0x04,10,0x04,0,0x04,12,0x04,

void delay(unsigned char t)

{

unsigned char t1; //12,0x04,10,0x04,10,0x04,12,0x04, 10,0x04,9,0x02,10,0x02,8,0x08, 10,0x08,0,0x08, //10,0x08,10,0x08, 5,0x06,6,0x04,8,0x04,8,0x04, 10,0x06,10,0x02,12,0x04,12,0x04, 9,0x04,9,0x02,9,0x02,6,0x08, 9,0x0c,5,0x04, 8,0x0c,8,0x04, 10,0x0c,10,0x04, 12,0x10, 8,0x06,10,0x02,12,0x04,12,0x04, 13,0x08,12,0x08, 10,0x06,8,0x02,12,0x08, 10,0x04,0,0x04,8,0x04,0,0x04, //10,0x04,10,0x04,8,0x04,8,0x04, 5,0x08,8,0x08, 10,0x06,8,0x02,12,0x08, 10,0x04,0,0x04,8,0x04,0,0x04, //10,0x04,10,0x04,8,0x04,8,0x04, 5,0x08,8,0x08, 5,0x08,8,0x08, 5,0x08,8,0x08, 8,0x08,0,0x08, //8,0x08, 0xff,0xff, }; //延时程序,控制发音的时间长度

unsigned long t2;

for(t1=0;t1<t;t1++) //双重循环,共延时t个半拍

for(t2=0;t2<1800;t2++); //延时期间,可进入T0中断去发音 TR0=0; //关闭T0, 停止发音 }

void delayms(unsigned int x)

{

unsigned int a,b;

for(a=x;a>0;a--)

for(b=124;b>0;b--);

}

void timer0() interrupt 1

{

TR0=0;

beep=~beep;

TL0=tl0;

TH0=th0;

TR0=1;

}

void main()

{

unsigned char k;

TMOD=0x01;

ET0=1;

EA=1;

while(1)

{

if( yyjjxq[k]==0xff)

{

beep=1; //T0中断程序,控制发音的音调 //先关闭T0 //输出方波, 发音 //下次的中断时间, 这个时间, 控制音调高低 //启动T0 } //定时器0工作方式1 //开T0中断 //开CPU中断 //结束

TR0=0;

delayms(500); delayms(500); delayms(500); //k=0;

}

else

{

if( yyjjxq[k]==0x00) {

TR0=0;

delay(yyjjxq[k+1]); k+=2; }

else

{ th0=FreqTab[ yyjjxq[k]]/256; tl0=FreqTab[ yyjjxq[k]]%256; TR0=1;

delay(yyjjxq[k+1]); k+=2;

} } }

} //第i个是音符, 第i+1个是第几个八度 //从数据表中读出频率数值 //实际上, 是定时的时间长度

本文来源:https://www.bwwdw.com/article/wuli.html

Top