基于STC8H8K64U的音乐播放器

//导入自定义的头文件
#include "TOOL.H"

/*
TOOL.H 文件内容:
	关键字重命名
		typedef unsigned char u8;
		typedef unsigned int  u16;
		typedef unsigned long u32;
	
	自定义的全局变量
		u8 num = 0;
			用于记录按键值
		u8 num_sound
			记录乐段值
		u16 scale_L[] = {170, 185, 208, 220, 247, 277, 311};
		u16 scale_M[] = {340, 370, 415, 440, 494, 554, 622};
		u16 scale_H[] = {680, 740, 830, 880, 988, 1108, 1244};
			记录E调频率
		u8 Music_mp3[][]
			存放乐谱
		u8	rhythm
			确定当前乐曲节奏
			
	自定义的函数
		void Init(void);
			用于初始化操作(包括引脚定义,定时器,中断)		
		void Delay_ms(u16 ms)
			用于产生毫秒级延时,参数ms
		void Next(void)interrupt 0
		void Last(void)interrupt 2
			用于按键加减的中断函数
		void Frequency(u8 temp)
			用于计算频率值
		void Timer0(void)interrupt 1
			用于发生频率的中断函数
		u16 Meter(u8 temp)
			用于计算当前节时间

*/

void main(void)
{
	//临时变量
	u16 temp = 0;
	//定时器1的溢出计数器
	u16 sound1 = 0;
	//记录当前节
	u8 val = 0;
	//缓存一些数据
	u8 cache1 = 0;
	u8 cache2 = 0;
	//初始化
	Init();
	//得到当前乐曲整体节拍
	rhythm = Music_mp3[num][0];
	//开始计数
	TR0 = 1;
	TR1 = 1;
	while(1)
	{
		//获取当前节
		val = Music_mp3[num][num_song];
		//读取结束符
		if(val == 0x00)
		{
			//结束后自动下一首
			num++;
			//结束本次循环
			break;
		}
		if(TF1)
		{	
			//获取当前节拍
			temp = Meter(val);			
			//计数器1 加1
			sound1++;
			//满足条件,进入下一节乐段
			if(temp <= sound1)
			{
				cache1 = Music_mp3[num][num_song];
				//进入下一节
				num_song++;
				//用于判断是否断音
				 cache2 = Music_mp3[num][num_song + 1];					
				//获取当前音名
				cache1 &= 0x07;
				cache2 &= 0x07;
				//标志计数器置零
				sound1 = 0;
				//当前音名与下一音相同时,暂停一瞬
				if(cache1 == cache2)
				{
					//暂时关闭脉冲
					ET0 = 0;
					//拉高P10电平
					P10 = 1;
					//短暂延时,分开音符
					Delay_ms(60);
					//继续发送信号
					ET0 = 1;
				}	
				//更新频率发生
				val = Music_mp3[num][num_song];
				Frequency(val);
			}	
			//计时器1 溢出位 置零
			TF1 = 0;
		}
	}
}

  

主函数部分无非就是一些代码的注释,定时器0,1使用了两种不同的溢出处理方式,效果差别不大,以下是“TOOL.H”的内容曲目暂时写了一份《生生世世爱》,感兴趣可以自己试着加一些新的曲子。

#include "STC8H.H"
#define Music_MAX 3

typedef unsigned char u8;
typedef unsigned int  u16;
typedef unsigned long u32;

void Frequency(u8 temp);

u8 rhythm = 100;

void Init()
{	
	//XFR寄存器访问使能
	P_SW2 |= 0x80;
	
	//将以下 IO 口设置为准双向口
	P0M0 = 0x00;
	P0M1 = 0x00;
	P1M0 = 0x00;
	P1M1 = 0x00;
	P2M0 = 0x00;
	P2M1 = 0x00;
	P3M0 = 0x00;
	P3M1 = 0x00;
	P4M0 = 0x00;
	P4M1 = 0x00;
	P5M0 = 0x00;
	P5M1 = 0x00;
	P6M0 = 0x00;
	P6M1 = 0x00;
		
	//外中断中断标志位
	IE0 = 0;
	IE1 = 0;
	//INT 中断使能
	EX0 = 1;
	EX1 = 1;
	//INT中断下降沿使能
	IT0 = 1;
	IT1 = 1;
	
	//工作时钟不分频
	AUXR |= 0xC0; 	
	//设置定时器计数模式
	TMOD = 0x00;
	//设置定时器0
	Frequency(0x2b);
	//设置定时器1 
	TH1 = 0xD1;	
	TL1 = 0x20;
	//开启定时器中断
	ET0 = 1;
	
	//开启总中断	
	EA = 1;
}

//毫秒级延时函数,参数ms
void Delay_ms(u16 ms)
{
	unsigned char i, j;
	while(ms--)
	{
		i = 16;
		j = 147;
		do
		{
			while (--j);
		} while (--i);
	}
}

//记录曲谱位置
u8 num = 0;
//记录当前播放位置
u8 num_song = 1;


//MUSIC 部分

//E调基本音频率
u16 scale_L[] = {0, 170, 185, 208, 220, 247, 277, 311};
u16 scale_M[] = {0, 340, 370, 415, 440, 494, 554, 622};
u16 scale_H[] = {0, 680, 740, 830, 880, 988, 1108, 1244};

//高往低数
//1-3 位表示音符 1-7
//4-5 位表示音域 00-10  低 中 高
//6-8 位表示时值 000-101 16分 - 8
u8 code Music_mp3[Music_MAX][300] = {
{
	50,
	0x2B,0x31,0x2F,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x4F,0x2F,0x2F,
	0x2B,0x31,0x2F,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x32,0x53,0x33,
	0x31,0x32,0x53,0x52,0x51,0x52,0x6F,0x4E,0x31,0x6F,0x31,0x52,0x31,0x33,
	0x33,0x14,0x13,0x32,0x33,
	0x53,0x31,0x2F,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x4F,0x2F,0x2F,
	0x2b,0x31,0x2F,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x0E,0x0F,0x2E,0x2D,0x2E,0x32,0x53,0x33,
	0x31,0x32,0x53,0x52,0x51,0x52,0x6F,0x4E,0x31,0x6F,0x31,0x52,0x31,0x33,
	0x33,0x14,0x13,0x32,0x33,0x93,
	0x6B,0xFF,0x2A,0x29,0x67,0xFF,0x29,0x2A,0x6B,0xFF,0x2B,0x2A,0x2B,0x29,0x67,0xFF,0x49,
	0x4A,0xFF,0x49,0x4A,0xFF,0x2A,0x2A,0x2A,0x2A,0x2A,0x54,0x2A,0x6B,0xFF,
	0x6B,0xFF,0x2A,0x29,0x67,0xFF,0x29,0x2A,0x6B,0x0B,0x2B,0x2B,0x4B,0x2A,0x29,0x67,0xFF,
	0x6B,0xFF,0x29,0x6A,0x0A,0x2A,0x4A,0x4C,0x2A,0x4B,0xFF,
	0x4B,0x4A,0x09,0x4B,0x29,0x4A,0x4A,0x09,0x4A,0x09,0x07,
	0x66,0x06,0x26,0x27,0x29,0x4B,0x6A,0x2B,0x6B,0x2B,0x4C,0x4B,0x0A,0x6A,0x2A,
	0x4B,0x4A,0x09,0x69,0x26,0x26,0x27,0x27,0x29,0x4A,0x29,0x2B,0x2C,0x2A,0x4C,
	0x4B,0x4A,0x09,0x4B,0x29,0x4A,0x4A,0x09,0x4A,0x09,0x07,
	0x66,0x06,0x26,0x27,0x29,0x4B,0x6A,0x2B,0x6B,0x2B,0x4C,0x4B,0x0A,0x6A,0x2A,
	0x4B,0x4A,0x09,0x69,0x26,0x26,0x27,0x27,0x29,0x4A,0x29,0x2B,0x4A,0x29,0x09,0x27,
	0x07,0x26,0x86,0xFF,0x00
},
{
	50,
	0x4E,0x53,0x15,0x33,0x0E,0x51,0x0E,0x11,0x0E,0x11,0x43,0x13,0x12,0x13,0x11,0x4E,
	0x43,0x15,0x36,0x36,0x36,0x33,0x55,0x13,0x35,0x13,0x35,0x2E,0x33,0x32,0x33,0x51,
	0x52,0x52,0x32,0x11,0x12,0x33,0x35,0x56,
	0x00
},
{
	60,
	0x06,0x06,0x2B,0x2B,0x46,0xFF,0x06,0x06,0x26,0xFF,
	0x06,0x06,0x2B,0x2B,0x46,0xFF,0x06,0x06,0x26,0xFF,
	0x06,0x06,0x26,0x06,0x06,0xFF,0x06,0x06,0x26,0xFF,
	0x06,0x06,0x2B,0x2B,0x06,0xFF,0x06,0x06,0x26,0xFF,
	0x00
}
};

//用于计算乐段频率 
void Frequency(u8 temp)
{
	u16 val;
	//提取音域
	switch((temp & 0x18) >> 3)
	{
		case 0:
			//提取音符
			val = scale_L[temp & 0x07];
			//计算延时,一次性运算有出错风险
			val = 1000000 / val;
			//脉冲二分频
			val = val/2;
			//得到微秒级延时
			val = val * 12;
			//得到定时器初值
			val = 65536 - val;
			//取得高八位数 置入TH0
			TH0 = (val & 0xFF00) >> 8;
			//获取低八位数 置入TL0
			TL0 = (val & 0x00FF);
			return;
		case 1:
			val = scale_M[temp & 0x07];
			val = 1000000 / val;		
			val = val/2;
			val = val * 12;
			val = 65536 - val;
			TH0 = (val & 0xFF00) >> 8;
			TL0 = (val & 0x00FF);
			return;			
		case 2:
			val = scale_H[temp & 0x07];
			val = 1000000 / val;		
			val = val/2;
			val = val * 12;
			val = 65536 - val;
			TH0 = (val & 0xFF00) >> 8;
			TL0 = (val & 0x00FF);
			return;
		case 3:
			ET0 = 0;
			P10 = 1;
			num_song++;
			Delay_ms(150);		
			ET0 = 1;
			return;			
	
	}	
}

//定时器0 中断函数,用于发生频率
void Timer0(void)interrupt 1
{
	//计时器0溢出位 置零
	TF0 = 0;
	//发射脉冲信号
	P10 = ~P10;
}

//用于返回当前乐段节拍
u16 Meter(u8 temp)
{	
	u16 val;
	switch((temp & 0xE0) >> 5)
	{
		case 0:
			val = 60000/rhythm;
			val = val / 16;
			return val;
		case 1:
			val = 60000/rhythm;
			val = val / 8;
			return val;		
		case 2:
			val = 60000/rhythm;
			val = val / 4;
			return val;
		case 3:
			val = 60000/rhythm;
			val = val / 2;
			return val;
		case 4:
			val = 60000/rhythm;
			val = val;
			return val;
		case 5:
			val = 60000/rhythm;
			val = val * 4;
			return val;
	}
}

//外部中断函数0 作用:变量加一
void Next(void)interrupt 0
{
	EA = 0;	
	P0 = ~P0;
	if(num >= Music_MAX - 1)
	{
		return;
	}
	num++;	
	num_song = 1;
	//得到当前乐曲整体节拍
	rhythm = Music_mp3[num][0];
	//防抖动
	Delay_ms(500);
	EA = 1;
}

//外部中断函数1 作用:变量减一
void Last(void)interrupt 2
{
	EA = 0;	
	P0 = ~P0;
	//num等于0时无需防抖动
	if(num == 0)
	{
		return;
	}
	//得到当前乐曲整体节拍
	rhythm = Music_mp3[num][0];
	num--;
	num_song = 0;
	//防抖动
	Delay_ms(500);
	EA = 1;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值