原创 基于51单片机的乐曲播放

2010-5-24 10:20 4534 11 15 分类: MCU/ 嵌入式

基于51单片机的乐曲播放<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


我们可以利用单片机产生乐曲的音符,并通过蜂鸣器或喇叭播放出音乐。


 


Ⅰ单片机的发音


  音调


音调是表示一个音符唱多高的频率,和平时说的“音高”十分类似。


音乐的产生主要是通过单片机的IO口输出高低不同的脉冲信号来控制蜂鸣器发音。要想产生音频脉冲信号,需要算出某一音频的周期(1/频率),然后将此周期除以2,即为半周期的时间。利用单片机定时器计时这个半个周期时间,每当计时到后就将输出脉冲的IO口反相,然后重复计时此半周期时间再对IO口反相,这样就能在此IO口上得到此频率的脉冲。


通常,利用AT89C5X单片机的内部定时器O,工作在方式1下,改变计数初值TH0TL0来产生不同的频率(当然也可以利用延时的方法来获得)。


C调部分音符的频率与定时器TH/TL的预置初值(51单片机晶振频率为12MHz,定时器工作于方式1),如下表所示。



低音


f/Hz


THx


TLx


中音


f/Hz


THx


TLx


高音


f/Hz


THx


TLx


 1


262


248


140


 1


523


252


68


 1


1045


254


34


 2


293


249


92


 2


596


252


173


 2


1171


254


87


 3


329


250


21


 3


659


253


10


 3


1316


254


133


 4


349


250


140


 4


697


253


52


 4


1393


254


155


 5


392


251


5


 5


783


253


131


 5


1563


254


194


 6


440


251


144


 6


879


253


200


 6


1755


254


228


 7


494


252


12


 7


987


254


6


 7


1971


255


3


 


       节拍


    节拍表示一个音符唱多长的时间,在一张完整乐谱的开头,都有如1=C 4/41=G 3/4;……等的标识。这里的4/43/4用来表示节拍,而1=C1=G表示一个乐谱的曲调,简单地说就是跟音调有关系。对于音符的节拍,这里以下图所示为例加以说明。


9b12fe58-1b9a-49a6-a20c-dbeb329d987c.jpg


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace prefix = w ns = "urn:schemas-microsoft-com:office:word" />   它表示乐谱中以四分音符为节拍,每一小节有三拍。其中,12为一拍,345为一拍,6为一拍。


    从发音的时长角度看,12的时长为四分音符的一半,即为八分音符长;34的时长为八分音符的一半,即为十六分音符长;5的时长为四分音符的一半,即为八分音符长;6的时长为四分音符长。一般说来,如果乐曲没有特殊说明,则对于一拍的发音时间大约为400500ms


在单片机上可以采用循环延时的方法来实现控制一个音符唱多长时间,从而实现节拍。一般来说,首先需要编写一个精确地基本时长的延时程序,比如说以最短的十六分音符的时长为基本延时时间。对于一个音符,如果它为十六分音符,则只需调用一次延时程序,如果它为四分音符,则只需调用四次延时程序,如果它为二分音符,则只需调用八次延时程序,依次类推即可。


    节拍也可以利用定时器中断产生。同样是找出整首乐曲中,最短的拍子,例如整首乐曲中,最短是14拍,若14拍的时间为125ms,则以14拍为基准,然后设定每125ms产生一次中断,其定时器初值为125000(晶振12MHz),它超过任何一个定时器模式的定时器值。若采用模式1,而定时器值设为62500,则只要执行2次中断,即可产生14拍的时间长度。同样,若要产生12拍的长度,则执行4次中断、若要产生34拍的长度,则执行6次中断……依此类推,节拍与定时器中断次数如下表所示。



  拍数


中断次数


 


  拍数


中断次数


 


  拍数


中断次数


   1/8


    1


   1/2


    4


  1 1/4


   10


   1/4


    2


   3/4


    6


  1 1/2


   12


   3/8


    3


    1


    8


    2


   16


本例即是利用T0定时器方式1的中断产生音调,利用T1定时器方式1的中断产生节拍。


 


     移调


一首的歌曲如果是C调,则音名CDo,音名DRe,音名EMi,音名FFa,音名GSo,音名ALa,音名BTi等。但是,并不是所有的歌曲都是在C调下演奏的,还有D调、E调、F调、G调等。D调是将C调各音符上升一个频率实现的,即C调下的音名DD调下唱DoC调下的音名ED调下唱ReC大调的音名FD调下升高半音符F#MiC调下的音名GD调下唱FaC调下的音名AD调下唱SoC调下的音名BD调下唱LaC调下的音名CD调下升高半音C#符唱Ti。这种改变唱法称为移调。


E调是在D调的基础上进行移调的,而F调是在E调的基础上进行移调的……下表为各调音符与音名的关系。



        音名


 


  Do


  Re


  Mi


  Fa


  So


  La


  Ti


    C


  C


  D


  E


  F


  G


  A


  B


    D


  D


  E


  F#


  G


A


  B


  C


    E


  E


  F#


  G#


  A


  B


  C


  D


    F


  F


  G


  A


  B


  C


  D


  E


    G


  G


  A


  B


  C


  D


  E


  F#


    A


  A


  B


  C#


  D


  E


  F#


  G#


    B


  B


  C


  D


  E


  F


  G


  A


 


硬件设计


采用51单片机的乐曲播放硬件电路如下图所示。


0f17bb8b-e0a7-44bf-9bdc-5e6abe0db157.jpg


在桌面上双击图标feaa344d-6504-4d0f-a0b3-3f6cf6ee7446.jpg,打开ISIS 7 Professional窗口(本人使用的是v7.4 SP3中文版)。单击菜单命令“文件”→“新建设计”,选择DEFAULT模板,保存文件名为“YQ.DSN”。在器件选择按钮3b6a6753-801c-4458-abd5-63415236e852.jpg中单击“P”按钮,或执行菜单命令“库”→“拾取元件/符号”,添加如下表所示的元件。



51单片机AT89C51    一片


晶体CRYSTAL 12MHz   一只


瓷片电容CAP 22pF    二只


电解电容CAP-ELEC 10uF   一只


电阻RES 10K         一只


电阻RES 3K         一只


三极管 PNP 9015    一只


喇叭 SPEAKER       一只


若用Proteus软件进行仿真,则上图中的晶振和复位电路以及U131脚,都可以不画,它们都是默认的。要注意CPU属性中晶振频率的选择。


ISIS原理图编辑窗口中放置元件,再单击工具箱中元件终端图标c54e797c-f41a-45c2-932b-260ee2214442.jpg,在对象选择器中单击POWERGROUND放置电源和地。放置好元件后,布好线。左键双击各元件,设置相应元件参数,完成电路图的设计。


 


软件设计


本例利用T0定时器方式1的中断产生音调,利用T1定时器方式1的中断产生节拍。例如,歌曲“送别”中一段乐曲的T0初值和T1中断次数如下所示。


点击看大图


 


本例的流程如下图所示。



点击看大图 


该乐曲播放的详细C51程序如下。


/************************


乐曲播放 12MHz


**********************/


#include "reg51.h"


 


#define uchar unsigned char


uchar rr7,rr6,rr5=0,ct0h,ct0l,baseh=0x10,basel=0xdc;


sbit speaker="P1"^0;


uchar code tone[]={                       //送别的音调TH0/TL0


253,131,253,10,253,131,254,34,253,200,254,34,253,200,253,131,253,131,252,68,252,173,253,10,252,173,252,68,252,173,


253,131,253,10,253,131,254,34,254,6,253,200,254,34,253,131,253,131,252,173,253,10,253,52,252,12,252,68,


253,200,254,34,254,34,254,6,253,200,254,6,254,34,253,200,254,6,254,34,253,200,253,200,253,131,253,10,252,68,252,173,


253,131,253,10,253,131,254,34,254,6,253,200,254,34,253,131,253,131,252,173,253,10,253,52,252,12,252,68,0


};        


uchar code beat[]={                //送别节拍--T1中断次数


8,4,4,16,8,4,4,16,8,4,4,8,4,4,24,


8,4,4,12,4,8,8,16,8,4,4,12,4,24,


8,8,16,8,4,4,16,4,4,4,4,4,4,4,4,32,


8,4,4,8,4,8,12,16,8,4,4,12,4,24,0


};


 


/******载入音调*****************/


load_t()


{


    uchar k;


loop:k=tone[rr7];


    if(k==0)


    {


       rr6=0;rr7=0;


       goto loop;


    }


    else


    {


       ct0h=TH0=k;rr7++;


       k=tone[rr7];


       ct0l=TL0=k;


       rr7++;TR0=1;


    }


}


 


/****************载入节拍*******/


load_b()


{


    uchar k;


    k=rr5=beat[rr6];


    rr6++;TH1=baseh;TL1=basel;TR1=1;


}


 


main()


{


    //uchar i;


    TMOD=0X11;IE=0X8A;F0=0;


    while(1)


    {


       load_t();         //载入音阶


       load_b();         //载入节拍


       while(F0==0)


       ;


       F0=0;


    }


}


 


/*******音调中断子函数************/


void int_t0() interrupt 1


{


    TR0=0;speaker=!speaker;


    TH0=ct0h;TL0=ct0l;TR0=1;


}


 


 


/*******节拍中断子函数************/


void int_t1() interrupt 3


{


    TR1=0;rr5--;


    if(rr5==0)


    {


       TR0=0;F0=1;


    }


    else


    {


       TH1=baseh;TL1=basel;TR1=1;


    }


}


 


打开KeilμVision3程序(本人使用的是Keil8.05中文版),执行菜单命令“工程”→“新建工程”创建“YQ”项目,并选择单片机型号为AT89C51(也可以使用原有项目)。执行菜单命令“文件”→“新建”创建文件,输入C语言源程序,保存为“YQ.C”。在Project Workspace窗口中右击源代码组1,选择“添加文件到组‘源代码组 l’”将源程序“YQ.C”添加到项目中。


KeilμVision3中执行执行菜单命令“工程”→“创建目标”(或点击“创建目标”快捷按钮),编译源程序。如果编译成功,则在“Output Window”的“创建”窗口中显示没有错误,并创建了“YQ.HEX”文件。


 


  仿真与调试


关于ProteusKeil的联合仿真调试,可参见我以前所写的博文或其它参考资料。需注意ProteusISISKeilμVision3中“YQ.HEX”的路径要一致(或ProteusISISCPU属性Program File为空)。


启动ProteusISIS,并将其放在屏幕的右上角(可将原理图放大到合适大小);再启动KeilμVision3,并将其放在屏幕的左下角。


    KeilμVision3中执行菜单命令“调试”→“启动/停止调试”,或直接单击图标0c2cfd5a-6ff2-4638-b9de-fa8b66290fee.jpg,进入KeilμVision3调试环境。同时,在Proteus ISIS的窗口中可看出Proteus也进入了程序调试状态。


    KeilμVision3代码编辑窗口中设置相应断点,断点的设置方法:在需要设置断点语句前双击鼠标左键,可设置断点;再次双击,可取消该断点。


KeilμVision3中按F5键(或点击“运行”快捷按钮)运行程序,就会循环播放“送别”的乐曲。或可以点击单步、运行到光标处、全速运行等快捷按钮,以及同时观察工程窗口寄存器页面、存储器窗口等,来进行仿真调试。


 


    本人邮箱:txxyc104@163.com,欢迎来信讨论.


 


 

PARTNER CONTENT

文章评论4条评论)

登录后参与讨论

用户377235 2013-7-19 10:10

好人

用户377235 2012-4-17 23:12

很好 感谢了!

用户202137 2010-6-20 09:53

对音乐知识一窍不通不知道能不能做出来…… - -!!

tengjingshu_112148725 2010-4-21 16:31

收藏之
相关推荐阅读
用户518655 2010-08-16 17:11
基于ARM单片机的单总线应用
基于ARM单片机的单总线应用单总线(1-Wire)是美国达拉斯半导体公司的一项专利技术。与目前广泛应用的其他串行数据通信方式不同,它采用单根信号线完成数据的双向传输,具有节省I/O引脚资源、结构简单、...
用户518655 2010-08-11 18:16
基于ARM单片机的128x64LCM应用(串行接口)
基于ARM单片机的128x64LCM应用(串行接口)ARM单片机是32位的,而51单片机是8位的,功能上ARM单片机要大大优于51单片机,而其价格已经很低了,从发展的眼光看,ARM单片机将会占据单片机...
用户518655 2010-08-10 10:41
基于ARM单片机的128x64LCM应用(并行接口)
基于ARM单片机的128x64LCM应用(并行接口)ARM单片机的功能要大大优于51单片机,而其价格已经很低了,生产厂家不论是出于广告宣传的需要,还是出于利润的角度考虑(嵌入ARM单片机将会卖更高的价...
用户518655 2010-08-06 18:02
基于ARM单片机的软件时钟
基于ARM单片机的软件时钟ARM单片机的功能要大大优于51单片机,而其价格已经很低了,生产厂家不论是出于广告宣传的需要,还是出于利润的角度考虑(嵌入ARM单片机将会卖更高的价格),他们更希望在自己的产...
用户518655 2010-08-03 16:49
寄语新同学
寄语新同学       我是一名从教三十多年的大学老师,因此我认为我有资格向即将成为大学生的新同学们说几句话。       首先祝贺你们即将成为一名大学生!在你们将要跨进大学校门开始新的学习生活之前,...
用户518655 2010-06-19 16:00
单片机的一种分类方法
单片机的一种分类方法<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />“单片机”一词在...
EE直播间
更多
我要评论
4
11
关闭 站长推荐上一条 /3 下一条