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