AT89C+SD卡+3310LCD播放器.docx
- 文档编号:2851617
- 上传时间:2023-05-04
- 格式:DOCX
- 页数:21
- 大小:58.02KB
AT89C+SD卡+3310LCD播放器.docx
《AT89C+SD卡+3310LCD播放器.docx》由会员分享,可在线阅读,更多相关《AT89C+SD卡+3310LCD播放器.docx(21页珍藏版)》请在冰点文库上搜索。
AT89C+SD卡+3310LCD播放器
这是未经整理的程序,有点乱,凑合着看,有时间再进一步改进。
SD部分是修改于本坛的一个贴子
----------------------------------------------------------
添加部分注释,提高可读性
#include
#include
#include
#include"LCD_3310.H"
#defineucharunsignedchar
#defineuintunsignedint
#defineulongunsignedlong
/************定义管脚*************/
sbitDOUT=P3^0;//SD卡数据输出
sbitCLK=P3^1;//SD卡时钟输入
sbitDIN=P3^2;//SD卡数据输入
sbitCS=P3^3;//SD卡片选使能
/************全局变量************/
ucharpbuf[64];//数据缓冲区
ucharp;//播放缓冲区指针
ucharpx;//频谱显示的X坐标
codeulongTrack[17]=
{//0x15000,0x58000SD卡中各声音文件的首址,以后打算把这些数据放在SD卡的特定配置文件中再读入。
0xd7800-0x8a00,0x76b800-0x8a00,0xedc000-0x8a00,0x1752800-0x8a00,0x1F08000-0x8a00,
0x2569800-0x8a00,0x2EDB800-0x8a00,0x3480000-0x8a00,0x3BFA800-0x8a00,
0x41EB000-0x8a00,0x48EF000-0x8a00,0x508A000-0x8a00,0x59AE800-0x8a00,
0x60AF000-0x8a00,0x6878000-0x8a00,0x6DBE000-0x8a00,0x7525800-0x8a00,
};
/*******SD访问错误码的定义*******/
#defineINIT_CMD0_ERROR0X01
#defineINIT_CMD1_ERROR0X02
#defineREAD_BLOCK_ERROR0X03
#defineWRITE_BLOCK_ERROR0X04
/*********通用延时函数***********/
voiddelay(uinti)
{
while(i--);
}
/********SD写入一个字节**********/
voidspi_write(ucharx)
{//不采用循环结构是为了提高处理速度
DIN=x&0x80;
CLK=0;
CLK=1;
DIN=x&0x40;
CLK=0;
CLK=1;
DIN=x&0x20;
CLK=0;
CLK=1;
DIN=x&0x10;
CLK=0;
CLK=1;
DIN=x&0x08;
CLK=0;
CLK=1;
DIN=x&0x04;
CLK=0;
CLK=1;
DIN=x&0x02;
CLK=0;
CLK=1;
DIN=x&0x01;
CLK=0;
CLK=1;
}
/*******SD慢速写入一个字节********/
voidspi_write_low_speed(ucharx)
{
uchari;
for(i=8;i;--i)
{
DIN=x&0x80;
x<<=1;
CLK=0;
delay
(1);
CLK=1;
delay
(1);
}
}
/***********SD读入一字节***********/
ucharspi_read(void)
{//利用51串口的同步移位功能,以达了最高的读度2MHzCLK
RI=0;
while(RI==0);
returnSBUF;
}
/********SD慢速读入一字节**********/
ucharspi_read_low_speed(void)
{
uchartemp,i;
for(i=8;i;--i)
{
CLK=0;
delay
(1);
temp<<=1;
if(DOUT)temp++;
CLK=1;
delay
(1);
}
returntemp;
}
/********发送一组SD命令************/
ucharwrite_cmd(uchardata*pcmd)
{
uchartemp,time=0,i;
for(i=0;i<6;i++)//一条命令都是6个字节,形参用指针,
{//指向6个字节命令,
spi_write(pcmd);
}
do//看看写进去没有,通过so管脚
{
temp=spi_read();
time++;
}//一直到读到的不是0xff或超时,退出去
while(temp==0xff&&time<100);
returntemp;
}
/******慢速发送一组SD命令**********/
ucharwrite_cmd_low_speed(uchar*pcmd)
{
uchartemp,time=0,i;
for(i=0;i<6;i++)//一条命令都是6个字节,形参用指针,
{//指向6个字节命令,
spi_write_low_speed(pcmd);
}
do//看看写进去没有,通过so管脚
{
temp=spi_read_low_speed();
time++;
}//一直到读到的不是0xff或超时,退出去
while(temp==0xff&&time<100);
returntemp;
}
/*********SD卡激活,复位*********/
ucharsd_reset(void)
{
uchartime,temp,i;
ucharpcmd[6]={0x40,0x00,0x00,0x00,0x00,0x95};
CS=1;
for(i=0;i<0x0f;i++)//复位时,至少要72个时钟周期,
{//现在是,15*8=120个clk
spi_write_low_speed(0xff);
}
CS=0;
time=0;
do
{
temp=write_cmd_low_speed(pcmd);
time++;
if(time>100)returnINIT_CMD0_ERROR;
}
while(temp!
=0x01);//校验码是0x01,表示写入成功
CS=1;
spi_write_low_speed(0xff);//时序上要求补8个clk
return0;//返回0,写入成功
}
/************SD卡初始化************/
ucharsd_init(void)
{
uchartime,temp;
ucharpcmd[6]={0x41,0x00,0x00,0x00,0x00,0xff};
CS=0;
time=0;
do
{
temp=write_cmd_low_speed(pcmd);
time++;
if(time>100)returnINIT_CMD1_ERROR;
}
while(temp!
=0x00);
CS=1;
spi_write_low_speed(0xff);
return0;
}
/*******读取一扇区的点阵图像*********/
ucharsd_read_bmp(uchardata*ad)
{
uchartemp,time,x,pcmd[6];
uintj=0;
pcmd[0]=0x51;
pcmd[1]=*ad;
pcmd[2]=*(++ad);
pcmd[3]=*(++ad);
pcmd[4]=0;
pcmd[5]=0xff;
CS=0;
time=0;
do
{
temp=write_cmd(pcmd);
if(++time>100)
{
CS=1;
returnREAD_BLOCK_ERROR;
}
}
while(temp!
=0);
//等待SD卡回应
while(spi_read()!
=0x7f);//0xfe,51的串口移位是LSB优先,所以结果高低位倒置
for(j=0;j<504;j++)//3310的分辨率为84*48,总计用504字节
{
LCD3310_write_dat(spi_read());
}
for(x=0;x<10;x++)spi_read();//略过8字节数据和2字节CRC
spi_write(0xff);
CS=1;
return0;
}
/*******读取一扇区的声音数据*********/
ucharsd_read_sector(uchardata*ad)
{
uchartemp,time,pcmd[6];
uintj=0;
pcmd[0]=0x51;
pcmd[1]=*ad;
pcmd[2]=*(++ad);
pcmd[3]=*(++ad);
pcmd[4]=0;
pcmd[5]=0xff;
CS=0;
time=0;
do
{
temp=write_cmd(pcmd);
if(++time>100)
{
CS=1;
returnREAD_BLOCK_ERROR;
}
}
while(temp!
=0);
//等待SD回应的时间有点长,所以在这里插入显示模拟的频谱图
temp=pbuf[16];//随便挑一个数据显示
LCD3310_set_XY(px,5);//设定显示位置
px+=6;
if(px>=39)px=0;
if(temp&0x80)temp^=0x80;//求得声音振幅
elsetemp=0x80-temp;
temp=Level[temp>>4];//不同幅度对应不同的谱线图案
LCD3310_write_dat(temp);
LCD3310_write_dat(temp);
LCD3310_write_dat(temp);
while(spi_read()!
=0x7f);//0xfe,51的串口移位是LSB优先,所以结果高低位倒置
while
(1)//读取512字节数据
{
RI=0;_nop_();pbuf[j++&63]=SBUF;//为求快速,不用函数调用
RI=0;_nop_();pbuf[j++&63]=SBUF;//直接启动串口移入
RI=0;_nop_();pbuf[j++&63]=SBUF;//连续读四字节
RI=0;_nop_();pbuf[j++&63]=SBUF;
if(j>=512)break;
while((((uchar)j-p)&63)>55);//检测播放进度,
}//如果缓冲区接近溢出,先暂停等待
spi_read();//略过crc
spi_read();//略过crc
spi_write(0xff);//SD时序要求补8个脉冲
CS=1;
return0;
}
/****************************主程序*******************************/
intmain(void)
{
ucharkey,n,Count,Min,Sec;
ulongaddr;//SD的扇区地址
P1=0x80;//DAC输出中点电压
RI=1;
REN=1;
TMOD=0x02;
TH0=256-62.5;//定时器设定约为32KHz,和WAV文件取样率对应
ET0=1;
EA=1;
px=0;
n=64;
dopbuf[--n]=0x80;while(n);//填充播放缓冲区
delay(65535);
LCD3310_init();
LCD3310_set_XY(0,0);
LCD3310_write_cmd(0x22);//设定LCD扫描顺序
sd_reset();
sd_init();
addr=0x4f400;
sd_read_bmp((uchar)&addr);//显示欢迎画面
while(D_C==1);
while(D_C==0);//等待按键
delay(65535);
//==============mainloop==================
while
(1)//循环播放所有曲目
{
TR0=0;
LCD3310_write_cmd(0x22);
LCD3310_set_XY(0,0);
addr=0x4f600+((uint)n<<9);
sd_read_bmp((uchar)&addr);//显示歌名、歌手
LCD3310_write_cmd(0x20);
TR0=1;
p=0xd0;
Min=0;
Sec=0;
Count=0;
for(addr=Track[n];addr
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- AT89C SD 3310 LCD 播放