基于STC89C52芯片完成音乐闹钟设计

这篇博客介绍了一个基于51系列单片机的倒计时闹钟项目,通过按键设置时间,并在倒计时结束后播放《孤勇者》的简谱音乐。程序使用了C语言编写,包含了定时器配置、音符频率映射和数码管显示等功能,实现了音乐的播放和时间显示。
摘要由CSDN通过智能技术生成

找到不同音符对应的频率,定义音符,根据《孤勇者》简谱编写乐谱,运用按键k1来设置闹钟倒计时时间,设置完成后按下按键k2,倒计时开始,倒计时结束后,播放《孤勇者》铃声

设计开发环境:

keli4(51系列兼容单片机C语言软件开发系统)

#include <reg52.h>
typedef unsigned int uint;
typedef unsigned char uchar;
uint a,FreqSelect,MusicSelect,count,count2,count_ms=100;
uchar code table[]={0x3F,  //"0"
    0x06,  //"1"
    0x5B,  //"2"
    0x4F,  //"3"
    0x66,  //"4"
    0x6D,  //"5"
    0x7D,  //"6"
    0x07,  //"7"
    0x7F,  //"8"
    0x6F,  //"9"
    0x00  //熄灭
	};

sbit P2_0 = P2^3;
sbit P2_1 = P2^2;
sbit P2_2 = P2^1;
sbit P2_3 = P2^0;
sbit P2_4 = P2^7;
sbit P2_5 = P2^6;
sbit P2_6 = P2^5;
sbit P2_7 = P2^4;
sbit k1=P1^6;
sbit k2=P1^7;
sbit Buzzer=P1^4; 
//播放速度,将一个四分音符的时长设置为600(ms),并以四分音符的时长为基准
#define SPEED	600
//音符与索引对应表,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#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 int FreqTable[]={
	0,
	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 int code Music[]={//乐谱较长加上关键字code将其储存在ROM(flash)
	//音符,时值,
	//1
	L6,4+4,
	P,4,
	P,2,
	M6,1,
	M7,1,
	//2
	H1,1,
	H2,1,
	M7,1,
	H1,1,
	H1,2,
	H1,1,
	M7,1,
	H1,1,
	H1,2,
	H1,1,
	H2,1,
	//3
	H3,1,
	H2,1,
	H3,1,
	H2,1,
	H3,2,
	H3,1,
	H2,1,
	H3,2,
	H5,2,
	H3,2,
	M6,1,
	M7,1,
	//4
	H1,1,
	H2,1,
	M7,1,
	H1,1,
	H1,2,
	H1,1,
	M7,1,
	H1,1,
	H2,1,
	M7,1,
	H1,1,
	H1,2,
	H1,1,
	H2,1,
	//5
	H3,1,
	H2,1,
	H3,1,
	H2,1,
	H3,2,
	H3,1,
	H2,1,
	H3,2,
	H5,2,
	H3,2,
	H5,2,
	//6
	H3,2+1,
	H5,1,
	H3,2+1,
	H5,1,
	H3,1,
	H5,1,
	H6,1,
	H3,1,
	H5,2,
	H5,2,
	//7
	H3,2+1,
	H5,1,
	H3,2+1,
	H5,1,
	H3,1,
	H5,1,
	H6,1,
	H3,1,
	H5,1,
	H5,1,
	H5,1,
	//8
	H3,1,
	H2,1,
	H2,2,
	H2,2,
	H1,1,
	H3,1,
	H3,1,
	H2,1,
	H2,2,
	H2,2,
	H1,1,
	H1,1,
	//9
	M6,4+4,
	P,4,
	P,2,
	H5,1,
	H5,1,
	//10
	H3,1,
	H2,1,
	H2,2,
	H2,2,
	H1,1,
	H3,1,
	H3,1,
	H2,1,
	H2,2,
	H2,2,
	H1,1,
	H1,1,
	//11
	M6,4+4,
	P,4,
	P,4,
			
	0xFF	//终止标志
};
/*
* 延时函数  毫秒级
*/
void delay1(uint z)
{
	uint x,y;
	for(x=z;z>0;z--)
		for(y=110;y>0;y--)
		;
} 
void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}                       
/********************************************************************
* 名称 : Timer1Init()
* 功能 : 定时器1初始化
* 输入 : 无
* 输出 : 无
***********************************************************************/
void Timer1Init(void)		//10毫秒@11.0592MHz
{
//	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x00;		//设置定时初值
	TH1 = 0xDC;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;        //enable timer1 interrupt
    EA = 1;          //open global interrupt switch
}
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}
/********************************************************************
* 名称 : display()
* 功能 : 数码管显示函数
* 输入 : Dis_data1,Dis_data2,Dis_data3,Dis_data4
* 输出 : 无
***********************************************************************/
void display1(uint Dis_data1,uint Dis_data2,uint Dis_data3,uint Dis_data4)
{   
   P0=table[Dis_data1];
   P2_0 = 0;
   delay1(2);
   P2_0 = 1;

   P0=table[Dis_data2];
   P2_1 = 0;
   delay1(2);
   P2_1 = 1;

   P0=table[Dis_data3];
   P2_2 = 0;
   delay1(2);
   P2_2 = 1;

    P0=table[Dis_data4];
   P2_3 = 0;
   delay1(2);
   P2_3 = 1;
   
}
void display2(uint Dis_data1,uint Dis_data2,uint Dis_data3,uint Dis_data4)
{   
   P0=table[Dis_data1];
   P2_4 = 0;
   delay1(2);
   P2_4 = 1;

   P0=table[Dis_data2];
   P2_5 = 0;
   delay1(2);
   P2_5 = 1;

   P0=table[Dis_data3];
   P2_6 = 0;
   delay1(2);
   P2_6 = 1;

   P0=table[Dis_data4];
   P2_7 = 0;
   delay1(2);
   P2_7 = 1;
   
}

/********************************************************************
* 名称 : main()
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void main()
{
	while(1)
	{
		if(k1==0){
			while(!k1);
			a++;
		}
		if(k2==0){
			break;
		}
		count=a;
		display2(count%10000/1000,count%1000/100,count%100/10,count%10);
	}	
	Timer1Init();
	//count=100;
	//count=10000;
	count_ms=1000;
	while(1)
	{
		display1(count%10000/1000,count%1000/100,count%100/10,count%10);
		if(count==0){
			Timer0Init();
			while(1)
			{
				if(Music[MusicSelect]!=0xFF)	//如果不是停止标志位
				{
					FreqSelect=Music[MusicSelect];	//选择音符对应的频率
					MusicSelect++;
 
					Delay(SPEED/2*Music[MusicSelect]);	//选择音符对应的时长
					MusicSelect++;
 
					TR0=0;//不同音符间短暂停顿,利用延时开关定时器实现
					Delay(5);	
					TR0=1;
				}
				else	//如果是停止标志位
				{
					TR0=0;  //关闭定时器
					while(1);
				}
			}


		}
	
	}	
}

/********************************************************************
* 名称 : void tm1_isr() interrupt 3 using 1
* 功能 : 定时器1中断服务函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void tm1_isr() interrupt 3 using 1
{
	TL1 = 0x00;		//设置定时初值
	TH1 = 0xDC;		//设置定时初值
    if (count_ms-- == 0)               //1ms * 1000 -> 1s
    {
        count_ms=1000;
		if(count==0)
		{
			count=a;
		}
		count --;              //reset counter
    }
}

void Timer0_Routine() interrupt 1
{
	if(FreqTable[FreqSelect])	//如果是休止符(0),那么不播放声音,只进行延时
	{
		//取对应频率值的重装载值到定时器(确认音高)FreqSelect=Music[MusicSelect]
		TL0 = FreqTable[FreqSelect]%256;		//设置低位定时初值
		TH0 = FreqTable[FreqSelect]/256;		//设置高位定时初值
		Buzzer=!Buzzer;	//翻转蜂鸣器IO口(注意这里的重装值是周期的一半,故仅进行一次蜂鸣器的翻转)
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

别管我啦就是说

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

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

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

打赏作者

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

抵扣说明:

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

余额充值