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

📄 main.c

📁 采用Mega16+VS1011B+SD卡制作的Mp3
💻 C
📖 第 1 页 / 共 2 页
字号:
//*********************************************
 //主程序Main.C
 //MCU:AVR_MEGA16L ,晶振频率:8.0 MHz
 //制作人:平顶山工学院计算机系,郭猛
//**********************************************
# include "stdlib.h"
# include "iom16v.h"
# include "macros.h"
# include "LCDFun.h"
# include "fat.h"
# include "ProString.h"
# include "MMC.h"
# include "VS1011B.h"

#ifndef uchar
	#define uchar unsigned char
#endif

#define uint8 unsigned char
#define uint16 unsigned int
#define uint32 unsigned long

//4个控制按键接口:
#define KEY01  		0	//PB0    前进
#define KEY02 		1	//PB1
#define KEY03		2	//PB2
#define KEY04       3   //PB3
//KEY01,KEY02,KEY03,KEY04输入
# define KeyOutput() DDRB|=(BIT(KEY01)|BIT(KEY02)|BIT(KEY03)|BIT(KEY04))
# define KeyIni()    PORTB|=(BIT(KEY01)|BIT(KEY02)|BIT(KEY03)|BIT(KEY04))
# define KeyInput()  DDRB&=~(BIT(KEY01)|BIT(KEY02)|BIT(KEY03)|BIT(KEY04))
# define KeySt01    (PINB&=BIT(KEY01))  //获取KEY01状态
# define KeySt02    (PINB&=BIT(KEY02))  //获取KEY02状态
# define KeySt03    (PINB&=BIT(KEY03))  //获取KEY03状态
# define KeySt04    (PINB&=BIT(KEY04))  //获取KEY04状态

//外部函数、变量的引用声明
extern unsigned char SecPerClus;	//每个簇占用的扇区数目,1GB的SD卡应为8
extern unsigned long data_offset;	//数据区的起始扇区数,FAT32的根目录区和数据区重合:

extern unsigned char ShowText_main;
extern unsigned char *pointer_FDT; //用于指向找到指定文件的文件名
extern unsigned long old_pos_blk,FirstRootDirSecNum;

extern unsigned char CurSongTim[3];		//当前歌曲的播放时间 分:秒:百秒
extern unsigned char TotalSongTim[4];	//当前歌曲的播放时间 时:分:秒:百秒

extern void E2PROM_Write(unsigned int IAddress,unsigned char *Data,unsigned char Cnt);
extern unsigned char E2PROM_Read_OneChar(unsigned int IAddress);
extern void ADC_Init(void);
extern unsigned char ADC_Convert(void);
extern void MCUMode(uchar iMode);

unsigned char buff[512];				//用于暂存读取一扇区的数据缓冲
unsigned char Mp3FileName[8];			//用于保存Mp3歌曲文件名,8字节短名格式
unsigned char CurVol,CurBass;	//当前音量,低音量
unsigned char Lcdak=1,UsrSel=0;			//背光开关,用户选择菜单项
unsigned char SWPlayTime=1; 			//时间开关
unsigned char SWSpeaker=1,SWIRRemoteMode=1; //扬声器开关,遥控制式
unsigned char CurStatus=0;				//播放器当前状态
unsigned long FONT_ClusterVar;	   		//找到字库文件的起始簇号
unsigned int DEF_MAX_SONGS=0;           //SD卡根目录下歌曲数目.

void IniData_From_EEPROM(void)			//从E2PROM中读取音量、低音信息
{ unsigned char i,j,k;
  CurVol=E2PROM_Read_OneChar(0);
  CurBass=E2PROM_Read_OneChar(1);
}

//DisplayNumChar用于显示百、十、个的数字值
//l,h: 行、列位置
//ll:要显示的数值
//ShowBit:3,显示百,十,个,位;2,显示十,个,位
void DisplayNumChar(unsigned char h,unsigned char l,unsigned char ll,unsigned char ShowBit)
{
  unsigned char hunum,tnnum,srnum;  //百、十、个位
  hunum=ll/100; 	//百位
  srnum=ll%10;		//个位
  tnnum=(ll-hunum*100)/10; //十位
  
  hunum+=0x30;srnum+=0x30;tnnum+=0x30;
  if(ShowBit==3)		//显示百,十,个,位
  {
     PrintOneASCII(h,l,hunum);PrintOneASCII(h,l+8,tnnum);
	 PrintOneASCII(h,l+16,srnum);
  }
  else if(ShowBit==2)	//显示十,个,位
  {
	 PrintOneASCII(h,l,tnnum);PrintOneASCII(h,l+8,srnum);
  }
}

//DisplayNumInt该函数主要用于测试显示中间变量
void DisplayNumInt(unsigned char h,unsigned char l,unsigned int ll,unsigned char ShowBit)
{
  unsigned char hunum,tnnum,srnum;  //百、十、个位
  hunum=ll/100; 	//百位
  srnum=ll%10;		//个位
  tnnum=(ll-hunum*100)/10; //十位
  
  hunum+=0x30;srnum+=0x30;tnnum+=0x30;
  if(ShowBit==3)		//显示百,十,个,位
  {
     PrintOneASCII(h,l,hunum);PrintOneASCII(h,l+8,tnnum);
	 PrintOneASCII(h,l+16,srnum);
  }
  else if(ShowBit==2)	//显示十,个,位
  {
	 PrintOneASCII(h,l,tnnum);PrintOneASCII(h,l+8,srnum);
  }
}

//从SD卡上读取汉字字型信息,输入汉字的内码号(常指针),返回汉字的字型指针
unsigned char * MMCFntHZ(unsigned char *buffp,unsigned char *HzChr)	
{
    unsigned int  InOffset;
	unsigned long Blk,Hzpt,FntStartBlk;		//字库文件的起始扇区
	unsigned char HzNmH,HzNmL;
	unsigned char flgover;
	unsigned char Dir_Attrib = 0;
	//汉字在汉字库中的位置=汉字点阵数*[(区码-A0h-1)*94+(位码-A0h-1)]
	HzNmH=HzChr[0];HzNmL=HzChr[1];
	//显示内码:
	//DisplayLong(HzNmH*65536+HzNmL,3);
	//Delay(500);
	/////
	Hzpt=32*((HzNmH-0xA0-1)*(unsigned long)94+(HzNmL-0xA0-1));
	//显示汉字字型在字库中的位置:
	//DisplayLong(Hzpt,1);
	//Delay(500);
	/////
	//由汉字内码,计算它所在的扇区号和偏移位置
	Blk=Hzpt/512;InOffset=Hzpt%512;  //512是每个扇区的大小
	//显示汉字字型在字库中的位置(扇区为单位):	
	//DisplayLong(Blk*65536+InOffset,2);
	//Delay(500);
	//////////////////
	//读取该文件:
	MMC_SD_ReadSingleBlock((FONT_ClusterVar-2)*SecPerClus+data_offset+Blk,buffp);
	//flgover = fat_read_file(FONT_ClusterVar,buffp,Blk,&Dir_Attrib);						
	//返回汉字字型信息指针:
	return (buffp+InOffset);
}

//在指定位置,打印指定长度的16*16汉字字符串
//Hz:汉字字符串指针(常指针),buffp:用于存放汉字字型信息的Buf,
//(x0,y0):字符串在LCD上的起始位置,Lens:字符串长度
void PrintHZ16(unsigned char *Hz,unsigned char *buffp,unsigned char x0,unsigned char y0,unsigned char Lens)
{
	unsigned char i,*HzPt;
	unsigned char x,y;
	x=x0;y=y0;
	for(i=0;i<Lens;i+=2)
	{
	 	//测试使用,显示内码:
		//DisplayLong(Hz[i]*65536+Hz[i+1],3);
	    //Delay(500);
	    if(Hz[i]>127 && Hz[i+1]>127)		  //均是汉字
		{
			HzPt=MMCFntHZ(buffp,Hz+i);
			PrintOneHZ(x,y,HzPt);
			y+=16;
		}else if(Hz[i]<128 && Hz[i+1]<128) 	  //有英文字符在里面
		{
		    PrintAscStr(x,y,Hz+i,2);
			y+=16;
		}
		if(y>=128) {y=0;x+=2;}
		if(x>7){x=0;}
	}
}

void ChangeVS1011Vol(uchar *Vol)	   //调整播放音量
{
  unsigned char retry;
  unsigned int Tmp;
  PrintConstAscStr(0,0,ScreenStr12[11],16);
  PrintConstAscStr(2,0,ScreenStr12[12],16);
  PrintConstAscStr(3,0,ScreenStr12[13],16);
  PrintConstAscStr(6,0,ScreenStr12[14],16);
  KeyIni();KeyInput();
  while(1)
  {
  if(KeySt02==0)	  //Volume++,减小音量
  {
	//等待该键释放
	Delay(200);
	while(KeySt02==0) Delay(200);	  
	(*Vol)++;
	if((*Vol)>=255) *Vol=255;
  } 
  else if(KeySt03==0)	  //Volume--,增大音量
  {
	//等待该键释放
	Delay(200);
	while(KeySt03==0) Delay(200);	  
	(*Vol)--;
	if((*Vol)<=0) *Vol=0;
  }
  else if(KeySt04==0)	   //确定退出
  {//等待该键释放
    Delay(200);
	while(KeySt04==0) Delay(200);	
	//保存音量到E2PROM
	E2PROM_Write(0,Vol,1);
    break;
  }
  else if(KeySt01==0)	   //取消退出
  {//等待该键释放
    Delay(200);
	while(KeySt01==0) Delay(200);	
	*Vol=DefaultVolume;	//恢复到默认值
	//保存音量到E2PROM
	E2PROM_Write(0,Vol,1);
    break;
  }
  //显示当前音量:
  DisplayNumChar(6,64,255-(*Vol),3);
  }
  //选中Vs1011
  SPI_CS_Deassert();  //PB2=1,释放MMC/SD卡
  //写入当前音量:
  retry=0;Tmp=(*Vol)*256+(*Vol);
  while(VS1011B_ReadCMD(0x0b) != Tmp)//设音量	//set Volume
  {
	VS1011B_WriteCMD(0x0b,Tmp);
	if(retry++ >10 )
	{
	   PrintConstAscStr(7,0,ScreenStr12[15],16);	  //显示"音量设置错误"
	   Delay(1000);
	   //释放Vs1011
       VS1011B_DDR |= BIT(VS1011B_XCS)|BIT(VS1011B_XRESET);	//XCS,XDCS=1
	   SPI_CS_Assert();
	   return ;
	}
  }
  //释放Vs1011
  VS1011B_DDR |= BIT(VS1011B_XCS)|BIT(VS1011B_XRESET);		//XCS,XDCS=1
  SPI_CS_Assert();
}

void ChangeVS1011Bass(uchar *VBass)	   //调整播放音量
{
  unsigned char retry,hl=0;
  unsigned char SB_Amp,SB_Freq;
  unsigned int Tmp;
  
  PrintConstAscStr(0,0,ScreenStr12[16],16);
  PrintConstAscStr(1,0,ScreenStr12[17],16);
  PrintConstAscStr(3,0,ScreenStr12[18],16);
  PrintConstAscStr(6,0,ScreenStr12[20],6);
  PrintConstAscStr(6,64,ScreenStr12[21],6);
  
  //默认选中第一项:
  PrintOneASCII(0,0,'>');
  PrintOneASCII(1,0,' ');
  
  SB_Amp=((*VBass)&0xF0)>>4; //取高四位
  SB_Freq=(*VBass)&0x0F;//取低四位
  //显示当前音量:
  DisplayNumChar(6,16,SB_Amp,2);
  DisplayNumChar(6,80,SB_Freq,2);
  
  KeyIni();KeyInput();
  while(1)
  {
  if(KeySt02==0)	  //--
  {
	//等待该键释放
	Delay(200);
	while(KeySt02==0) Delay(200);	
	if(hl==0) SB_Amp=(--SB_Amp)&0x0F;
	else 
	{
	   SB_Freq=(--SB_Freq)&0x0F; 
	   if(SB_Freq<2) SB_Freq=2;
	}
	//显示当前音量:
    DisplayNumChar(6,16,SB_Amp,2);
    DisplayNumChar(6,80,SB_Freq,2);
  } 
  else if(KeySt03==0)	  //++
  {
	//等待该键释放
	Delay(200);
	while(KeySt03==0) Delay(200);	 
	if(hl==0) SB_Amp=(++SB_Amp)&0x0F;
	else SB_Freq=(++SB_Freq)&0x0F;
	//显示当前音量:
    DisplayNumChar(6,16,SB_Amp,2);
    DisplayNumChar(6,80,SB_Freq,2);
  }
  else if(KeySt04==0)	   //确定退出
  {//等待该键释放
    Delay(200);
	while(KeySt04==0) Delay(200);	
	hl=(++hl)%2;
	if(hl==0)   //设置完毕,保存结果并退出
	{
	    *VBass=(SB_Amp*16+SB_Freq);
		Tmp=*VBass;
		//保存重低音音量到E2PROM
		E2PROM_Write(1,VBass,1);
		break;
	}else if(hl==1)   //1.设置完毕,设置2.
	{
	 	  PrintOneASCII(1,0,'>');
  		  PrintOneASCII(0,0,' '); //设置下一项
	}
  }
  else if(KeySt01==0)	   //取消退出
  {//等待该键释放
    Delay(200);
	while(KeySt01==0) Delay(200);	
	Tmp=DefaultBass;	//恢复到默认值
	*VBass=0x55;
	//保存默认的重低音音量到E2PROM
	E2PROM_Write(1,VBass,1);
    break;
  }
  if(hl==0)
  {
      PrintOneASCII(0,0,'>');
      PrintOneASCII(1,0,' ');
  }else if(hl==1)
  {
   	  PrintOneASCII(1,0,'>');
  	  PrintOneASCII(0,0,' '); //设置下一项
  }
  }
  //选中Vs1011
  SPI_CS_Deassert();  //PB2=1,释放MMC/SD卡
  //写入当前音量:
  retry=0;
  while(VS1011B_ReadCMD(0x02) != Tmp)//设低音音量
  {
	VS1011B_WriteCMD(0x02,Tmp);
	if(retry++ >10 )
	{
	   PrintConstAscStr(7,0,ScreenStr12[19],16);
	   Delay(1000);
	   //释放Vs1011
       VS1011B_DDR |= BIT(VS1011B_XCS)|BIT(VS1011B_XRESET);	//XCS,XDCS=1
	   SPI_CS_Assert();
	   return ;
	}
  }
  //释放Vs1011
  VS1011B_DDR |= BIT(VS1011B_XCS)|BIT(VS1011B_XRESET);		//XCS,XDCS=1
  SPI_CS_Assert();
}

void ChangePlayPosition(unsigned int * Pos)
{
    unsigned char i,j=3;
	unsigned int Bak_Pos=*Pos;
	
	PrintConstAscStr(0,0,ScreenStr12[28],16);
    PrintConstAscStr(1,0,ScreenStr12[18],16);
	DisplayNumChar(4,8,0,3);DisplayNumChar(4,80,DEF_MAX_SONGS,3);
	for(i=1;i<7;i++)
	   PrintOneASCII(4,24+i*8,96+0x20);   //显示白色长条
	PrintOneASCII(3,48,97+0x20);		 //中心位置,显示一个滑块
	
	//显示中间选定位置:
	*Pos=DEF_MAX_SONGS/2;
    DisplayNumChar(6,16,DEF_MAX_SONGS/2,3);
	
	while(1)
    {
       if(KeySt02==0)	  //--
  	   {
	   	  //等待该键释放
	   	  Delay(200);
		  while(KeySt02==0) Delay(200);	
		  j--;
		  if(j<=1) j=1;
		  //显示选定位置:
		  for(i=1;i<7;i++)
	         PrintOneASCII(3,24+i*8,0x20);  //删除原来的滑块
		  PrintOneASCII(3,24+j*8,97+0x20);	//滑块移动
		  *Pos=j*DEF_MAX_SONGS/6;
    	  DisplayNumChar(6,16,*Pos,3);
  	   } 
  	   else if(KeySt03==0)	  //++
  	   {	   
	      //等待该键释放
		  Delay(200);
		  while(KeySt03==0) Delay(200);	 
		  j++;
		  if(j>=6) j=6;
		  //显示选定位置:
		  for(i=1;i<7;i++)
	         PrintOneASCII(3,24+i*8,0x20);  //删除原来的滑块
		  PrintOneASCII(3,24+j*8,97+0x20);	//滑块移动
		  *Pos=j*DEF_MAX_SONGS/6;
    	  DisplayNumChar(6,16,*Pos,3);
  	   }
  	   else if(KeySt04==0)	   //确定退出
  	   {  //等待该键释放
          Delay(200);
		  while(KeySt04==0) Delay(200);	
		  break;
  	   }
	   else if(KeySt01==0)	   //取消退出
	   {
	   	  //等待该键释放
          Delay(200);
		  while(KeySt01==0) Delay(200);	
		  *Pos=Bak_Pos;
		  break;
	   }
   }
}

void MainMenu(unsigned int *pdata)
{
    unsigned char retry;
    IniData_From_EEPROM();		//先读取一下原先的数据
    ClearLCD();
    //显示主菜单测试
    CLI();//关中断
	UsrSel=0;
	PrintConstAscStr(0,16,Menustr6[0],13);
	PrintConstAscStr(1,16,Menustr6[1],13);
	PrintConstAscStr(2,16,Menustr6[2],13);
	PrintConstAscStr(3,16,Menustr6[3],13);
	PrintConstAscStr(4,16,Menustr6[4],13);
	PrintConstAscStr(5,16,Menustr6[5],13);
	
	//默认选中第一项
	PrintOneASCII(0,0,'>');
    PrintOneASCII(1,0,' ');
	PrintOneASCII(2,0,' ');
	PrintOneASCII(3,0,' ');
	PrintOneASCII(4,0,' ');
	PrintOneASCII(5,0,' ');
	
	KeyIni();KeyInput();
	while(1)
	{
	    if(KeySt01==0)			//退出
		{
		//等待该键释放
		    Delay(200);	//去抖

⌨️ 快捷键说明

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