📄 mp3.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 + -