【51单片机】 利用定时器产生生日快乐歌

定时器产生音乐的基础:

声音的频谱范围约在几十到几千赫兹,利用单片机定时器的定时中断功能,可以从一个I/O口线上形成一定频率的脉冲,经过滤波和功率放大,接上喇叭就能发出一定频率的声音,若再利用延时程序控制输出脉冲的频率来改变音调,即可实现音乐发生器功能。

要让单片机产生音频脉冲,只要计算出某一音频的周期,在将此周期除以2得到半周期,利用定时器对此半周期进行定时,每当定时时间到,将某个I/O口线上的电平取反,从而在I/O口线上得到所需要的音频脉冲。

例如中音DO的频率为523Hz,若单片机工作频率为12MHz,定时器T0设置为工作方式1,按公式计算得定时器初值为64580;高音DO的频率为1047Hz,计算得定时器初值为65058。

例如一段延时程序DELAY为1/4拍,则1拍只要调用4次DELAY程序,依此类推。

编写音乐程序时,先把乐谱的音符找出,按表建立对应的简谱码及定时器初值表,按表建立节拍码表。每个音符使用1个字节,字节的高4位存放音符的高低,低4位存放音符的节拍。“生日快乐”乐谱如下:

|5.5 6 5|1 7 -||5.5 6 5|2 1 -|5.5 5 3|1 7 6|4.4 3 1|2 1 -|

设计乐谱对应的音符节拍码表和音符对应的定时器的初值表如下:

uchar TABLE[]={
//音符节拍码表

0x82, 0x01,0x81, 0x94, 0x84, 0xB4, 0xA4, 0x04,
0x82, 0x01,0x81, 0x94, 0x84, 0xC4, 0xB4, 0x04,
0x82, 0x01, 0x81, 0xF4, 0xD4, 0xB4, 0xA4, 0x94,
0xE2, 0x01, 0xE1, 0xD4, 0xB4, 0xC4, 0xB4, 0x04,
0x82, 0x01, 0x81, 0x94, 0x84, 0xB4, 0xA4, 0x04,
0x82, 0x01, 0x81, 0x94, 0x84, 0xC4, 0xB4, 0x04,
0x82, 0x01, 0x81, 0xF4, 0xD4, 0xB4, 0xA4, 0x94,
0xE2, 0x01, 0xE1, 0xD4, 0xB4, 0xC4, 0xB4, 0x04,
0x00} ;
uchar TABLE1[]={
//音符对应的定时器初值表
0xfb, 0x04, 0xfb, 0x90, 0xfc, 0x09, 0xfc, 0x44,
0xfc, 0xac, 0xfd, 0x09,0xfd, 0x34, 0xfd, 0x82,
0xfd, 0xc8, 0xfe, 0x06, 0xfe, 0x22, 0xfe, 0x56,
0xfe, 0x85, 0xfe, 0x9a, 0xfe, 0xc1};

“生日快乐”乐曲的C语言程序如下:

#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

sbit BEEP=P1^0;//定义喇叭输出端口

uchar tick,tl, th;//定义节拍和TO初值变量

uchar TABLE[]={//音符节拍码表
0x82, 0x01, 0x81, 0x94, 0x84, 0xB4, 0xA4, 0x04,
0x82, 0x01, 0x81, 0x94, 0x84, 0xC4, 0xB4, 0x04,
0x82, 0x01, 0x81, 0xF4, 0xD4, 0xB4, 0xA4, 0x94,
0xE2, 0x01, 0xE1, 0xD4, 0xB4, 0xC4, 0xB4, 0x04,
0x82, 0x01, 0x81, 0x94, 0x84, 0xB4, 0xA4, 0x04,
0x82, 0x01, 0x81, 0x94, 0x84, 0xC4, 0xB4, 0x04,
0x82, 0x01, 0x81, 0xF4, 0xD4, 0xB4, 0xA4, 0x94,
0xE2, 0x01, 0xE1, 0xD4, 0xB4, 0xC4, 0xB4, 0x04,
0x00} ;
uchar TABLE1[]={
//音符对应的定时器初值表
0xfb, 0x04, 0xfb, 0x90, 0xfc, 0x09, 0xfc, 0x44,
0xfc, 0xac, 0xfd, 0x09, 0xfd, 0x34, 0xfd, 0x82,
0xfd, 0xc8, 0xfe, 0x06, 0xfe, 0x22, 0xfe, 0x56,
0xfe, 0x85, 0xfe, 0x9a, 0xfe, 0xc1};

//T0中断服务函数
timer0() interrupt 1 using 1{
TL0=tl;TH0=th;//重装定时初值
BEEP=~ BEEP;//喇叭输出端口电平取反
}

//基本单位延时函数
void delay1 () {
uint i;
for (i=0; i<20000;i++) ;
}
//节拍延时函数
void delay(tt) {
uchar i;
for (i=0;i<=tt;i++)
delay1();
}

void main() {
uchar t,t1,k=0;//定义临时变量
while(1) {
TMOD=0x01; IE=0x82;//定义TO工作方式,开中断
while (TABLE[k]!=0){ //判断取得的音符节拍码是否为结束码
tick= (TABLE[k])&0x0f;//不是,则取节拍码
t=(_crol_(TABLE[k],4))&0x0f; //取音符码
if(t!=0) {//判断取得的音符码是否为0
    t1=--t*2+1;//不是,则根据取得的音符码计算TO初值
    t=t*2;
    t1=TL0=TABLE1 [t1];
    th=TH0=TABLE1[t];
    TR0=1;//启动TO
}
else TR0=0;//取得的音符码为0,则停止T0
delay(tick) ;//根据则取得的节拍码延时
k++;
}

    TR0=0;//取得结束码,则停止TO
  }
}

使用Proteus仿真电路进行仿真,点击Play按钮执行程序,从计算机的音箱中听到“生日快乐”乐曲:

 

  • 7
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值