⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3.c

📁 用89C51SND1C实现MP3播放器的源代码.用KEIL c51编写.
💻 C
字号:
/****************************************************************/
/*					UP-MP3DIY100								*/
/*		Beijing Universal Pioneering Technology Co., LTD		*/
/*		CopyRighted,All right Reserved	www.up-tech.com			*/
/*						July,2003								*/
/*				010-62387873  62381842							*/
/****************************************************************/

#include "REGSND1.H"
#include "atmelusbci.h"
#include "uart.h"
#include "usbdisk.h"
#include "bulk_only.h"
#include "fat16.h"
#include "flash.h"

int m=0;

extern unsigned char bulk_state;//记录USB传输过程中传输状态
extern unsigned char Bulk_Out_Buf[];//Bulk-Out端点缓存区
extern unsigned char Page_Buf[];//页(扇区)缓存区

extern unsigned char FirstTransaction;
//设备描述符
code unsigned char Device_Descriptor[18]={
								    	0x12,			//0x12
										 0x01,              //DEVICE descriptor
										 0x10,0x01,         //spec rev level (BCD) 1.0
										 0x0,              //device class
										 0x0,              //device subclass
										 0x0,              //device protocol
										 0x20,              //max packet size
										 0x05,0x82,         //National's vendor ID
										 0x00,0x11,         //National's product ID  
										 0x00,0x00,         //National's revision ID  
										 0,                 //index of manuf. string   
										 0,                 //index of prod.  string  
										 0,                 //index of ser. # string   
										 0x01               //number of configs. 	
									};
//配置描述符
code unsigned char Configuration_Descriptor_All[32]={

									    9,//Size of Descriptor in Bytes
									    2,//Configuration Descriptor (0x02)
									    0x20,//Total length in bytes of data returned  LSB
										0x00,//MSB
										1,//Number of Interfaces
										1,//Value to use as an argument to select this configuration
									    0,//Index of String Descriptor describing this configuration
										0x80,
										0xfa,//Maximum Power Consumption in 2mA units 
									
									    9,
									    4,
									    0,//the index of the interface descriptor Number of Interface
									    0,//Value used to select alternative setting
										2,//EndPoint Number Used in this Descriptor
										8,//Class Code (Assigned by USB Org)
										6,	//interface subclass1=RBC,2=SFF,3=QIC,4=UFI,5=SFF,6=SCSI
										0x50,//bulk 0nly Transport
										0,//Index of String Descriptor Describing this interface

										 //Bulk-in Endpoint
										 0x07,              //length of this desc.   
										 0x05,              //ENDPOINT descriptor TYPE
										 0x81,              //address (IN) Endpoint 4 84
										 0x02,              //attributes  (BULK)    
										 0x40,0x00,         //max packet size (64)
										 0x0,              //Does not apply to Bulk endpoints
							
										 //Bulk-out Endpoint
										 0x07,              //length of this desc.   
										 0x05,              //ENDPOINT descriptor TYPE
										 0x02,              //address (OUT) Endpoint 5 05
										 0x02,              //attributes  (BULK)
										 0x40,0x00,         //max packet size (64)
										 0x0             //Does not apply to Bulk endpoints
										};

//用于存放歌曲列表的数组
unsigned char SONG[88] ={'M','O','O','N',' ',' ',' ',' ','T','X','T'};

//MP3有关的变量*********************
#define VOLUME		1
#define EFFECTION	2
#define SELECTSONG	3
#define PLAY		1
#define STOP		0
unsigned char CurrentFun=SELECTSONG;
unsigned char PlayState=PLAY;
unsigned char ChangeSong=0;

unsigned char NowPlaying=0;
unsigned char NumofSong=0;
extern long int DataRead;
//***************************

//USB DISK 
//读端点数据
unsigned char ReadEp(unsigned char EpNum,unsigned char *Data)
{
	unsigned char i=0,nLength;
	UEPNUM=EpNum;//指向相应端点

	nLength=UBYCTX;//读取端点数据长度
	while(nLength--) {Data[i++]=UEPDATX;/*printuf("%x ",Data[i]);*/}//依次读取端点收到的数据

	UEPSTAX&=~(RXOUTB0|RXOUTB1|RXSETUP);//清中断标志
	
	return(i);//返回读取到的数据的长度
}

//向端点0写数据
void WriteEp(unsigned char EpNum,unsigned char nLength,unsigned char *Data)
{
	unsigned char i=0;
	UEPNUM=EpNum;//指向相应端点
	UEPSTAX|=DIR;//设置方向为写
	while(nLength--) UEPDATX=Data[i++];//将数据写入端点
	UEPSTAX|=TXRDY;//发送数据Sending the data,this action will switch between bank0 and bank1
	while(!(UEPSTAX&TXCMP)) ;//等待发送完成
	UEPSTAX&=(~(TXCMP));//清中断标志clear TXCMP
}
//写Bulk端点
void WriteEpBulk(unsigned char EpNum,unsigned char nLength,unsigned char *Data)
{
	unsigned char i;
	UEPNUM=EpNum;//指向相应端点
	UEPSTAX|=DIR;//设置方向为写Set for status of a Control In transaction
	for(i=0;i<nLength;i++) UEPDATX=Data[i];//将数据写入端点
	UEPSTAX|=TXRDY;//发送数据Sending the data,this action will switch between bank0 and bank1
	
}
void Get_Status()
{
	printu("Get_Status ");
}
void Clear_Feature()
{
	printu("Clear_Feature ");
}
void Set_Feature()
{
	printu("Set_Feature ");
}
void Set_Address(unsigned char EpNum)
{
//	unsigned char Test[]={0};
	WriteEp(0,0,0);//在Status阶段过后才能改变设备地址

	USBADDR|=EpNum;//设置地址
	USBADDR|=FEN;//地址使能
	USBCON|=FADDEN;

//	printuf("\nSet_Address:%x\n",USBADDR);
}
void Get_Descriptor(unsigned char DesType,unsigned char nLength)
{
	if(DesType==0x01) WriteEp(0,18,Device_Descriptor);//提供设备描述符
	if((DesType==0x02)&&(nLength==0x09)) WriteEp(0,9,Configuration_Descriptor_All);//提供配置描述符
	//提供全部描述符
	if((DesType==0x02)&&(nLength==0xff)) {WriteEp(0,32,Configuration_Descriptor_All);WriteEp(0,2,&Device_Descriptor[4]);}
	//提供全部描述符
	if((DesType==0x02)&&(nLength==0x20)) {WriteEp(0,32,Configuration_Descriptor_All);}

//		printu("Get_Descriptor\n");
}
void Get_Configuration()
{
	printu("Get_Configuration ");
}
void Set_Configuration(unsigned char wValue)
{

	if(wValue == 0) {
	/* put device in unconfigured state */
		 /* Disable all endpoints but EPP0. *///init_unconfig

 		UEPNUM=0x00;//Ep0 as control Endpoint
		UEPCONX=0x80;
	
		UEPNUM=0x01;//Ep1 as Bulk-in Endpoint
		UEPCONX=0x86;
	
		UEPNUM=0x02;//Ep2 as Bulk-out Endpoint
		UEPCONX=0x82;

//		WriteEp(0,&Device_Descriptor[4],2);
		USBCON&=(~CONFG);
		WriteEp(0,0,0);//状态传送阶段之前完成指定操作

	}
	else if(wValue == 1) {
	/* Configure device */
		/* Enable generic/iso endpoints. init_config*/

		UEPNUM=0x00;//Ep0 as control Endpoint
		UEPCONX=0x80;
	
		UEPNUM=0x01;//Ep1 as Bulk-in Endpoint
		UEPCONX=0x86;
	
		UEPNUM=0x02;//Ep2 as Bulk-out Endpoint
		UEPCONX=0x82;


		USBCON|=CONFG;
		WriteEp(0,0,0);//状态传送阶段之前完成指定操作

	}
//	printu("Set_Configuration ");
}
void Get_Interface()
{
	printu("Get_Interface ");
}
void Set_Interface()
{
	WriteEp(0,0,0);
	printu("Set_Interface ");
}

void Ep0Int()
{
	unsigned char i,j;
	unsigned char ControlData[32]={0,};
	i=ReadEp(0,ControlData);//读端点0
	P3_5 = 0;//USB通信指示灯点亮
	j=ControlData[0]&0x60;//过滤端点0数据
	if((j==0)&&i){//如果为标准USB请求
	switch(ControlData[1]){//分别按请求类别进行处理
			case get_status			:	Get_Status();break;
			case clear_feature 		:	Clear_Feature();break;

			case set_feature		:	Set_Feature();break;

			case set_address		:	Set_Address(ControlData[2]);break;
			case get_descriptor		:	Get_Descriptor(ControlData[3],ControlData[6]);break;

			case get_configuration	:	Get_Configuration();break;
			case set_configuration	:	Set_Configuration(ControlData[2]);break;
			case get_interface		:	Get_Interface();break;
			case set_interface		:	Set_Interface();break;
			default					:	Reserved();break;
		}
	}
	else if(ControlData[0]==0xa1){//特殊请求,特殊处理,直接返回Status
			WriteEp(0,0,0);
		}
	
	P3_5 = 1;//USB通信指示灯关闭

}

//Bulk-In端点处理
void main_txdone()
{
//	printuf("Bulk_State:%x\n",bulk_state);
	P3_5 = 0;////USB通信指示灯点亮

	UEPSTAX&=(~(TXCMP));//清中断标志位clear TXCMP
	switch(bulk_state){//按不同的传输状态,进行不同的后续处理
		case BULK_DATA_TRANS:
			TransDataGoOn();
			break;
		case BULK_DATA_END:
			TransmitCSW();
			break;
		case BULK_REQEST_TRANS:
			TransRequestGoOn();
			break;
		case BULK_CSW_END:
			break;
		default:	return;
		}
	P3_5 = 1;//USB通信指示灯关闭
}

//Bulk-Out端点处理
void main_rxdone()
{
//	printu("\nmain_rxdone  ");
	P3_5 = 0;//USB通信指示灯点亮
	ReadEp(2,Bulk_Out_Buf);//读取端点2
	if((bulk_state != BULK_DATA_RECIEVE) &&(Bulk_Out_Buf[0] == 0x55)) InterpretCBW();//判断是否为命令数据
	else Trans_Data2PC();	//为普通数据时转向数据接收处理程序
	P3_5 = 1;//USB通信指示灯关闭

}
void Reserved()
{
	printuf("Undefined Interrupt Occured:%x\n",UEPINT);
}
//END OF USB DISK


void MP3Init()
{

//	printuf("Ready to set the pll clock\n");
	AUXR1=0xf2;	//这两个寄存器的值在用Start Application和直接上电时不一样,前一种情况下MP3蟹码器才工作,
	PLLCON=0;	//这里强制将其置为与用Start Application按钮时一致

	//锁相环时钟及MP3解码器时钟设置
	PLLNDIV=0x03;						//pll 84,000,000 1 13 7, 3 6 1, 1 6 3, 336000000 0,1b,1f
	PLLRDIV=0x06;						//pll 72M mp3clk 36M audclk 7.2M(3,6,a)
										//	  92M        
	PLLCON=PLLCON|PLLEN;
	PLLCON=PLLCON|PLOCK;

	MP3CLK=0x02;

	//MP3音量及音效初始值
	MP3VOR=0x0f;
	MP3VOL=0x0f;
	MP3BAS=0x0f;
	MP3MED=0x0f;
	MP3TRE=0x0f;

	//音频解码器模式及时钟设置
	AUDCON0=0x77;
	AUDCON1=0x41;
	AUDCLK=0x05;	// 1a

//	AUDCON0=0x76;	//HLR=0,256X
//	AUDCON1=0x41;
//	AUDCLK=0x08;	// 1a
//	printuf("MP3STA:%x\n",MP3STA);

	MP3CON&=(~MSKREQ);	//允许产生MP3中断Clear to allow the MPREQ flag to generate a MP3 interrupt.

	MP3CON|=MPEN;	//使能MP3解码器Set to enable the MP3 decoder.


	CKCON=0x01;		//使能X2模式,增加处理速度

}
//播放MP3歌曲
void PlayMP3(unsigned char *SongName)
{
		int i=0,j=0;

		//First 1024 Byte MP3 Data
		m=ReadSector(SongName,Page_Buf);//从当前歌曲中读取512字节
		if(MP3STA1&MPFREQ)	//解码器数据请求中断产生时
		{
			for(i=0;i<1024;i++)//第一次要向解码器缓存中置入1024字节
			{
				if(j==512)//当用完512字节时
				{
					m=ReadSector(SongName,Page_Buf);//读取当前歌曲的下一个512字节
					j=0;
				}
				MP3DAT=Page_Buf[j++];//向MP3解码器数据寄存器送入一个数
				while(!PlayState) ;	//如果是暂停状态则等待
				while(ChangeSong) {DataRead=0;ChangeSong=0;return;}//如果选曲时,则重新播放当前曲目
				while(!(MP3STA1&MPBREQ));//等待中断再次产生

			}
		}
	
		//Other MP3 data
//		while(1){
			while(MP3STA1&MPFREQ)	{//解码器数据请求中断产生时
					if(j==512){//当用完512字节时
						j=0;
						if(m<512) {NowPlaying++;return;}//如果上一次从歌曲中读出的数据不足512时,则结束本歌曲播放

						m=ReadSector(SongName,Page_Buf);//读取当前歌曲的下一个512字节
						}
					MP3DAT=Page_Buf[j++];//向MP3解码器数据寄存器送入一个数
					while(!PlayState) ;//如果是暂停状态则等待
					while(ChangeSong) {DataRead=0;ChangeSong=0;return;}//如果选曲时,则重新播放当前曲目
					while(!(MP3STA1&MPBREQ)) ;//等待中断再次产生
					}
//			}
	
}

void KeyBoardInit()
{
	P1=0x0f;	//将端口1的低四位,即键盘对应的4位置1
	KBCON=0x00;//设置键盘有效模式为低电平有效,并使能中断Low Level,Enable Interrupt
	IEN1=IEN1|EKB;	//使能键盘中断Enable KeyBoard Interrupt

}

void Func()
{
		if(CurrentFun<3) CurrentFun++;//在选曲/音量调节/音效调节三者间切换
		else if(CurrentFun==3) CurrentFun=1;
}
void Next()//按下"下一首/音量减小"键时的处理
{

	switch(CurrentFun){//如果当前处于音量调节功能
		case VOLUME		:
			{
			if(MP3VOR>0x00)//当前音量没有达到最小时
			{
			MP3VOR-=0x01;//右声道音量增大一档
			MP3VOL-=0x01;//左声道音量增大一档
			}

			break;
			}
		case EFFECTION	://如果处于音效调节功能
			{
			if(MP3BAS>7){//降低重音效果
				MP3BAS-=7;
				MP3MED=0x0f;	
				MP3TRE+=7;
				}
			break;
			}
		case SELECTSONG	://如果处理MP3选取功能
			{
			if(NowPlaying==(NumofSong-1)) NowPlaying=0;//如果已经处于最后一首了,则指向第一首
			else NowPlaying++;	//否则,指向下一首
			ChangeSong=1;		//置选曲标志位
			break;
			}
		default:break;
	}
}
void Previous()//按下"上一首/音量增大"键时的处理
{
	switch(CurrentFun){
		case VOLUME		://如果当前处于音量调节功能
			{
			if(MP3VOR<0x1f)//当前音量没有达到最大时
			{
			MP3VOR+=0x01;//右声道音量增大一档
			MP3VOL+=0x01;//左声道音量增大一档
			}

			break;
			}
		case EFFECTION	://如果处于音效调节功能
			{
			if(MP3BAS<0x1d){//增加重音效果
				MP3BAS+=7;
				MP3MED=0x0f;	
				MP3TRE-=7;
				}
			break;
			}
		case SELECTSONG	://如果处理MP3选取功能
			{
			if(NowPlaying>0)NowPlaying--;//如果当前播放歌曲不为第一首,则指向上一首
			else NowPlaying=NumofSong-1;//如果当前已经到达第一首,则指向最后一首
			ChangeSong=1;				//置选曲标志位
			break;
			}
		default:break;
	}
}
void PlayPause()
{
	PlayState=!PlayState;	//按一下播放键时,改变播放状态

}
void key_interrupt() interrupt 11
{
		unsigned char i=0;
		EA=0;			//关中断
		IEN1&=(~EKB);	//Enable KeyBoard Interrupt
		i=KBSTA;		//取键盘中断位
		switch(i){		//依次处理四个键中的某个键被按下时的情况
			case 1:	Func();break;
			case 2:	Next();break;
			case 4:	Previous();break;
			case 8: PlayPause();break;
			default:break;
		}
		IEN1|=EKB;	//Enable KeyBoard Interrupt
		EA=1;		//开中断
		return;
}

void main()
{

//	int i,j;
	printu("UP-TECH MP3 Player Test!\n");
	P3_5 = 0x01;//USBLED off
	P3_3 = 0;	//P3_3=0 LCD Power off,P3_3=1 LCD Power on

	printu("Entering MP3...\n");
	Flash_Reset();//Flash复位
	MP3Init();//MP3初始化
	KeyBoardInit();//键盘初始化

	EA=1;//开中断,键盘可以开始工作
	NumofSong=GetMP3List();//得到U盘中的MP3歌曲列表
	printuf("Song:%x\n",NumofSong);//输出歌曲总数信息
	if(NumofSong==0) printu("There is no MP3 file in USB Disk!\n");
	P3_5=0;//打开USB灯亮

	while(1) {
		if(NumofSong!=0) PlayMP3(&SONG[11*NowPlaying]);//如果处于播放状态,则播放当前歌曲
		if(NowPlaying==NumofSong) PlayState=STOP;			//全部歌曲播放完了,播放器停止
	}

}		


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -