用51单片机演奏Beyond《海阔天空》

最近笔者在学习51单片机的使用,在学到蜂鸣器的时候突发奇想,想要演奏Beyond的《海阔天空》,但在网上找不到相关的源码,故便自己参考B站up主@江科大自化协的视频即源码整理了一下实现思路,文中如果出现了什么问题还望大家指出。另外我会把源码,excel文件以及运行出的hex文件放到Github上,欢迎大家前来star

源码及excel地址:https://github.com/udbbdh/51-beyond-.git

演示视频地址:用51单片机演奏《海阔天空》_哔哩哔哩_bilibili


前言

        最近笔者在学习51单片机的使用,在学到蜂鸣器的时候突发奇想,想要演奏Beyond的《海阔天空》,但在网上找不到相关的源码,故便自己整理了一下实现思路,连带着源码一起在此分享给大家,欢迎大家多多点赞收藏。


一、51单片机的蜂鸣器原理的简要介绍

        蜂鸣器大致可以分为有源蜂鸣器和无源蜂鸣器两大类(其中的“源”指的是震荡源而非电源),而蜂鸣器正是通过震荡源的震荡来发声的。对于有源蜂鸣器来说,由于它自带震荡源,其振荡频率是固定的,所以只能发出特定频率的声音(即发出的声音频率无法改变)。对于无源蜂鸣器来说,它内部没有自带震荡源,可以利用定时器来控制震荡的周期,进而改变声音的频率,使其发出不同音调的声音。我所用的单片机为普中STC89C52R,集成的蜂鸣器为无源蜂鸣器,因此可以发出不同音调的声音,具有演奏音乐的能力。

如果还想要对51单片机蜂鸣器进行更细致的学习,大家可以参考官方给的资料。

二、思路步骤

1.根据晶振频率计算定时器的重载值

        晶振频率可以从单片机上读出,是单片机内部用于产生定时的设备,但由于51单片机的定时器所产生的频率只能够是晶振频率的1/12,故定时器的实际频率为11.0592/12MHz。

        如果我们想要发出一个音调的声音,只需要查到那个声音的频率f,再控制定时器的重载值即可。

        举个例子,假如要发出f=440Hz的声音,则该音调的声音的周期T=1/f=2272.73us,对于方型波来说,也就是每半个周期波形变化一次,因此定时器需要定时0.5T=1136.36us。定时器是通过计数进行定时的,计数范围为0~65535,上面我们提到,计时器的是实际频率为(11.0592/12)MHz,所以定时器每次+1所需要的时间为1s/(11.0592/12MHz)=1.085us,所以要记时0.5T就需要计数0.5T/1.085us,即1136.36/1.085=1047.33次,取整之后即1047次。又由于定时器是溢出才知道到时间了的,所以我们需要从(65536-1047=64489)开始计时,所以定时器TH0=int(64489/256)=251,TL0=int(64489%256)=232,这样定时器就配置好了。

        如果是一个一个进行计算的话会十分的麻烦,推荐使用EXCEL进行计算,如下图所示

2.Keil5代码思路

首先我们要看开发板的原理图里面给出的蜂鸣器的端口

我这里是p2_5端口,所以下面就应该是p2^5。 

sbit Buzzer=p2^5;//对p2^5端口进行命名,类似于define

 之后建立一个数组,用于储存EXCEL中计算得到的定时器的重载值。

unsigned int FreqTable[]={
	0,
	63776,63871,63968,64053,64139,64215,64290,64359,64425,64488,64546,64602,
	64654,64703,64750,64794,64836,64875,64912,64947,64980,65011,65041,65069,
	65095,65119,65143,65165,65186,65205,65224,65241,65258,65273,65288,65302,
};//从63776~65302分别表示从低音1到高音7

 之后就是根据乐谱再定义一个数组,把每一个音调都用它在数组FreqTable数组中的索引来表示,但一个个去对应会十分麻烦,所以我们用define来简化对应关系的寻找

#define P	0
#define L1	1
#define L1_	2
#define L2	3
#define L2_	4
#define L3	5
#define L4	6
#define L4_	7
#define L5	8
#define L5_	9
#define L6	10
#define L6_	11
#define L7	12
#define M1	13
#define M1_	14
#define M2	15
#define M2_	16
#define M3	17
#define M4	18
#define M4_	19
#define M5	20
#define M5_	21
#define M6	22
#define M6_	23
#define M7	24
#define H1	25
#define H1_	26
#define H2	27
#define H2_	28
#define H3	29
#define H4	30
#define H4_	31
#define H5	32
#define H5_	33
#define H6	34
#define H6_	35
#define H7	36

 之后就开始定义谱子

unsigned char code Music[]={
	//音符,时值,
	M7,4,
	H4,4,
	H3,8,
	
	H2,2,
	H1,2,
	M7,2,
	M6,4,
	M4,2,
	M5,2,
	H1,2,
	M4,2,
	P,2,
	M3,4,
	
	
	P,2,
	M4,2,
	M5,2,
	H1,2,
	M4,2,
	P,2,
	M3,4,
	//
	P,2,
	M4,2,
	M5,2,
	H2,2,
	
	H1,6,
	M4,6,
	M7,4,
	M6,6,
	
	P,3,
	//今天我
	M3,2,
	M2,2,
	M1,8,
	P,4,
	M2,1,
	M3,1,
	
	M5,2,
	M5,1,
	M5,1+2,
	M6,2,
	M5,4,
	P,2,
	M6,1,
	M7,1,
	
	H1,2,
	H1,1,
	H1,1+2,
	H1,2,
	H1,2,
	M7,2,
	M6,1,
	M5,2,
	M6,9,
	
	P,4,
	
	M6,2,
	M5,2,
	
	M5,6,
	M5,2,
	M3,1,
	M2,1,
	M1,2,
	M3,2,
	M4,2,
	
	
	M3,2,
	M2,2,
	M2,2,
	M3,1,
	M2,1+4,
	M3,2,
	M2,1,
	M2,3,
	
	
	M1,2,
	M1,2,
	M1,1,
	M1,5,
	M2,2,
	M1,2,
	
	M1,6,
	
	P,6,
	M6,1,
	M7,1,
	
	H1,2,
	H1,1,
	H1,3,
	H1,2,
	M7,2,
	M6,2,
	M5,1,
	M5,3,
	
	M5,4,
	M3,2,
	M2,2,
	M1,4,
	
	//也会怕有一天会跌倒
	P,2,
	H1,1,
	H1,1,
	H1,2,
	H1,1,
	H2,1,
	H2,2,
	H2,2,
	H1,1,
	H2,2,
	H3,6,
	P,2,
	H3,3,
	H2,2,
	H1,1,

	
	P,6,
	H1,1,
	H1,1,
	H1,2,
	H1,1,
	H2,3,
	P,2,
	M5,1,
	M5,1,
	
	
	
	H3,4,
	H2,4,
	H1,8,
	
	P,2,
	H1,1,
	H1,1,
	H1,2,
	H1,1,
	H2,3,
	H2,1,
	H2,1,
	H1,1,
	M7,2,
	H1,9,
	
	
	//仍然自由自我
	P,4,
	M6,2,
	M6,2,
	M7,2,
	M6,2,
	M7,2,
	H1,8,
	
	//永远高唱我歌
	H1,1,
	H1,1,
	H2,2,
	H1,2,
	H2,2,
	H3,8,
	
	//走遍千里
	H3,2,
	H2,6,
	H3,2,
	H1,8,
	
	
	//原谅我
	P,2,
	M6,1,
	M7,1,
	
	H1,2,
	H1,1,
	H1,3,
	H1,2,
	M7,2,
	M6,2,
	M5,1,
	M5,3,
	
	M5,4,
	M3,2,
	M2,2,
	M1,4,
	
	P,4,
	H1,1,
	H1,1,
	H1,2,
	H1,1,
	H2,1,
	H2,2,
	H2,2,
	H1,1,
	H2,2,
	H3,9,
	
	
	H3,3,
	H2,2,
	H1,1,
	
	P,2,
	H1,1,
	H1,1,
	H1,2,
	H1,1,
	H2,3,
	P,2,
	M5,1,
	M5,1,
	
	H3,4,
	H2,4,
	H1,8,
	
	P,2,
	H1,1,
	H1,1,
	H1,2,
	H1,1,
	H2,3,
	H2,1,
	H2,1,
	H1,1,
	M7,2,
	H1,9,
	
	0xFF	//终止标志
};

然后定义计时器的主函数和中断

#define SPEED	700
unsigned int FreqSelect,MusicSelect;

void main()
{
	Timer0Init();
	while(1)
	{
		if(Music[MusicSelect]!=0xFF)	//如果不是停止标志位
		{
			FreqSelect=Music[MusicSelect];	//选择音符对应的频率
			MusicSelect++;
			Delay(SPEED/4*Music[MusicSelect]);	//选择音符对应的时值
			MusicSelect++;
			TR0=0;//TR0=0表示不允许计数
			Delay(5);	//音符间短暂停顿
			TR0=1;//TR0=0表示允许计数
		}
		else	//如果是停止标志位
		{
			TR0=0;
			while(1);
		}
	}
}

void Timer0_Routine() interrupt 1
{
	if(FreqTable[FreqSelect])	//如果不是休止符
	{
		/*取对应频率值的重装载值到定时器*/
		TL0 = FreqTable[FreqSelect]%256;		//设置定时初值
		TH0 = FreqTable[FreqSelect]/256;		//设置定时初值
		Buzzer=!Buzzer;	//翻转蜂鸣器IO口
	}
}


总结

以上就是今天要讲的内容,本文仅仅简单介绍了如何利用蜂鸣器演奏《海阔天空》,最艰难的工作就在于自己一个一个根据谱子找音符了,网上很多谱子听起来怪怪的,所以我只能根据原曲来一点点调,用这首歌纪念家驹!

  • 9
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值