51单片机 音乐播放器

在这里插入图片描述
在这里插入图片描述
main.c

#include<reg52.h>
#include<intrins.h>

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

#include "lcd1602.h"

#define uchar unsigned char 
#define uint unsigned int
#define u8 unsigned char 
#define u16 unsigned int
//以下是C调低音的音频宏定义
#define L1  262    //将"L1"宏定义为低音"1"的频率262Hz         时间是1/262=3826/2 us    取半周期
#define L2  286    //将"L2"宏定义为低音"2"的频率286Hz
#define L3  311    //将"L3"宏定义为低音"3"的频率311Hz
#define L4  349    //将"L4"宏定义为低音"4"的频率349Hz
#define L5  392    //将"L5"宏定义为低音"5"的频率392Hz
#define L6  440    //将"l_a"宏定义为低音"6"的频率440Hz
#define L7  494    //将"L7"宏定义为低音"7"的频率494Hz
//以下是C调中音的音频宏定义
#define Z1    523     //将"Z1"宏定义为中音"1"的频率523Hz
#define Z2    587     //将"Z2"宏定义为中音"2"的频率587Hz
#define Z3    659     //将"Z3"宏定义为中音"3"的频率659Hz
#define Z4    698     //将"Z4"宏定义为中音"4"的频率698Hz
#define Z5    784     //将"Z5"宏定义为中音"5"的频率784Hz
#define Z6    880     //将"Z6"宏定义为中音"6"的频率880Hz
#define Z7    987     //将"Z7"宏定义为中音"7"的频率523H      
//以下是C调高音的音频宏定义
#define H1  1046    //将"H1"宏定义为高音"1"的频率1046Hz
#define H2  1174    //将"H2"宏定义为高音"2"的频率1174Hz
#define H3  1318    //将"H3"宏定义为高音"3"的频率1318Hz
#define H4  1396    //将"H4"宏定义为高音"4"的频率1396Hz
#define H5  1567    //将"H5"宏定义为高音"5"的频率1567Hz
#define H6  1760    //将"H6"宏定义为高音"6"的频率1760Hz
#define H7  1975    //将"H7"宏定义为高音"7"的频率1975Hz

/*  ******************************************    */
//  ********   硬件端口定义   
/*  ******************************************    */
sbit sound = P1 ^ 4;    //蜂鸣器


sbit KAISHI = P1 ^ 0;        //开始
sbit ZANTING = P1 ^ 1;        //暂停

sbit PRE_KEY = P1 ^ 2;        //上一首
sbit NEXT_KEY = P1 ^ 3;        //下一首


sbit yianjian = P1 ^ 5;        //1
sbit eranjian = P1 ^ 6;        //1
sbit sananjian = P1 ^ 7;        //1

/*  ******************************************    */
//  ********   程序变量定义
/*  ******************************************    */
unsigned int C;     //储存定时器的定时常数
unsigned char u, t;	 //音乐所用的变量

unsigned char velocity = 60;	//控制节拍使用的 这里100表示一个拍子100ms

unsigned char press_key = 0;	//按键  按下后会改变数值  初始值为0

unsigned char open_flag = 1; //暂停时为0  播放时为1
unsigned char music_crr = 0; //当前是播放哪一首音乐  可以为0  1  2  分别是是三首歌


char	rtc_hour	= 0;
char	rtc_min		= 0;
char	rtc_sec		= 0;

char num2 = 0;    /* 计数 */




/*  ******************************************    */
//  ********  音乐0	   天空之城
/*  ******************************************    */
//以下是《天空之城》简谱    //每行对应一小节音符
unsigned int code music0[]=
{	Z6,Z7,/**/H1,Z7,H1,H3,/**/Z7,Z3,Z3, /**/Z6,Z5,Z6,H1,/**/Z5,Z3,Z3, /**/Z4,Z3,Z4,H1,
	Z3,H1,H1,H1,/**/Z7,Z4,Z4,Z7,/**/Z7,Z6,Z7, /**/H1,Z7,H1,H3,/**/Z7,Z3,Z3, /**/Z6,Z5,Z6,H1,
	Z5, Z3,/**/Z4,H1,Z7,H1,/**/H2,H2,H2,H1,/**/H1,Z6,Z7,Z5,/**/Z6,H1,H2, /**/H3,H2,H3,H5,
	H2,Z5,Z5, /**/H1,Z7,H1,H3,/**/H3, /**/Z6,H1,Z7,H2,/**/H1,Z5,Z5, /**/H4,H3,H2,H1,
	H3, /**/Z3,H3, /**/H6,H5,H5, /**/H3,H2,H1,H1,/**/H2,H1,H2,H5,/**/H3,H3,
	H6,H5, /**/H3,H2,H1,H1,/**/H2,H1,H2,Z7,/**/Z6,Z6,Z7, /**/Z6,0xff}; //以0xff作为音符的结束标志      

//以下是简谱中每个音符的节拍
//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 
unsigned char code music0_JP[ ]=
{	4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,4,12,
	20,4,4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,8,8, /**/20,4,4, /**/12,4,8,8,
	32, 4, /**/8,4,6,8, /**/4,4,4,16, /**/8,4,6,8, /**/24,4,4, /**/12,4,8,8,
	24,4,4, /**/4,4,8,8, /**/32, /**/4,8,8,6, /**/12,4,16, /**/8,8,8,8,
	30, /**/20,8, /**/16,8,8, /**/4,4,16,8, /**/8,4,4,8, /**/20,8,
	16,16, /**/4,20,8, /**/8,4,4,8, /**/20,4,4,8,8, /**/8};


/*  ******************************************    */
//  ********   音乐2
/*  ******************************************    */
unsigned int code music1[]=
{	Z3,Z3,Z5,Z6,H1,H1,Z6,
	Z5,Z5,Z6,Z5,
	Z3,Z3,Z5,Z6,H1,H1,Z6,
	Z5,Z5,Z6,Z5,
	Z5,Z5,Z5,Z3,Z5,
	Z6,Z6,Z5,
	Z3,Z2,Z3,Z5,Z3,Z2,
	Z1,Z1,Z2,Z1,0xff}; //以0xff作为音符的结束标志      

//以下是简谱中每个音符的节拍
//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 
unsigned char code music1_JP[ ]=
{	16,8,8,8,8,8,8,
	16,8,8,32,
	16,8,8,8,8,8,8,
	16,8,8,32,
	16,16,16,8,8,
	16,16,32,
	16,8,8,16,8,8,
	16,8,8,32,1,8,8};

/*  ******************************************    */
//  ********   音乐3 小星星
/*  ******************************************    */
unsigned int code music2[]=
{	H3,H3,H3,H2,H1,H2,H5,H5,H1,H1,H1,H1,Z6,
	Z7,H3,H3,Z5,Z6,H6,H5,H4,H3,H2,H1,H1,
	Z6,H1,H2,H5,H5,H2,H1,H2,H2,Z1,H3,H3,
	H3,H2,H1,H2,H5,H5,H1,H1,H1,H1,Z6,Z7,
	H3,H3,Z5,Z6,H6,H5,H4,
	H3,H2,H1,H1,Z6,H1,H2,H5,H5,Z5,H2,H1,

	0xff}; //以0xff作为音符的结束标志      

//以下是简谱中每个音符的节拍
//"4"对应4个延时单位,"2"对应2个延时单位,"1"对应1个延时单位 
unsigned char code music2_JP[ ]=
{	8,2,2,2,2,4,4,8, 8,2,2,2,2,
	4,4,4,4,8,4,2,2,4,2,2,8,
	2,2,2,2,2,2,2,2,8,8,8,2,2,2,2,4,4,8,8,2,2,2,2,4,4,4,4,8,4,2,2,
	8,2,2,4,2,2,2,2,2,2,4,12,8,8

};






/*  ******************************************    */
//  ********   延时1ms		 用于一般延时
/*  ******************************************    */
void delay(uint z)
{
	uint x;
	while (z--)
	{
		for (x = 125; x > 0; x--)
			;
	}
}
/*  ******************************************    */
//  ********   延时100ms	控制音乐节拍
/*  ******************************************    */
void delay1()
{
	uint i, j;
	for (i = 0; i < velocity; i++)
		for (j = 0; j < 125; j++)
			;
}

/*  ******************************************    */
//  ********   定时器初始化函数	 用了定时器1
/*  ******************************************    */
void init_timer(void)
{
	EA = 1;         //开总中断
	ET1 = 1;        //定时器T1中断允许
	TMOD &= 0x0f;
	TMOD |= 0x00;    // 使用定时器T1的模式1(13位计数器)
	TR1 = 1;

	TMOD |= 0x01;    // 使用定时器T1的模式1(13位计数器)
	TR0 = 1;
	ET0 = 1;        //定时器T1中断允许

}
/*  ******************************************    */
//  ********   按键扫描	   返回值 1 2 3 4 5 代表五个按键
/*  ******************************************    */
unsigned char ScanKey(void)
{
	if (KAISHI == 0)  //是否按下
	{
		delay(1);	  //延时防止电平抖动
		if (KAISHI == 0)
		{
			while (KAISHI == 0)
				; //等待松开
			return 1;
		}
	}

	if (ZANTING == 0)
	{
		delay(1);
		if (ZANTING == 0)
		{
			while (ZANTING == 0)
				;
			return 2;
		}
	}

	if (PRE_KEY == 0)
	{
		delay(1);
		if (PRE_KEY == 0)
		{
			while (PRE_KEY == 0)
				;
			return 3;
		}
	}
	
	if (NEXT_KEY == 0)
	{
		delay(1);
		if (NEXT_KEY == 0)
		{
			while (NEXT_KEY == 0)
				;
			return 4;
		}
	}

	

	if (yianjian == 0)//选择第1首歌的按键按下
	{
		delay(1);
		if (yianjian == 0)
		{
			while (yianjian == 0)
				;
			return 5;
		}
	}
	
	if (eranjian == 0) //选择第二首歌的按键按下
	{
		delay(1);
		if (eranjian == 0)
		{
			while (eranjian == 0)
				;
			return 6;
		}
	}
	
	if (sananjian == 0)//选择第3首歌的按键按下
	{
		delay(1);
		if (sananjian == 0)
		{
			while (sananjian == 0)
				;
			return 7;
		}
	}

	return 0;
}
/*  ******************************************    */
//  ********   处理按键 按下按键后 相应变量改变 
/*  ******************************************    */

void delay_key(void)
{
	
	if (press_key == 1) 	//开始
	{
		open_flag = 1;	  //开始
		
		press_key = 0;
		
	}
	if (press_key == 2) 	//暂停
	{
		open_flag = 0;	  //暂停
		
		press_key = 0;
		
	}
	if (press_key == 3) 	 //上一首
	{
		press_key = 0;
		if (music_crr > 0)
		{
			music_crr = (music_crr - 1) % 3;
		} else
		{
			music_crr = 2;	  //如果是第0首歌  那么按上一首就是第2首
		}
		LCD_write_char(9,0,music_crr+'1');//显示歌曲号
		rtc_hour=0;rtc_min=0; rtc_sec=0;
	}
	if (press_key == 4) 	 //下一首
	{
		press_key = 0;

		music_crr = (music_crr + 1) % 3;
		
		LCD_write_char(9,0,music_crr+'1'); //显示歌曲号
		rtc_hour=0;rtc_min=0; rtc_sec=0;
		

	}
	
	
	if (press_key == 5) 	  //1
	{
		press_key = 0;
		music_crr=0;
		LCD_write_char(9,0,music_crr+'1'); //显示歌曲号
		rtc_hour=0;rtc_min=0; rtc_sec=0;
		open_flag = 1;	  //开始
		
	}
	if (press_key == 6) 	  //2
	{
		press_key = 0;
		music_crr=1;
		LCD_write_char(9,0,music_crr+'1'); //显示歌曲号
		rtc_hour=0;rtc_min=0; rtc_sec=0;
		open_flag = 1;	  //开始
	}
	if (press_key == 7) 	  //3
	{
		press_key = 0;
		music_crr=2;
		LCD_write_char(9,0,music_crr+'1'); //显示歌曲号
		rtc_hour=0;rtc_min=0; rtc_sec=0;
		open_flag = 1;	  //开始
	}

	

	if (open_flag == 1)
		{
TR0=1;
		}else
		{
			 TR0=0;
		}
		
	LCD_dis_TIME( 6, 1, rtc_hour, rtc_min, rtc_sec );
}

uint changdu = 0;
/*  ******************************************    */
//  ********   主函数 程序逻辑
/*  ******************************************    */
void main()
{
	LCD_init();
	LCD_write_str(0,0,"   WELCOME!");
	delay(1000);


  LCD_write_str(0,0,"Playing:    ");
	LCD_write_char(9,0,'1');
	LCD_write_str(0,1,"Time:");
	LCD_dis_TIME( 6, 1, rtc_hour, rtc_min, rtc_sec );
	
	
	init_timer();
	TR1 = 0;     //关闭定时器
	sound = 0;	 //关闭蜂鸣器
	open_flag = 0; //关闭音乐
	
	TR0 = 0;     //关闭定时器
	LCD_dis_TIME( 6, 1, rtc_hour, rtc_min, rtc_sec );

	while (1)
	{
		press_key = ScanKey();	  //获取按下的键
		delay_key();	  //将按下的键值传入处理函数 改变状态变量

		
		

		if (music_crr == 0 && open_flag == 1)
		{

			u = 0;   //从第1个音符f[0]开始播放
			changdu = sizeof(music0);
			
			while (music0[u] != 0xff)            //只要没有读到结束标志就继续播放
			{
				press_key = ScanKey();	  //获取按下的键
				delay_key();	  //将按下的键值传入处理函数 改变状态变量
				if (music_crr != 0)	   //切换音乐
				{
					init_timer();
					TR1 = 0;     //关闭定时器
					sound = 1;	 //关闭蜂鸣器
					break;
				}
				if (open_flag == 0)	//如果暂停音乐
				{
					while (open_flag == 0)
					{
						press_key = ScanKey();	  //获取按下的键
						delay_key();	  //将按下的键值传入处理函数 改变状态变量
					}
				}

				C = 460830 / music0[u];
				TH1 = (8192 - C) / 32;   //可证明这是13位计数器TH0高8位的赋初值方法     5
				TL1 = (8192 - C) % 32;   //可证明这是13位计数器TL0低5位的赋初值方法
				TR1 = 1;             //启动定时器T0

				changdu--;
				

				for (t = 0; t < music0_JP[u]; t++)  //控制节拍数
					delay1();          //延时1个节拍单位
				TR1 = 0;                   //关闭定时器T1

				u++;                        //播放下一个音符

			}

			init_timer();
			TR1 = 0;     //关闭定时器
			sound = 1;	 //关闭蜂鸣器

		}

		if (music_crr == 1 && open_flag == 1)
		{
			u = 0;   //从第1个音符f[0]开始播放
			changdu = sizeof(music1);
			
			while (music1[u] != 0xff)            //只要没有读到结束标志就继续播放
			{
				press_key = ScanKey();	  //获取按下的键
				delay_key();	  //将按下的键值传入处理函数 改变状态变量
				if (music_crr != 1)	   //切换音乐
				{
					init_timer();
					TR1 = 0;     //关闭定时器
					sound = 1;	 //关闭蜂鸣器
					break;
				}
				if (open_flag == 0)	//如果暂停音乐
				{
					while (open_flag == 0)
					{
						press_key = ScanKey();	  //获取按下的键
						delay_key();	  //将按下的键值传入处理函数 改变状态变量
					}
				}

				C = 460830 / music1[u];
				TH1 = (8192 - C) / 32;   //可证明这是13位计数器TH0高8位的赋初值方法     5
				TL1 = (8192 - C) % 32;   //可证明这是13位计数器TL0低5位的赋初值方法
				TR1 = 1;             //启动定时器T0

				changdu--;
				

				for (t = 0; t < music1_JP[u]; t++)  //控制节拍数
					delay1();          //延时1个节拍单位
				TR1 = 0;                   //关闭定时器T1

				u++;                        //播放下一个音符

			}

			init_timer();
			TR1 = 0;     //关闭定时器
			sound = 1;	 //关闭蜂鸣器

		}

		if (music_crr == 2 && open_flag == 1)
		{
			u = 0;   //从第1个音符f[0]开始播放
			changdu = sizeof(music2);
			
			while (music2[u] != 0xff)            //只要没有读到结束标志就继续播放
			{
				press_key = ScanKey();	  //获取按下的键
				delay_key();	  //将按下的键值传入处理函数 改变状态变量
				if (music_crr != 2)	   //切换音乐
				{
					init_timer();
					TR1 = 0;     //关闭定时器
					sound = 1;	 //关闭蜂鸣器
					break;
				}
				if (open_flag == 0)	//如果暂停音乐
				{
					while (open_flag == 0)
					{
						press_key = ScanKey();	  //获取按下的键
						delay_key();	  //将按下的键值传入处理函数 改变状态变量
					}
				}

				C = 460830 / music2[u];
				TH1 = (8192 - C) / 32;   //可证明这是13位计数器TH0高8位的赋初值方法     5
				TL1 = (8192 - C) % 32;   //可证明这是13位计数器TL0低5位的赋初值方法
				TR1 = 1;             //启动定时器T0

				changdu--;
			

				for (t = 0; t < music2_JP[u] / 2; t++)  //控制节拍数
					delay1();          //延时1个节拍单位
				TR1 = 0;                   //关闭定时器T1

				u++;                        //播放下一个音符

			}

			init_timer();
			TR1 = 0;     //关闭定时器
			sound = 1;	 //关闭蜂鸣器

		}



	}
}

void Time1(void)
interrupt 3   //T1定时器的中断等级要注意  是3
{
	sound=!sound;      //将P3.7引脚输出电平取反,形成方波  
	TH1=(8192-C)/32;//可证明这是13位计数器TH0高8位的赋初值方法
	TL1=(8192-C)%32;//可证明这是13位计数器TL0低5位的赋初值方法 
}



void Time0(void)
interrupt 1  //T1定时器的中断等级要注意  是3
{

	
	TH0=(65535-50000)/255;  //可证明这是13位计数器TH0高8位的赋初值方法
	TL0=(65535-50000)%255;//可证明这是13位计数器TL0低5位的赋初值方法 

	num2++;
	if ( num2 == 20 )
	{
		num2 = 0;

		

		rtc_sec++;
		if ( rtc_sec == 60 )
		{
			rtc_sec = 0;
			rtc_min++;
			if ( rtc_min == 60 )
			{
				rtc_min = 0;
				rtc_hour++;
				if ( rtc_hour == 24 )
				{
					rtc_hour = 0;
				}
			}
		}
	}
	

}


lcd1602.h



#include <reg52.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
LCD_init();
LCD_write_str(1,1,"2223123");
*/

sbit lcd_rs=P2^5;
sbit lcd_rw=P2^6;
sbit lcd_en=P2^7;

#define DataPort P0

#define RS_CLR lcd_rs=0
#define RS_SET lcd_rs=1

#define RW_CLR lcd_rw=0

#define EN_CLR lcd_en=0
#define EN_SET lcd_en=1



void delay_lcd_ms(unsigned int a) {
	unsigned int i, j;
	for (i = a; i > 0; i--)
		for (j = 100; j > 0; j--)
			;
}
//***********************************************************************
//	显示屏命令写入函数
//***********************************************************************
void LCD_write_com(unsigned char com) 
{	
	RS_CLR;
	RW_CLR;
	EN_SET;
	DataPort = com;                 //命令写入端口
	delay_lcd_ms(5);
	EN_CLR;
}

//***********************************************************************
//	显示屏数据写入函数
//***********************************************************************
void LCD_write_data(unsigned char dataa) 
{
	RS_SET;
	RW_CLR;
	EN_SET;
	DataPort = dataa;                //数据写入端口
	delay_lcd_ms(5);
	EN_CLR;
}

//***********************************************************************
//	显示屏单字符写入函数
//***********************************************************************
void LCD_write_char(unsigned char x,unsigned char y,unsigned char dataa) 
{
	
    if (y == 0) 
    {
    	LCD_write_com(0x80 + x);        //第一行显示
    }
    else 
    {
    	LCD_write_com(0xC0 + x);        //第二行显示
    }
    
    LCD_write_data( dataa);  
}

//***********************************************************************
//	显示屏字符串写入函数
//***********************************************************************
void LCD_write_str(unsigned char x,unsigned char y,unsigned char *s) 
{
	EA=0;
    if (y == 0) 
    {
    	LCD_write_com(0x80 + x);        //第一行显示
    }
    else 
    {
    	LCD_write_com(0xC0 + x);        //第二行显示
    }
    
    while (*s) 
    {
    	LCD_write_data( *s);
    	s ++;
    }
 EA=1;
}

//***********************************************************************
//	显示一个数字 传入坐标和数值
//***********************************************************************
void LCD_dis_TIME(unsigned char x,unsigned char y, int hour,int min,int sec) 
{
	  char disp[10];
	  memset(disp,0,10);
	sprintf(disp,"%02d:%02d:%02d",hour,min,sec);
	  LCD_write_str(x,y,disp);
    
}

//***********************************************************************
//	显示屏初始化函数
//***********************************************************************
void LCD_init(void) 
{
	 LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
	 LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
	 LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
	
	
    LCD_write_com(0x38);		//显示模式设置  
    delay_lcd_ms(5);
    LCD_write_com(0x08);		//显示关闭
    delay_lcd_ms(5);
    LCD_write_com(0x01);		//显示清屏
    delay_lcd_ms(5);
    LCD_write_com(0x06);		//显示光标移动设置
    delay_lcd_ms(5);
    LCD_write_com(0x0C);		//显示开及光标设置
    delay_lcd_ms(5);
}

猜你喜欢

转载自blog.csdn.net/x1131230123/article/details/107367470