可变调的蜂鸣器、电子音乐

利用定时器定时翻转蜂鸣器的beep引脚,产生方波使蜂鸣器发生,所以根据定时器不同的定时产生不同的方波,就可以改变蜂鸣器的音调(与改变led灯亮度类似)。

void time0() interrupt 1
{
	TH0=timeh;								//赋值,改变定时
	TL0=timel;
	beep=~beep;							   //翻转产生方波
}

 用二维数组music[n][m]来存储乐谱,方便歌曲的切换和简化代码,m要开大点,要比最长的乐谱大一点。将定时器0设置最高优先等级。

电子音乐代码(还未优化):

#include <STC15F2K60S2.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit beep=P3^4;
sbit key1=P3^2;
sbit key2=P3^3;
uchar timeh,timel,jindu=0,gequ=0;
bit flag;
uint MusicCnt=3;        //歌曲总数

uchar code music[3][500] =
{                        /*0x15,“1”代表低八音,“5”代表so*/
{                        /*0x21,“2”代表中八音,“1”代表do*/
0x15,0x20,0x21,0x10,     /*0x31,“3”代表高八音,“1”代表do*/
0x22,0x10,0x23,0x15,     /*上面是音符的记录方法,每个音符后跟的是节拍*/
0x24,0x05,0x23,0x10,     /*本代码还未优化节拍,可以利用STC-ISP生成精准延时函数,优化节拍*/
0x21,0x10,0x22,0x20,
0x21,0x10,0x16,0x10,
0x21,0x40,0x15,0x20,
0x21,0x10,0x22,0x10,
0x23,0x10,0x23,0x05,
0x24,0x05,0x25,0x10,
0x21,0x10,0x24,0x15,
0x23,0x05,0x25,0x10,
0x22,0x05,0x23,0x05,
0x23,0x05,0x22,0x05,
0x22,0x30,0x23,0x20,
0x25,0x10,0x31,0x10,
0x27,0x15,0x26,0x05,
0x26,0x20,0x25,0x10,
0x25,0x05,0x26,0x05,
0x27,0x10,0x26,0x05,
0x25,0x05,0x23,0x40,
0x24,0x15,0x24,0x05,
0x25,0x10,0x26,0x10,
0x25,0x10,0x24,0x05,
0x23,0x05,0x22,0x20,
0x17,0x10,0x17,0x05,
0x16,0x05,0x15,0x10,
0x16,0x10,0x21,0x40,
0x00,0x00
},
{
0x21,0x05,0x21,0x05,
0x21,0x05,0x23,0x05,
0x25,0x05,0x25,0x05,
0x25,0x05,0x25,0x05,
0x26,0x05,0x26,0x05,
0x26,0x05,0x31,0x05,
0x25,0x20,0x24,0x05,
0x24,0x05,0x24,0x05,
0x26,0x05,0x23,0x05,
0x23,0x05,0x23,0x05,
0x23,0x05,0x22,0x05,
0x22,0x05,0x22,0x05,
0x22,0x05,0x25,0x15,
0x25,0x05,0x21,0x05,
0x21,0x05,0x21,0x05,
0x23,0x05,0x25,0x05,
0x25,0x05,0x25,0x05,
0x25,0x05,0x26,0x05,
0x26,0x05,0x26,0x05,
0x31,0x05,0x25,0x20,
0x24,0x05,0x24,0x05,
0x24,0x05,0x26,0x05,
0x21,0x05,0x21,0x05,
0x21,0x05,0x23,0x05,
0x25,0x05,0x25,0x05,
0x25,0x05,0x25,0x05,
0x26,0x05,0x26,0x05,
0x26,0x05,0x31,0x05,
0x25,0x20,0x24,0x05,
0x24,0x05,0x24,0x05,
0x23,0x03,0x23,0x03,
0x23,0x03,0x23,0x03,
0x23,0x05,0x23,0x05,
0x22,0x05,0x22,0x05,
0x22,0x05,0x23,0x05,
0x21,0x20,0x00,0x00
},
{
0x16,0x05,0x17,0x05,
0x21,0x15,0x17,0x05,
0x21,0x10,0x23,0x10,
0x17,0x30,0x23,0x10,
0x16,0x15,0x15,0x05,
0x16,0x10,0x21,0x10,
0x15,0x30,0x13,0x10,
0x14,0x15,0x13,0x05,
0x14,0x05,0x21,0x05,
0x21,0x10,0x13,0x30,
0x21,0x10,0x17,0x10,
0x14,0x05,0x14,0x10,
0x17,0x10,0x17,0x20,
0xff,
0x16,0x05,0x17,0x05,
0x21,0x15,0x17,0x05,
0x21,0x10,0x23,0x10,
0x17,0x30,0x13,0x05,
0x13,0x05,0x16,0x15,
0x15,0x05,0x16,0x10,
0x21,0x10,0x15,0x30,
0x13,0x10,0x14,0x10,
0x21,0x05,0x17,0x05,
0x17,0x10,0x21,0x10,
0x22,0x10,0x23,0x05,
0x21,0x20,0xff,
0x21,0x05,0x17,0x05,
0x16,0x10,0x17,0x10,
0x15,0x10,0x16,0x20,
0xff,
0x21,0x05,0x22,0x05,
0x23,0x15,0x22,0x10,
0x23,0x10,0x24,0x10,
0x25,0x05,0x22,0x30,
0x15,0x10,0x22,0x03,
0x21,0x03,0x17,0x03,
0x21,0x03,0x21,0x10,
0x21,0x05,0x22,0x10,
0x23,0x05,0x23,0x40,
0x16,0x05,0x17,0x05,
0x21,0x10,0x17,0x05,
0x21,0x05,0x22,0x10,
0x21,0x15,0x15,0x05,
0x15,0x20,0x24,0x10,
0x23,0x10,0x22,0x10,
0x21,0x10,0x23,0x30,
0x16,0x05,0x17,0x05,
0x21,0x15,0x17,0x05,
0x21,0x10,0x23,0x10,
0x17,0x30,0x13,0x10,
0x16,0x15,0x15,0x05,
0x16,0x10,0x21,0x10,
0x15,0x30,0x13,0x10,
0x14,0x10,0x21,0x05,
0x17,0x05,0x17,0x10,
0x21,0x10,0x22,0x10,
0x23,0x05,0x21,0x05,
0x21,0x20,0x21,0x05,
0x17,0x05,0x16,0x10,
0x17,0x10,0x15,0x10,
0x16,0x40,0x00,0x00
}
};
uchar code quzi[] =    /*每个音对应的定时器重装值,左边一列为高位,右边一列为低位*/
{
0xf8,0x8c,//低1
0xf9,0x5b,	  
0xfa,0x15,//低3
0xfa,0x67,
0xfb,0x04,
0xfb,0x90,
0xfc,0x0c,
0xfc,0x44,
0xfc,0xac,
0xfd,0x09,
0xfd,0x34,
0xfd,0x82,
0xfd,0xc8,
0xfe,0x06,
0xfe,0x22,
0xfe,0x56,
0xfe,0x6e,
0xfe,0x9a,
0xfe,0xc1,
0xfe,0xe4,
0xff,0x03
};

uint ss[3]={180,300,200};//因为还未优化节拍,所以引入ss数组调节节拍

void delay(unsigned int x)
{
	uint i,j;						   
	 for(i=x;i>0;i--)
	 	for(j=124;j>0;j--);
}

void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void Delay100ms(uint x)		//@11.0592MHz
{
	unsigned char i, j, k;
	while(x--)
	{
	_nop_();
	_nop_();
	i = 5;
	j = 52;
	k = 195;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
	}
}

uchar quyin(uchar tem)        //取音调对应重装值位置
{
	uchar qudiao,jp,weizhi;
	qudiao=tem/16;
	jp=tem%16;
	if(qudiao==1)
		qudiao=0;
	else if(qudiao==2)
		qudiao=14;
	else if(qudiao==3)
		qudiao=28;
	weizhi=qudiao+(jp-1)*2;
	return weizhi;
}
void playmusic()
{
	uchar p,m,tem;    
	while(1)   
	{   
		if(flag==1)
		{
				if(gequ==MusicCnt)gequ=0;//歌单播放完,切回第一首
				p=music[gequ][jindu];   	  
				if(p==0x00)              //0x00,歌曲结束标志
				{
					jindu=0;
					gequ++;
					Delay100ms(20);      //延时2s后,播放下一首
					break;
				}        
				else if(p==0xff)         //0xff,休止符标志,延时100ms
				{
					jindu=jindu+1;
					Delay100ms(1);
					TR0=0;
					break;
				}      
				else
				{
					tem=quyin(music[gequ][jindu]);//取音符的音调对应重装值的位置
					timeh=quzi[tem];              //取重装值
					timel=quzi[tem+1];
					jindu++;
					TH0=timeh;                    //重装
					TL0=timel;
					m=music[gequ][jindu];         //取节拍
					jindu++;
				}  		   
				TR0=1;            //开启定时器
				delay(m*ss[gequ]);//延时完成节拍,可以用精准的延时函数进行优化
				TR0=0;            //关闭定时器
				beep=0;           //保护蜂鸣器
			}										
		else
		while(flag!=1);    
	}
}

void init()						  
{
    P0M0=0xff;
	P0M1=0x00;
	P2M0=0x08;
	P2M1=0x00;
	P3M0=0x10;
	P3M1=0x00;
	TMOD=0x01;
	TH0=0xD8;
	TL0=0xEF;
	IE=0x87;
	IP=0x02;
	TR0=0;
	beep=0;
}
void main()
{
	init();
	P0=0x00;
	key1=1;
	key2=1;
	flag=0;
	while(1)
	{
		playmusic();
	}
}									

void time0() interrupt 1
{
	TH0=timeh;
	TL0=timel;
	beep=~beep;
}

void ex1() interrupt 0					  
{
	Delay5ms();
	if(key1==0)
	{
			while(!key1);
			Delay5ms();
			flag=~flag;
	}
}

void ex2() interrupt 2
{
	Delay5ms();
	if(key2==0)
	{
		while(!key2);
		Delay5ms();
		jindu=0;
		gequ++;		
        if(gequ==MusicCnt)
		gequ=0;
	}
}

也可以引入其他功能,比如调节歌曲进度,加减jindu就行(注意:进度的边界)。

(若有不足和错误,还请各位斧正) 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值