51单片机嵌入式开发:15、STC89C52RC操作蜂鸣器实现一个music音乐播放器的音乐盒

news2024/11/15 18:06:07

STC89C52RC操作蜂鸣器实现一个music音乐播放器的音乐盒

  • 1 概述
  • 2 蜂鸣器操作方法
  • 3 蜂鸣器发出音声
  • 4 硬件电路
  • 5 软件实现
  • 6 整体工程:
  • 7 总结


在这里插入图片描述

1 概述

要实现一个基于STC89C52RC单片机的音乐盒,可以按照以下步骤进行:
(1)硬件连接:
将蜂鸣器连接到STC89C52RC单片机的一个IO口上(例如P1.0)。
连接其他必要的硬件,如按键、LCD显示屏等,以实现音乐盒的控制和用户交互功能。
(2)音乐文件准备:
将音乐文件转换为适合播放的格式,例如将音乐转换为一系列音符和节拍的组合。
将转换后的音乐数据保存在单片机的程序或外部存储器中(如EEPROM或Flash存储器)。
(3)编写程序:
使用C语言编写程序来控制STC89C52RC单片机的功能。
初始化必要的硬件接口,如IO口和定时器等。
编写播放音乐的函数,根据音乐数据控制蜂鸣器发声。
编写与用户交互的代码,如按键控制、显示当前播放状态等。
考虑使用定时器来控制音乐的节奏和节拍。
(4)主循环:
在主循环中实现音乐盒的逻辑控制。
监测用户的输入,根据输入进行相应的操作,如播放、暂停、停止、切换曲目等。
调用相应的函数来控制蜂鸣器发声和更新LCD显示。
(5)调试和优化:
进行测试和调试,确保音乐盒的各项功能正常工作。
根据需要进行性能优化,如减小程序体积、优化音乐数据存储等。
请注意,以上步骤只是一个概述,并不包含具体的代码实现。实际开发中需要根据具体需求和硬件环境进行详细的设计和编码。
在具体实现过程中,可以借助STC89C52RC单片机的IO口控制蜂鸣器输出声音,并使用定时器来控制音乐的节奏和节拍。此外,还可以添加其他功能,如音量控制、曲目选择、循环播放等,以增强音乐盒的功能和用户体验。

2 蜂鸣器操作方法

在C51单片机中操作蜂鸣器的方法通常是通过控制相应的IO口输出高低电平信号来实现。以下是一种常见的方法:
首先,确定连接蜂鸣器的IO口,假设为P1.0。
然后,按照以下步骤进行操作:
设置IO口为输出模式:
P1 = P1 & 0xFE; // 将P1.0设置为输出
发出蜂鸣器声音:
P1 = P1 | 0x01; // 将P1.0置为高电平(蜂鸣器发声)
停止蜂鸣器声音:
P1 = P1 & 0xFE; // 将P1.0置为低电平(蜂鸣器停止发声)
根据具体的单片机型号和开发环境,上述代码可能需要适当修改。请确保已经正确设置了IO口的方向和状态,并且将蜂鸣器正确连接到相应的IO口。
另外,如果需要生成特定频率的声音,可以使用定时器来控制蜂鸣器的开关时间,从而实现不同频率的声音效果。这需要针对具体的单片机和定时器进行相应的配置和编程。
请注意,在使用蜂鸣器时,要特别注意电源和电流的要求,以防止对单片机和蜂鸣器造成损坏。确保根据蜂鸣器的规格和要求进行正确的电气连接和电流限制。
以上是一种简单的方法来操作蜂鸣器,具体的实现可能会因单片机型号、开发环境和需求而有所不同。

3 蜂鸣器发出音声

蜂鸣器通常通过控制电流或电压的变化来产生不同的声音效果。通过改变电流或电压的频率、持续时间和幅度,可以产生不同频率和音调的声音。
在嵌入式系统中,控制蜂鸣器发声通常通过单片机或其他电路来实现。通过控制相应的IO口输出高低电平信号或调节PWM(脉冲宽度调制)信号,可以控制蜂鸣器的开关和声音的频率,从而产生不同的音效。具体的控制方法可以根据蜂鸣器类型和使用的电路进行调整和实现。
(1)为了尽可能还原音乐,国际标准音高包含了多个音高,使用了哆唻咪发嗦来嘻(表中用1234567)的音符,并对应不同的频率。为了模拟这些音高,下表列出了9个频率对应的音高。

在这里插入图片描述

(2)接下来,我们可以在Excel表格中使用以下公式来快速计算各个音高对应的计数值:T = 65535 - (1 / (频率 * 2 * 1.0851)) + 1。下图显示了上述频率对应的计数值:

在这里插入图片描述

(3)到这一步,还需要将之前计算得到的十进制计数值转换为十六进制计数值,因为51单片机的定时器计数值由高位和低位两部分组成。为了实现这个转换,我们可以在Excel中使用函数=DEC2HEX(单元格)来将对应单元格的十进制计数值转换为十六进制计数值。下图显示了之前计算得到的十进制计数值对应的十六进制计数值:

在这里插入图片描述

4 硬件电路

根据原理图所示:
控制引脚需要跳线到J18的第七引脚,才能控制喇叭。

在这里插入图片描述

5 软件实现

(1)定时器
为了实现音乐的还原,我们使用定时器来还原音高,并使用延时函数来还原音长。设计采用定时器中断产生一定频率的方波信号,驱动无源蜂鸣器来还原音高。同时,延时函数用于控制该频率的维持时间,从而还原音长。通过这样的方式,我们可以实现简谱中一个音符的还原,将它们连贯起来就能还原整段音乐。
根据表格添加音高对应的定时器计数值常量至ROM(9个音高)

code unsigned char yingaoh[63]={
0x92,0xC8,0xE4,0xF2,0xF9,0xFC,0xFE,0xFF,0xFF, //音符1的9个音高
0x9E,0xCE,0xE7,0xF3,0xF9,0xFC,0xFE,0xFF,0xFF,	//音符2的9个音高
0xA8,0xD4,0xEA,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符3的9个音高
0xAD,0xD6,0xEB,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符4的9个音高
0XB6,0XDB,0XED,0XF6,0XFB,0XFD,0XFE,0XFF,0XFF, //音符5的9个音高
0XBE,0XDF,0XEF,0XF7,0XFB,0XFD,0XFE,0XFF,0XFF, //音符6的9个音高
0XC5,0XE2,0XF1,0XF8,0XFC,0XFE,0XFF,0XFF,0XFF, //音符7的9个音高
}; //7个音符的9个八度高位计数值
code unsigned char yingaol[63]={
0x3C,0xF3,0x79,0x3C,0x1E,0x8F,0x47,0x23,0x91, //音符1的9个音高
0x2A,0xF3,0x79,0xBC,0xDE,0xEF,0x77,0x3B,0x9D,	//音符2的9个音高
0x9D,0x4E,0x27,0x13,0x89,0x45,0xA2,0x51,0xA8, //音符3的9个音高
0x6D,0xCE,0x61,0xB0,0xD8,0x6C,0xB6,0x5B,0xAD, //音符4的9个音高
0X86,0X43,0XA1,0XD0,0X68,0XB4,0XDA,0X6D,0XB6, //音符5的9个音高
0X8A,0X45,0XA2,0XD1,0XE8,0XF4,0XFA,0X7D,0XBE, //音符6的9个音高
0XBE,0XD3,0X6C,0XB5,0X5A,0X2D,0X16,0X8B,0XC5,	//音符7的9个音高
}; 7个音符的9个八度低位计数值 

(2)添加音乐对应的单片机代码(爱拼才会赢)
其中,music[0]代表节拍数,music[1]代表每分钟的节拍数。数组的结尾放入0表示音乐的结束。数组中的其他值按顺序每两个值表示一个音高和维持的时间(需要通过换算计算出实际时间)。。

code unsigned char music[]={
4,89,
5,4,2,5,4,1,6,4,1,
1,5,6,6,4,2,5,4,2,
6,4,1,1,5,1,6,4,2,
5,4,2,3,4,12,3,4,2,
3,4,1,5,4,1,6,4,6,
1,5,2,5,4,2,3,5,2,
3,5,1,2,5,1,1,5,2,
2,5,12,1,5,2,2,5,2,
3,5,2,3,5,2,2,5,2,
3,5,1,2,5,1,1,5,6,
6,4,1,1,5,1,2,5,2,
2,5,2,2,5,1,1,5,1,
6,4,2,5,4,8,6,4,2,
5,4,1,6,4,1,5,4,2,
1,5,2,6,4,2,5,4,2,
3,4,2,1,4,4,2,4,12,
1,4,2,2,4,2,3,4,6,
5,4,2,5,4,2,3,4,2,
1,5,2,7,4,2,6,4,6,
6,4,2,6,4,4,1,5,2,
2,5,1,3,5,1,5,5,4,
3,5,4,2,5,2,1,5,2,
5,4,2,1,5,2,2,5,1,
3,5,1,2,5,12,3,5,1,
2,5,1,1,5,4,2,5,1,
1,5,1,6,4,4,1,5,2,
3,4,1,1,5,1,1,5,2,
6,4,2,1,5,4,6,4,1,
5,4,1,3,4,2,5,4,16,
5,4,2,6,4,2,1,5,2,
6,4,2,6,4,8,3,5,2,
3,5,2,3,5,2,3,5,1,
2,5,1,2,5,6,2,5,1,
1,5,1,6,4,6,3,5,2,
2,5,4,1,5,1,2,5,1,
1,5,1,6,4,1,1,5,16,
5,4,2,6,4,2,1,5,6,
6,4,2,5,4,2,6,4,1,
1,5,1,6,4,2,5,4,2,
3,4,12,3,4,2,3,4,1,
5,4,1,6,4,6,1,5,2,
5,4,2,3,5,2,3,5,1,
2,5,1,1,5,2,2,5,12,
1,5,2,2,5,2,3,5,2,
3,5,2,2,5,2,3,5,1,
2,5,1,1,5,6,6,4,1,
1,5,1,2,5,2,2,5,2,
2,5,1,1,5,1,6,4,2,
5,4,8,6,4,2,5,4,1,
6,4,1,5,4,2,1,5,2,
6,4,2,5,4,2,3,4,2,
1,4,4,2,4,12,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,2,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,4,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,0

};

(3)实现音高的控制程序

//使用定时器方式,实现发音的频率来实现音高
void sys_music_init(void)
{
	TMOD=0x01;		//置T0定时器工作在方式1
	EA=1;			//开总中断
	ET0=1;			//开定时器0中断,这两句等效于IE=0x82
	TR0=1; 				//开定时器0
}


//音高模拟函数实际上就是利用定时器中断产生一定频率方波驱动蜂鸣器发出一定频率的声音。

void music_t0_isr() interrupt 1 //定时器0中断函数
{
	TR0=0;		 //关闭定时器TR0

	BEEP=!BEEP;	 //蜂鸣状态取反

	TH0=timeh;	 //把timeh赋给定时0高位计数值

	TL0=timel;	 //把timel赋给定时0低位计数值

	TR0=1;	   //开定时器TR0
}
void music_delay(unsigned int t)  //节拍延时函数
{
	//根据每分钟节拍数,求解四分之一音符保持时长,四舍五入单位为10ms 
	unsigned int time;
	unsigned int time_tmp = 0;
	
	
	//1000*((60/M1)) *t/M0
	
	time_tmp = (unsigned int)music[1]*(unsigned int)music[0];

	//time=15000UL*t/time_tmp; //根据节拍算出10ms的计数次数 
	time = 80*t;
	
	delay_ms(time);
	
	//TR0=0;
}

void sys_music_test(void)
{
	unsigned char m,n;
	m=(music[buf_i]-1)*9+music[buf_i+1]; 	//获取音符对应计数值所在下标
	n=music[buf_i+2]; 						//获取音符保持时长值
		
	timeh=yingaoh[m]; 						//获取音符对应定时器计数值高位
	timel=yingaol[m]; 						//获取音符对应定时器计数值低位
	
	TH0=timeh;	//把timeh赋给定时0高位计数值
	TL0=timel;	//把timel赋给定时0低位计数值
	
	//TR0=1; 				//开定时器0
	music_delay(n); 	//执行音符保持函数
	buf_i=buf_i+3;	  	//读下一个音符
	if(music[buf_i]==0) 
	{
		buf_i=2;	   	//如果到末尾则回到开头,循环播放
	}
}

6 整体工程:

在这里插入图片描述

//main.c文件

#include "includes.h"



/******************************************************************/
/*                    微秒延时函数  //10us                         */
/******************************************************************/
void delay_us(unsigned int us)//delay us
{
	while(us--)
	{
	}
}

/******************************************************************/
/*                    微秒延时函数                                */
/******************************************************************/
void delay_ms(unsigned int Ms)//delay us
{
	while(Ms--)
	{
		delay_us(100);
	}
}

/*------------------------------------------------
                    延时子程序
------------------------------------------------*/
void delay(unsigned int cnt) 
{
 while(--cnt);
}




/*------------------------------------------------
                    主函数
------------------------------------------------*/
void main (void)
{	
	sys_music_init();
	delay(10);
	delay_ms(1);
	
	sys_keynum_ledon(1,0);
	
	buf_i = 2;
	while(1)
	{
		sys_music_test();
	}
}

//includes.h文件

#ifndef __INCLUDES_H__
#define __INCLUDES_H__

//#include<reg52.h> 

#include<intrins.h> //汇编指令_nop_
#include<stdio.h> 	//标准输入输出

//_nop_(); 产生一条NOP指令
//作用:对于延时很短的,要求在us级的,采用“_nop_”函数,这个函数相当汇编NOP指令,延时几微秒。
//NOP指令为单周期指令,可由晶振频率算出延时时间。

//8051 为每个机器周期 12 时钟
//对于12M晶振,延时1uS。
//11.0592M晶振,延时1.0851uS。

//对于延时比较长的,要求在大于10us,采用C51中的循环语句来实现。


//包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "STC89C5xRC_RDP.h"

//应用层头文件
//#include "c51_gpio.h"
#include "c51_ledtube.h"
//#include "c51_key.h"
//#include "c51_timer.h"
//#include "c51_exit.h"
//#include "c51_lcd1602.h"
//#include "c51_iic.h"
//#include "c51_tx1838.h"
//#include "c51_uart.h"
#include "c51_music.h"


extern void delay(unsigned int cnt);
extern void delay_us(unsigned int us);//delay us;
extern void delay_ms(unsigned int Ms);//delay Ms;


#endif

//c51_ledtube.c文件

#include "includes.h"

// 显示段码值01234567,可对应原理图查看显示不同图形对应的引脚高点电平配置状态
unsigned char const EL[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,\
		                  	 0x77,0x7c,0x39,0x5e,0x79,0x71};//0-F



///********************************************************
//函数名称:sys_ledtube_on1
//函数功能:点亮一个数码管全为亮起来
//入口参数:
//出口参数:
//修    改:
//内    容:
//********************************************************/
//void sys_ledtube_on1(void)
//{
//	//根据原理图,将P0口全部输出高电平,P2选择0号数码管
//	P0=0xFF;//取显示数据,段码
//	P2=0;  	//取位码
//}

///********************************************************
//函数名称:sys_ledtube_on2
//函数功能:显示一组数据
//入口参数:
//出口参数:
//修    改:
//内    容:
//********************************************************/
//static unsigned char ledtube_cnt = 0;
//void sys_ledtube_on2(void)
//{
//	ledtube_cnt++;
//	if(ledtube_cnt>7)
//	{
//		ledtube_cnt = 0;
//	}
//	P0 = 0x00;				//防止切换数码管瞬间有虚影出现
//	P2 = 0x00;
//	P0 = EL[ledtube_cnt];	//取显示数据,段码
//	P2 = ledtube_cnt;  		//取位码
//	
//	//根据人眼适应虚影缓冲时间为50ms左右
//	//我们调整delay在500以下可以看到明显的看起来是一串数据一起显示
//	delay(100); 			
//}


/********************************************************
函数名称:sys_keynum_ledon
函数功能:显示按键数值
入口参数:按键数值
出口参数:
修    改:
内    容:
********************************************************/
void sys_keynum_ledon(unsigned char num,unsigned char pn)
{
	//根据原理图,将P0口全部输出高电平,P2选择0号数码管
	P0 = 0x00;		//防止切换数码管瞬间有虚影出现
	P2 = pn;  		//取位码
	P0 = EL[num];	//取显示数据,段码
}

//c51_music.c 文件

#include "includes.h"

unsigned char timeh=0;
unsigned char timel=0;//TR0计数器高位值、低位值
unsigned int buf_i = 2;



code unsigned char yingaoh[63]={
0x92,0xC8,0xE4,0xF2,0xF9,0xFC,0xFE,0xFF,0xFF, //音符1的9个音高
0x9E,0xCE,0xE7,0xF3,0xF9,0xFC,0xFE,0xFF,0xFF,	//音符2的9个音高
0xA8,0xD4,0xEA,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符3的9个音高
0xAD,0xD6,0xEB,0xF5,0xFA,0xFD,0xFE,0xFF,0xFF, //音符4的9个音高
0XB6,0XDB,0XED,0XF6,0XFB,0XFD,0XFE,0XFF,0XFF, //音符5的9个音高
0XBE,0XDF,0XEF,0XF7,0XFB,0XFD,0XFE,0XFF,0XFF, //音符6的9个音高
0XC5,0XE2,0XF1,0XF8,0XFC,0XFE,0XFF,0XFF,0XFF, //音符7的9个音高
}; //7个音符的9个八度高位计数值

code unsigned char yingaol[63]={
0x3C,0xF3,0x79,0x3C,0x1E,0x8F,0x47,0x23,0x91, //音符1的9个音高
0x2A,0xF3,0x79,0xBC,0xDE,0xEF,0x77,0x3B,0x9D,	//音符2的9个音高
0x9D,0x4E,0x27,0x13,0x89,0x45,0xA2,0x51,0xA8, //音符3的9个音高
0x6D,0xCE,0x61,0xB0,0xD8,0x6C,0xB6,0x5B,0xAD, //音符4的9个音高
0X86,0X43,0XA1,0XD0,0X68,0XB4,0XDA,0X6D,0XB6, //音符5的9个音高
0X8A,0X45,0XA2,0XD1,0XE8,0XF4,0XFA,0X7D,0XBE, //音符6的9个音高
0XBE,0XD3,0X6C,0XB5,0X5A,0X2D,0X16,0X8B,0XC5,	//音符7的9个音高
}; //7个音符的9个八度低位计数值 


code unsigned char music[]={
4,89,
5,4,2,5,4,1,6,4,1,
1,5,6,6,4,2,5,4,2,
6,4,1,1,5,1,6,4,2,
5,4,2,3,4,12,3,4,2,
3,4,1,5,4,1,6,4,6,
1,5,2,5,4,2,3,5,2,
3,5,1,2,5,1,1,5,2,
2,5,12,1,5,2,2,5,2,
3,5,2,3,5,2,2,5,2,
3,5,1,2,5,1,1,5,6,
6,4,1,1,5,1,2,5,2,
2,5,2,2,5,1,1,5,1,
6,4,2,5,4,8,6,4,2,
5,4,1,6,4,1,5,4,2,
1,5,2,6,4,2,5,4,2,
3,4,2,1,4,4,2,4,12,
1,4,2,2,4,2,3,4,6,
5,4,2,5,4,2,3,4,2,
1,5,2,7,4,2,6,4,6,
6,4,2,6,4,4,1,5,2,
2,5,1,3,5,1,5,5,4,
3,5,4,2,5,2,1,5,2,
5,4,2,1,5,2,2,5,1,
3,5,1,2,5,12,3,5,1,
2,5,1,1,5,4,2,5,1,
1,5,1,6,4,4,1,5,2,
3,4,1,1,5,1,1,5,2,
6,4,2,1,5,4,6,4,1,
5,4,1,3,4,2,5,4,16,
5,4,2,6,4,2,1,5,2,
6,4,2,6,4,8,3,5,2,
3,5,2,3,5,2,3,5,1,
2,5,1,2,5,6,2,5,1,
1,5,1,6,4,6,3,5,2,
2,5,4,1,5,1,2,5,1,
1,5,1,6,4,1,1,5,16,
5,4,2,6,4,2,1,5,6,
6,4,2,5,4,2,6,4,1,
1,5,1,6,4,2,5,4,2,
3,4,12,3,4,2,3,4,1,
5,4,1,6,4,6,1,5,2,
5,4,2,3,5,2,3,5,1,
2,5,1,1,5,2,2,5,12,
1,5,2,2,5,2,3,5,2,
3,5,2,2,5,2,3,5,1,
2,5,1,1,5,6,6,4,1,
1,5,1,2,5,2,2,5,2,
2,5,1,1,5,1,6,4,2,
5,4,8,6,4,2,5,4,1,
6,4,1,5,4,2,1,5,2,
6,4,2,5,4,2,3,4,2,
1,4,4,2,4,12,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,2,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,1,4,2,
2,4,2,3,4,6,5,4,2,
5,4,2,3,4,2,1,5,2,
7,4,2,6,4,6,6,4,2,
6,4,4,1,5,2,2,5,1,
3,5,1,5,5,4,3,5,4,
2,5,2,1,5,2,5,4,2,
1,5,2,2,5,1,3,5,1,
2,5,12,3,5,1,2,5,1,
1,5,4,2,5,1,1,5,1,
6,4,4,1,5,2,3,4,1,
1,5,1,1,5,2,6,4,2,
1,5,4,6,4,1,5,4,1,
3,4,2,5,4,16,5,4,2,
6,4,2,1,5,2,6,4,2,
6,4,8,3,5,2,3,5,2,
3,5,2,3,5,1,2,5,1,
2,5,6,2,5,1,1,5,1,
6,4,6,3,5,2,2,5,4,
1,5,1,2,5,1,1,5,1,
6,4,1,1,5,16,0

};


//使用定时器方式,实现发音的频率来实现音高
void sys_music_init(void)
{
	TMOD=0x01;		//置T0定时器工作在方式1
	EA=1;			//开总中断
	ET0=1;			//开定时器0中断,这两句等效于IE=0x82
	TR0=1; 				//开定时器0
}


//音高模拟函数实际上就是利用定时器中断产生一定频率方波驱动蜂鸣器发出一定频率的声音。

void music_t0_isr() interrupt 1 //定时器0中断函数
{
	TR0=0;		 //关闭定时器TR0

	BEEP=!BEEP;	 //蜂鸣状态取反

	TH0=timeh;	 //把timeh赋给定时0高位计数值

	TL0=timel;	 //把timel赋给定时0低位计数值

	TR0=1;	   //开定时器TR0
}



void music_delay(unsigned int t)  //节拍延时函数
{
	//根据每分钟节拍数,求解四分之一音符保持时长,四舍五入单位为10ms 
	unsigned int time;
	unsigned int time_tmp = 0;
	
	
	//1000*((60/M1)) *t/M0
	
	time_tmp = (unsigned int)music[1]*(unsigned int)music[0];

	//time=15000UL*t/time_tmp; //根据节拍算出10ms的计数次数 
	time = 168*t;
	
	delay_ms(time);
	
	//TR0=0;
}

void sys_music_test(void)
{
	unsigned char m,n;
	m=(music[buf_i]-1)*9+music[buf_i+1]; 	//获取音符对应计数值所在下标
	n=music[buf_i+2]; 						//获取音符保持时长值
		
	timeh=yingaoh[m]; 						//获取音符对应定时器计数值高位
	timel=yingaol[m]; 						//获取音符对应定时器计数值低位
	
	TH0=timeh;	//把timeh赋给定时0高位计数值
	TL0=timel;	//把timel赋给定时0低位计数值
	
	//TR0=1; 				//开定时器0
	music_delay(n); 	//执行音符保持函数
	buf_i=buf_i+3;	  	//读下一个音符
	if(music[buf_i]==0) 
	{
		buf_i=2;	   	//如果到末尾则回到开头,循环播放
	}
}

//c51_music.h文件

#ifndef __C51_MUSIC_H__
#define __C51_MUSIC_H__


#define BEEP	P12


extern unsigned char timeh;
extern unsigned char timel;//TR0计数器高位值、低位值

extern unsigned int buf_i;

extern void sys_music_init(void);
extern void music_t0_isr();
extern void music_delay(unsigned int t);  //节拍延时函数
extern void sys_music_test(void);



#endif

//c51_ledtube.h文件

#ifndef __C51_LEDTUBE_H__
#define __C51_LEDTUBE_H__


extern unsigned char const EL[];

//extern void sys_ledtube_on1(void);
//extern void sys_ledtube_on2(void);

extern void sys_keynum_ledon(unsigned char num,unsigned char pn);


#endif


 

7 总结

蜂鸣器操作的一般总结:
(1)硬件连接:
将蜂鸣器连接到单片机的一个IO口上,通常使用GPIO口。
(2)初始化:
在程序开始时,需要对相关IO口进行初始化,将其配置为输出模式。
(3)发出声音:
要使蜂鸣器发出声音,将相应的IO口置高电平(或低电平,具体根据电路设计而定)即可。
通过控制IO口的电平状态,可以控制蜂鸣器的开关状态。
(4)延时:
要控制蜂鸣器发声的时间长度,可以使用延时函数。
在C51中,常用的延时函数包括delay、_nop_等,它们可以提供一定的延时效果。
(5)控制频率和音调:
要实现不同的频率和音调,可以使用定时器功能。
在C51中,可以通过配置定时器相关寄存器,设置定时器的工作方式、计数值和预分频等,从而控制定时器的频率和周期。
通过定时器中断,可以实现产生一定频率的方波信号,驱动蜂鸣器发声。
(6)停止声音:
要停止蜂鸣器的声音,将相应的IO口置低电平(或高电平)即可。
需要注意的是,具体的蜂鸣器操作步骤和代码实现可能会根据使用的单片机型号和编程环境而有所差异。在编写程序时,可以参考相关的单片机手册和编程指南,以及使用的开发工具提供的文档和示例代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1940032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第274题H指数

题目&#xff1a; 题解&#xff1a; func hIndex(citations []int) int {// 答案最多只能到数组长度left,right:0,len(citations)var mid intfor left<right{// 1 防止死循环mid(leftright1)>>1cnt:0for _,v:range citations{if v>mid{cnt}}if cnt>mid{// 要找…

ISO 14001:企业环境管理的黄金标准

在全球可持续发展潮流中&#xff0c;企业的环境责任愈发重要。ISO 14001环境管理体系&#xff0c;为各类企业提供了一条优化环境绩效的明路。无论企业规模大小&#xff0c;业务类型如何&#xff0c;ISO 14001都能帮助企业有效管理环境影响&#xff0c;实现绿色发展。 ISO 14001…

QT样式美化 之 qss入门

样例一 *{font-size:13px;color:white;font-family:"宋体"; }CallWidget QLineEdit#telEdt {font-size:24px;}QMainWindow,QDialog{background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #1B2534, stop: 0.4 #010101,stop: 0.5 #000101, stop: 1.0 #1F2B…

【LeetCode】day17:654 - 最大二叉树, 617 - 合并二叉树, 700 - 二叉树搜索树中的搜索, 98 - 验证二叉搜索树

LeetCode 代码随想录跟练 Day17 654.最大二叉树617.合并二叉树700.二叉搜索树中的搜索98.验证二叉搜索树 654.最大二叉树 题目描述&#xff1a; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的…

PyCharm创建一个空的python项目

1.设置项目路径 2.配置python解释器 右下角可以选择always

提交(git-add git-commit git-push)

当修改好一个功能的时候&#xff0c;可以提交到远程仓库&#xff0c;这样就等于更新了一次版本&#xff0c;那么下次改修了文件的话&#xff0c;是跟这个版本做对比的 git status&#xff0c; 查看文件修改情况&#xff0c;git add 假如你只想提交1个文件&#xff0c;那么直接…

Python入门基础教程(非常详细)

现在找工作真的越来越难了&#xff01;今年更是难上加难 前几天在网上刷到这样一条热搜&#xff1a; #23岁找工作因年龄大被HR拒绝了# 是这个世界疯了还是我疯了&#xff1f; 合着只想要有20年以上工作经验的应届毕业生是吧 这好像就是现在的就业市场现状&#xff1a;“35岁…

【leetcode】二分查找本质

标题&#xff1a;【leetcode】二分查找本质 水墨不写bug 正文开始&#xff1a;&#xff08;点击题目标题转跳到OJ&#xff09; 目录 &#xff08;O&#xff09;前言* &#xff08;一&#xff09; 在排序数组中查找元素的第一个和最后一个位置 思路详解&#xff1a; 参考代…

cocos2d-x安装和项目

首先多方查找资料发现教程很简洁&#xff0c;发现对自己的操作方面没多大帮助&#xff0c;后来干脆去官网&#xff0c;好像也很简洁。基于这样一个原因&#xff0c;加上我首次碰cocos2d-x&#xff0c;决定记录一下整个流程&#xff0c;解决实际操作上的疑惑。 涉及的方面&…

数模·时间序列

时间序列思维导图 时间序列分析的方法 聚焦于趋势和季节变化 时间序列预测模型 时间序列平稳性 时间序列的平稳性是时间序列分析中的一个重要概念。一个时间序列如果是平稳的&#xff0c;意味着其统计性质&#xff08;如均值、方差、自相关等&#xff09;不随时间变化。 平稳性…

[计网04] 传输层和应用层 笔记 总结 万字详解

目录 传输层概述和功能 URL 和URI 端口号划分 套接字Socket UDP&#xff08;User Datagram Protocol&#xff09; UDP首部 UDP伪首部 TCP 三报文握手和四报文挥手 TCP&#xff08;Transmission Control Protocol&#xff09; TCP首部报文格式 TCP流量控制 cwnd&…

如何在 C# ASP.NET MVC 项目中实现 Memcached?

一.介绍 在现代 Web 应用程序中&#xff0c;性能和可扩展性至关重要。提高性能的有效方法之一是使用缓存。Memcached 是一种开源、高性能、分布式内存缓存系统&#xff0c;被广泛使用。本文将引导您在 C# ASP.NET MVC 项目中实现 Memcached。 二.什么是 Memcached&#xff1f;…

SpringBoot面试高频总结01

1. 什么是SpringBoot&#xff1f; SpringBoot是一个基于Spring框架的快速开发框架&#xff0c;它采用约定大于配置&#xff0c;自动装配的方式&#xff0c;可以快速地创建独立的&#xff0c;生产级别的&#xff0c;基于Spring的应用程序。 相比于传统的Spring框架&#xff0c;S…

真实测评,霍尼韦尔、希喂、352宠物空气净化器性能对比

在快节奏的社会生活中&#xff0c;人们越来越注重精神需要&#xff0c;许多年轻人纷纷选择拥抱宠物&#xff0c;作为生活中的温馨伴侣。宠物们治愈心灵的同时也要付出一定“代价”&#xff0c;日常养护&#xff0c;如清理猫毛、管理气味以及保持宠物环境的清洁&#xff0c;都是…

Agent类型解析:AIGC在不同领域的应用与影响

目录 引言 垂直智能体&#xff08;Vertical Agent&#xff09; 水平智能体&#xff08;Horizontal Agent&#xff09; 混合智能体&#xff08;Hybrid Agent&#xff09; 结论 引言 在人工智能&#xff08;AI&#xff09;领域&#xff0c;智能体&#xff08;Agent&#xf…

更加深入Mysql-04-MySQL 多表查询与事务的操作

文章目录 多表查询内连接隐式内连接显示内连接 外连接左外连接右外连接 子查询 事务事务隔离级别 多表查询 有时我们不仅需要一个表的数据&#xff0c;数据可能关联到俩个表或者三个表&#xff0c;这时我们就要进行夺标查询了。 数据准备&#xff1a; 创建一个部门表并且插入…

JavaWeb day01-HTML入门

Web前端 课程安排 HTML、CSS简介 HTML快速入门 实现标题排版 新闻标题样式

Docker核心技术:Docker的基本使用

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Docker核心技术 系列文章&#xff1a;Docker的基本使用&#xff0c;其他文章快捷链接如下&#xff1a; 应用架构演进容器技术要解决哪些问题Docker的基本使用&#xff08;本文&#xff09;Docker是如何实现的 3…

Spark调优特殊case- Task倾斜

首先我们观察下上面的stage5, Task MaxTime2.4Min, 但是stage5的整体耗时竟然可以达到55Min, 其实分区1000&#xff0c; 300个executor&#xff0c; 按照最大的TaskTime2.4Min来估算所有Task运行完成时间, 那么时间应该是- 2.4Min * 3 2.4Min 9.6Min 也就是最慢也就跑10分钟就…

【时时三省】(C语言基础)函数和数组

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ——csdn时时三省 函数 跟数学里面的函数很相似 数组 一组相同类型的元素的集合 比如把5个整形1-5存起来 int arr&#xff3b;10&#xff3d;&#xff1d;&#xff5b;1&#xff0c;2&#xff0c;3&#x…