51单片机学习--蜂鸣器播放音乐

评论区别江科协江科协地喊了,这是我自己看他的视频做的学习笔记,记录在这个平台上而已,我又没盈利单纯为了方便我自己复习用的,勿扰好吗。
用的在这里插入图片描述
在这里插入图片描述
由原理图可知,蜂鸣器BEEP与P1_5 相关,但其实这个原理图有错,实测接的是P2_5
下面这个代码就是以500HZ的频率响500ms的例子

sbit Buzzer = P2^5;

unsigned char KeyNum;
unsigned int i;

void main()
{
	while(1)
	{
		KeyNum = Key();
		if(KeyNum)
		{
			for(i = 0; i < 500; i ++) {
				Buzzer = !Buzzer;
				Delay(1);// 1ms翻转一次,周期就是2ms,频率就是500HZ 
			} //一共会响500ms
			
		}
		
	}
}

接下来先把这个发出声响的代码封装成Buzzer模块,接下来的目标是实现发出不同音调的声响



在这里插入图片描述
先来看用定时器实现的蜂鸣器发生,每次中断就翻转一次Buzzer,中断每1ms执行一次,所以翻转周期是2ms,音调一样

#include <REGX52.H>
#include "Timer0.h"
#include "Delay.h"


sbit Buzzer = P2^5;



void main()
{
	Timer0_Init();
	
	while(1)
	{
		
	}
}


void Timer0_Routine() interrupt 1
{
	TL0 = 0x66;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	Buzzer = !Buzzer;
}

只要更改中断函数中的定时初值,翻转需要的的时长就会变化,从而改变声音的周期进而改变音调
在这里插入图片描述
比如中央C的重装载值是64580,这个声调对应的初值如下

void Timer0_Routine() interrupt 1
{
	TL0 = 64580 % 256;		//设置定时初值
	TH0 = 64580 / 256;		//设置定时初值
	Buzzer = !Buzzer;
}

接下来只要稍微费点力气,把所有重装载值整理到一个数组里,使数组的每个序号对应一个音调,需要的时候调用序号就行

unsigned int FreqTable[] = { //中央C以及高八度低八度的音调由低到高
	63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
	64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
	65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283
};

扒出小星星的简谱,把音调对应的数组序号存到一个Music数组里,按序遍历这个数组就能比较完整地播放一首小星星啦

#include <REGX52.H>
#include "Timer0.h"
#include "Delay.h"


sbit Buzzer = P2^5;

unsigned int FreqTable[] = {
	63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
	64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
	65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283
};

unsigned char FreqSelect, MusicSelect;

unsigned char Music[] = {12,12,19,19,21,21,19,17,17,16,16,14,14,12};
//小星星简谱音调对应的数组下标(前两句)

void main()
{
	Timer0_Init();
	
	while(1)
	{
		FreqSelect = Music[MusicSelect];
		MusicSelect ++;
		Delay(500); //音符时长,可修改
		TR0 = 0; //定时器关闭,自然停顿,否则两个连音之间没有了间隔
		Delay(5);
		TR0 = 1; //定时器开启
	}
}


void Timer0_Routine() interrupt 1
{
	TL0 = FreqTable[FreqSelect] % 256;		//设置定时初值
	TH0 = FreqTable[FreqSelect] / 256;		//设置定时初值
	Buzzer = !Buzzer;
}


但这样还不完美,每个音符只能固定地响500ms,想要自主控制音符的时长,则又需要一个数组来记录每个音符的长度!十六分音符记为1,八分音符记为2,四分音符记为4。。。。。

#include <REGX52.H>
#include "Timer0.h"
#include "Delay.h"


sbit Buzzer = P2^5;

unsigned int FreqTable[] = {
	63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
	64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
	65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283
};

unsigned char FreqSelect, MusicSelect;

unsigned char Music[] = {12,12,19,19,21,21,19,17,17,16,16,14,14,12};
//小星星简谱音调对应的数组下标(前两句)

unsigned char Music2[] ={4,4,4,4,4,4,8,4,4,4,4,4,4,8};
//每个音符的时长

void main()
{
	Timer0_Init();
	
	while(1)
	{
		FreqSelect = Music[MusicSelect];
		Delay(125 * Music2[MusicSelect]);
		MusicSelect ++;
		TR0 = 0; //定时器关闭,自然停顿,否则两个连音之间没有了间隔
		Delay(5);
		TR0 = 1; //定时器开启
	}
}


void Timer0_Routine() interrupt 1
{
	TL0 = FreqTable[FreqSelect] % 256;		//设置定时初值
	TH0 = FreqTable[FreqSelect] / 256;		//设置定时初值
	Buzzer = !Buzzer;
}


最后还有一点,歌曲中不是一直都有声音的,所以需要有休止符,不发声,在音调数组的最后加上一个0,这样Music数组中也能存休止符了,中断函数中特判一下,不为0时才发声
以下就是一个比较完整地蜂鸣器播放音乐的代码了!

#include <REGX52.H>
#include "Timer0.h"
#include "Delay.h"


sbit Buzzer = P2^5;

unsigned int FreqTable[] = {
	63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
	64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
	65058,65085,65110,65134,65157,65178,65198,65217,65235,65252,65268,65283,
	0
}; //最后一个是休止符

unsigned char FreqSelect, MusicSelect;

unsigned char Music[] = {12,12,19,19,21,21,19,17,17,16,16,14,14,12};
//小星星简谱音调对应的数组下标(前两句)

unsigned char Music2[] ={4,4,4,4,4,4,8,4,4,4,4,4,4,8};
//每个音符的时长

void main()
{
	Timer0_Init();
	
	while(1)
	{
		FreqSelect = Music[MusicSelect];
		Delay(125 * Music2[MusicSelect]);
		MusicSelect ++;
		TR0 = 0; //定时器关闭,自然停顿,否则两个连音之间没有了间隔
		Delay(5);
		TR0 = 1; //定时器开启
	}
}


void Timer0_Routine() interrupt 1
{
	if(FreqTable[FreqSelect] != 0) //若不为休止符
	{
		TL0 = FreqTable[FreqSelect] % 256;		//设置定时初值
		TH0 = FreqTable[FreqSelect] / 256;		//设置定时初值
		Buzzer = !Buzzer;
	}
}

最后一个问题,当歌曲音符比较多变化复杂的时候,数据量巨大,数组存不下,那么就要用到之前的方法,在Music数组前加上关键字code ,把数据存到flash里面,同时使数据变成只可读取,不可更改

C51单片机是一种基于8051内核的单片机,广泛应用于嵌入式系统的开发。在使用C51单片机控制蜂鸣器播放音乐时,通常会涉及到定时器的使用以及音乐节奏和音调的生成。 具体来说,可以通过以下步骤来实现: 1. 初始化定时器:选择合适的定时器,并对其进行初始化设置,用于产生准确的时间间隔,控制音乐的节奏。 2. 音符频率设置:将不同的音符对应到不同的频率上,可以通过设置定时器的计数值来改变蜂鸣器的输出频率,从而发出不同的音调。 3. 音乐序列编写:根据想要播放的乐曲,将音符按照正确的顺序排列,每个音符代表蜂鸣器发出的一个音。 4. 循环播放:通过循环结构,依次执行每个音符的播放指令,这样就可以连续播放整首乐曲了。 5. 控制音量:有的情况下可能还需要通过调整PWM波形的占空比来控制音量大小。 下面是一个简化的代码示例,用于演示如何通过C51单片机控制蜂鸣器播放简单的音调序列: ```c #include <reg51.h> // 定义音符频率,这里只是示例值,实际值需要根据蜂鸣器特性调整 #define NOTE_C 956 #define NOTE_D 851 #define NOTE_E 758 #define NOTE_F 716 // 定义蜂鸣器连接的端口 sbit Buzzer = P1^0; // 定时器初始化函数 void Timer0_Init() { TMOD |= 0x01; // 设置定时器模式为模式1 EA = 1; // 开启全局中断 ET0 = 1; // 开启定时器0中断 } // 定时器中断服务程序,用于控制音符的播放 void Timer0_ISR() interrupt 1 { static unsigned int count = 0; TH0 = (65536 - count) >> 8; // 重新加载定时器初值 TL0 = (65536 - count) & 0xFF; Buzzer = !Buzzer; // 翻转蜂鸣器端口状态,产生声音 } // 主函数 void main() { Timer0_Init(); // 初始化定时器 while(1) { // 播放一段音符序列 count = NOTE_C; TR0 = 1; // 启动定时器 Delay(1000); // 延时函数,保持当前音符播放一定时间 TR0 = 0; // 停止定时器 count = NOTE_D; TR0 = 1; // 重新启动定时器 Delay(1000); TR0 = 0; // ... 播放其他音符 } } // 延时函数 void Delay(unsigned int ms) { // ... 实现具体的延时代码,可以使用定时器或循环来完成 } ``` 这个代码中,我们设置了一个简单的延时函数`Delay`和一个定时器中断服务程序`Timer0_ISR`来控制蜂鸣器。在主函数中,我们通过设置不同的频率来控制蜂鸣器发出不同的音调,并通过延时函数来控制音乐的节奏。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silver_Bullet14

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值