单片机实验8:电子音乐演奏

一、实验目的以及要求

1、了解电子音乐的产生与频率的关系。

2、编写一个电子音乐发生器。

3、编制一个程序,可自动演奏电子音乐。

二、实验原理

音名与频率的关系:

音乐的十二平均率规定:每两个八度音(如简谱中的中音1与高音1)之间的频率相差一倍。在两个八度音之间,又可分为十二个半音,每两个半音的频率比为12根号2。另外,音名A(简谱中的低音6)的频率为440HZ,音名B到C之间、E到F之间为半音,其余为全音。由此可以计算出简谱中从低度音1至高音1之间每个音名的频率,如下表所示:

简谱中音名与频率的关系表

音名

频率(HZ)

音名

频率(HZ)

音名

频率(HZ)

低音1

261.63

中音1

523.25

高音1

1046.50

低音2

293.67

中音2

587.33

高音2

1174.66

低音3

329.63

中音3

659.25

高音3

1318.51

低音4

349.23

中音4

698.46

高音4

1396.92

低音5

391.99

中音5

783.99

高音5

1567.98

低音6

440

中音6

880

高音6

1760

低音7

493.88

中音7

987.76

高音7

1975.52

由于音阶频率多为非整数,而分频系数又不能为小数,故必须将计算得到的分频数四舍五入取整。若基准频率过低,则由于分频系数过小,四舍五入取整后的误差较大。若基准频率过高,虽然误码差变小,但分频结构将变大。实际的设计应综合考虑两方面的因素,在尽量减小频率误差的前提下取合适的基准频率。

三、实验内容和步骤

P1.5接蜂鸣器SP孔。运行程序music1或music2,蜂鸣器将演奏音乐。

四、实验代码

/****************************** (C) COPYRIGHT 2013   **************************
* 主  控  MCU     : AT89S52
* 主      频      : 11.0592MHz
* 编  译  器      : Keil C51 V4.22
* 描      述      : 驱动蜂鸣器演奏歌曲演示程序.
*********************************************************************************/
#include"Reg52.H"                                                                       /* 调用MCS51寄存器头文件 */
#include"stdio.H"
//*********************************************
//MON51必须用到的
code unsigned char stop[3] _at_ 0x3b;
//*********************************************

typedef	unsigned char UINT8;                                                            /* 类型定义 */
typedef unsigned int  UINT16; 
/******************************** 引脚定义 **************************************
                        单片机            	蜂鸣器
                         P15                U16-N1
*********************************************************************************/
sbit Speaker = P1^5;							                                        /* 定义蜂鸣器端口 */

UINT8 	Sound_Temp_TH0,Sound_Temp_TL0;													/* 定时器初值 */
UINT8   SpeedTime;																		/* 一拍时间 */	

/******************************** 音阶频率表 ************************************/
/* 四个八度的28个频率数据 */

UINT8 code FREQH[ ] = {                                                                 /* 音阶频率表 高八位 */
						0xF9,0xF9,0xFA,0xFA,0xFB,0xFB,0xFC,                        		/* 低音 1,2,3,4,5,6,7 */
                        0xFC,0xFC,0xFD,0xFD,0xFD,0xFD,0xFE,                             /* 中音 1,2,3,4,5,6,7 */
                        0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFF                              /* 高音 1,2,3,4,5,6,7 */
                      } ;
                         
UINT8 code FREQL[ ] = {                                                                 /* 音阶频率表 低八位 */
						0x21,0xE1,0x8C,0xD8,0x68,0xE9,0x5B,                        		/* 低音 1,2,3,4,5,6,7 */
                        0x8F,0xEE,0x44,0x6B,0xB4,0xF4,0x2D,                             /* 中音 1,2,3,4,5,6,7 */
                        0x47,0x77,0xA2,0xB6,0xDA,0xFA,0x16                              /* 高音 1,2,3,4,5,6,7 */
                      };

/********************************** 歌曲表1 *************************************/
/* 两只老虎数据表 */
UINT8 code MUSIC1[ ] = {
						1,2,2, 2,2,2, 3,2,2, 1,2,2, 1,2,2, 2,2,2, 3,2,2, 1,2,2, 3,2,2, 4,2,2, 5,2,4, 3,2,2, 4,2,2, 5,2,4, 0,0,0 
                       };

/* 爱如火数据表 */
UINT8 code MUSIC2[ ] = {
						1,3,2, 7,2,2, 3,2,2, 3,2,2, 5,2,2, 5,2,2, 3,2,2, 6,2,2, 5,2,2,
						1,3,2, 7,2,2, 3,2,2, 3,2,2, 5,2,2, 5,2,2, 3,2,2, 6,2,2, 5,2,2,
						1,3,2, 2,3,2, 7,2,2, 6,2,2, 7,2,2, 7,2,2, 6,2,2, 2,3,2, 7,2,2,
						1,3,2, 7,2,2, 3,2,2, 3,2,2, 5,2,2, 5,2,2, 3,2,2, 6,2,2, 5,2,2,
					   };
					   
//一个音符有三个数字。前为第几个音、中为第几个八度、后为时长(以拍为单位)
//6,2,3 分别代表: 6,中音,3个拍;
//5,2,1 分别代表: 5,中音,1个拍;

/*******************************************************************************
* 函  数  名      : DelayMs
* 描      述      : 毫秒延时.
* 输      入      : UINT16 Us:
*                   要延时的Ms时间.
* 返      回      : 无.
*******************************************************************************/
void DelayMs( UINT16 Ms )
{
	UINT16 i;
  	
	while( Ms-- )
	{
		for ( i = 0; i < 114; i++ );													/* 延时1毫秒 */
	}
}

/*******************************************************************************
* 函  数  名      : BeepTimer0
* 描      述      : 定时器T0,蜂鸣器中断.
* 输      入      : 无.
* 返      回      : 无.
*******************************************************************************/
void BeepTimer0() interrupt 1
{
 	Speaker = !Speaker;
 	TH0=Sound_Temp_TH0;
	TL0=Sound_Temp_TL0;																	/* 重新赋定时器初值 */
}

/*******************************************************************************
* 函  数  名      : PlayMusic
* 描      述      : 播放音乐.
* 输      入      : UINT8 *Sound:
*                   指向音乐缓冲区.
* 返      回      : 无.
*******************************************************************************/
void PlayMusic( UINT8 *Sound )
{
 	UINT16  i = 0,j;
	UINT8  ByteCnt;
	UINT16 SoundLength;																	/* 歌曲长度 */

	SoundLength = 0;
	while( Sound[ SoundLength++ ] != 0x00 );                                            /* 计算歌曲长度 */	

	while( i < SoundLength )
	{
		j = Sound[ i ] +  7 * ( Sound[ i + 1 ] - 1 ) - 1;      		                // 
		Sound_Temp_TH0 = FREQH[ j ];													/* 音符频率 */
	    Sound_Temp_TL0 = FREQL[ j ];
	    SpeedTime = Sound[ i + 2 ];														/* 该音符时常 */  
	
		TH0 = Sound_Temp_TH0;                                                           /* 赋定时器初值 */
		TL0 = Sound_Temp_TL0;
		TR0=1;                                                                        /* 启动定时器 */
		i += 3;   	                                                                    /* 指向下一组数据 */
		while( SpeedTime-- )                                                            /* 延时达到该音符符时间间隔 */
		{
			for( ByteCnt = 0; ByteCnt < 200; ByteCnt++ )
			{
				DelayMs(1);
			}
		}
		TR0=0;                                                                        /* 关闭定时器 */ 
		Speaker = 0;                                                                    /* 关闭蜂鸣器 */
	}	
}

/*******************************************************************************
* 函  数  名      : main
* 描      述      : 主函数.
* 输      入      : 无.
* 返      回      : 无.
*******************************************************************************/
void main( )
{ 	
	TMOD = 0x01; 																		/* 定时器T0工作在方式1 */
 	ET0=1;																			/* 开TR0中断 */
	EA=1;																				/* 开中断 */

	while(1)
	{
		PlayMusic( MUSIC1 );                                                            /* 播放第一首歌曲 */
		DelayMs(500);
		PlayMusic( MUSIC2 );                                                            /* 播放第二首歌曲 */
		DelayMs(500);
	}    
}

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

x陌北x

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

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

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

打赏作者

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

抵扣说明:

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

余额充值