?? main.c
字號:
//*********************************************
//主程序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 + -