单片AT89C2051 + SD卡 + 3310LCD = 音乐播放器
http://www.amobbs.com/thread-4503884-1-1.html
这个小玩意,采用 ATMEL 的传统51MCU作主控制芯片,加上SD卡和显示屏,就可以作简单的音乐播放器了,虽然音质不怎么样,不过作为DIY还是蛮有乐趣,希望大家喜欢。
没有采用FAT文件系统,只是按扇区读取SD卡,由于2051资源有限,改为4051有望可以操作FAT,但目前程序还在不断完善中。
128byte怎样读取512byte的扇区数据?可以采用边读边播放的方式,就能解决。音乐文件是32KHz取样率的WAV文件,所以和HIFI就沾不上边了。
程序是用C来编写,以方便交流,资料整理中,完善后再上传。
这是未经整理的程序,有点乱,凑合着看,有时间再进一步改进。
SD部分是修改于本坛的一个贴子
----------------------------------------------------------
添加部分注释,提高可读性
#include <reg51.h>
#include <INTRINS.H>
#include <MATH.H>
#include "LCD_3310.H"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long /************ 定义管脚 *************/
sbit DOUT = P3^; //SD卡数据输出
sbit CLK = P3^; //SD卡时钟输入
sbit DIN = P3^; //SD卡数据输入
sbit CS = P3^; //SD卡片选使能 /************ 全局变量 ************/
uchar pbuf[]; //数据缓冲区
uchar p; //播放缓冲区指针
uchar px; //频谱显示的X坐标 code ulong Track[] =
{ //0x15000,0x58000 SD卡中各声音文件的首址,以后打算把这些数据放在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访问错误码的定义 *******/
#define INIT_CMD0_ERROR 0X01
#define INIT_CMD1_ERROR 0X02
#define READ_BLOCK_ERROR 0X03
#define WRITE_BLOCK_ERROR 0X04 /********* 通用延时函数 ***********/
void delay(uint i)
{
while(i--);
} /******** SD写入一个字节 **********/
void spi_write(uchar x)
{ //不采用循环结构是为了提高处理速度
DIN = x & 0x80;
CLK = ;
CLK = ;
DIN = x & 0x40;
CLK = ;
CLK = ;
DIN = x & 0x20;
CLK = ;
CLK = ;
DIN = x & 0x10;
CLK = ;
CLK = ;
DIN = x & 0x08;
CLK = ;
CLK = ;
DIN = x & 0x04;
CLK = ;
CLK = ;
DIN = x & 0x02;
CLK = ;
CLK = ;
DIN = x & 0x01;
CLK = ;
CLK = ;
} /******* SD慢速写入一个字节 ********/
void spi_write_low_speed(uchar x)
{
uchar i;
for(i = ; i; --i)
{
DIN = x & 0x80;
x <<= ;
CLK = ;
delay();
CLK = ;
delay();
}
} /*********** SD读入一字节 ***********/
uchar spi_read(void)
{ //利用51串口的同步移位功能,以达了最高的读度2MHz CLK
RI = ;
while(RI == );
return SBUF;
} /******** SD慢速读入一字节 **********/
uchar spi_read_low_speed(void)
{
uchar temp,i;
for(i = ; i; --i)
{
CLK = ;
delay();
temp <<= ;
if(DOUT) temp++;
CLK = ;
delay();
}
return temp;
} /******** 发送一组SD命令 ************/
uchar write_cmd(uchar data *pcmd)
{
uchar temp,time=,i;
for(i = ; i<; i++) //一条命令都是6个字节,形参用指针,
{ //指向6个字节命令,
spi_write(pcmd);
}
do //看看写进去没有,通过so管脚
{
temp = spi_read();
time++;
} //一直到读到的不是0xff或超时,退出去
while(temp==0xff && time<);
return temp;
} /****** 慢速发送一组SD命令 **********/
uchar write_cmd_low_speed(uchar *pcmd)
{
uchar temp,time=,i;
for(i=;i<;i++) //一条命令都是6个字节,形参用指针,
{ //指向6个字节命令,
spi_write_low_speed(pcmd);
}
do //看看写进去没有,通过so管脚
{
temp = spi_read_low_speed();
time++;
} //一直到读到的不是0xff或超时,退出去
while(temp==0xff && time<);
return temp;
} /********* SD卡 激活,复位 *********/
uchar sd_reset(void)
{
uchar time,temp,i;
uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};
CS = ;
for(i = ; i < 0x0f; i++) //复位时,至少要72个时钟周期,
{ //现在是,15*8=120个clk
spi_write_low_speed(0xff);
}
CS = ;
time=;
do
{
temp = write_cmd_low_speed(pcmd);
time++;
if(time > ) return INIT_CMD0_ERROR;
}
while(temp != 0x01); //校验码是0x01,表示写入成功
CS = ;
spi_write_low_speed(0xff);//时序上要求补8个clk
return ; //返回0,写入成功
} /************ SD卡初始化 ************/
uchar sd_init(void)
{
uchar time, temp;
uchar pcmd[] = {0x41,0x00,0x00,0x00,0x00,0xff};
CS = ;
time = ;
do
{
temp = write_cmd_low_speed(pcmd);
time++;
if(time > ) return INIT_CMD1_ERROR;
}
while(temp != 0x00);
CS = ;
spi_write_low_speed(0xff);
return ;
} /******* 读取一扇区的点阵图像 *********/
uchar sd_read_bmp(uchar data *ad)
{
uchar temp, time, x, pcmd[];
uint j = ;
pcmd[] = 0x51;
pcmd[] = *ad;
pcmd[] = *(++ad);
pcmd[] = *(++ad);
pcmd[] = ;
pcmd[] = 0xff; CS = ;
time = ;
do
{
temp = write_cmd(pcmd);
if(++time > )
{
CS = ;
return READ_BLOCK_ERROR;
}
}
while(temp != );
//等待SD卡回应
while(spi_read() != 0x7f); //0xfe,51的串口移位是LSB优先,所以结果高低位倒置
for (j = ; j < ; j++) //3310的分辨率为 84 * 48,总计用504字节
{
LCD3310_write_dat(spi_read());
}
for (x = ; x < ; x++) spi_read(); //略过8字节数据和2字节CRC
spi_write(0xff);
CS = ;
return ;
} /******* 读取一扇区的声音数据 *********/
uchar sd_read_sector(uchar data *ad)
{
uchar temp, time, pcmd[];
uint j = ;
pcmd[] = 0x51;
pcmd[] = *ad;
pcmd[] = *(++ad);
pcmd[] = *(++ad);
pcmd[] = ;
pcmd[] = 0xff; CS = ;
time = ;
do
{
temp = write_cmd(pcmd);
if(++time > )
{
CS = ;
return READ_BLOCK_ERROR;
}
}
while(temp != );
//等待SD回应的时间有点长,所以在这里插入显示模拟的频谱图
temp = pbuf[]; //随便挑一个数据显示
LCD3310_set_XY(px,); //设定显示位置
px += ;
if (px >= ) px = ;
if (temp & 0x80) temp ^= 0x80; //求得声音振幅
else temp = 0x80 - temp;
temp = Level[temp>>]; //不同幅度对应不同的谱线图案
LCD3310_write_dat(temp);
LCD3310_write_dat(temp);
LCD3310_write_dat(temp); while(spi_read() != 0x7f);//0xfe,51的串口移位是LSB优先,所以结果高低位倒置 while() //读取512字节数据
{
RI = ;_nop_(); pbuf[j++ & ] = SBUF; //为求快速,不用函数调用
RI = ;_nop_(); pbuf[j++ & ] = SBUF; //直接启动串口移入
RI = ;_nop_(); pbuf[j++ & ] = SBUF; //连续读四字节
RI = ;_nop_(); pbuf[j++ & ] = SBUF;
if(j >= ) break;
while((((uchar)j - p) & ) > ); //检测播放进度,
} //如果缓冲区接近溢出,先暂停等待
spi_read();//略过 crc
spi_read();//略过 crc
spi_write(0xff);//SD 时序要求补8个脉冲
CS = ;
return ;
} /**************************** 主程序 *******************************/
int main(void)
{
uchar key,n,Count,Min,Sec;
ulong addr; // SD 的扇区地址 P1 = 0x80; // DAC 输出中点电压
RI = ;
REN = ;
TMOD = 0x02;
TH0 = - 62.5; //定时器设定约为 32KHz,和WAV文件取样率对应
ET0 = ;
EA = ;
px = ;
n = ;
do pbuf[--n] = 0x80; while(n); //填充播放缓冲区
delay(); LCD3310_init();
LCD3310_set_XY(,);
LCD3310_write_cmd(0x22); //设定LCD扫描顺序
sd_reset();
sd_init();
addr = 0x4f400;
sd_read_bmp((uchar) &addr); //显示欢迎画面
while (D_C == ) ;
while (D_C == ) ; //等待按键
delay(); //============== main loop ==================
while() //循环播放所有曲目
{
TR0 = ;
LCD3310_write_cmd(0x22);
LCD3310_set_XY(,);
addr = 0x4f600 + ((uint)n<<);
sd_read_bmp((uchar) &addr); //显示歌名、歌手
LCD3310_write_cmd(0x20);
TR0 = ;
p = 0xd0;
Min = ;
Sec = ;
Count= ;
for (addr = Track[n]; addr < Track[n+];)//播放第n曲
{
//============ 按键处理 ===============
key = (key >> ) | (P3 & 0x30); //仅一句的扫键函数,包括扫描和消抖
if (key == 0x03) //键码为03是播放/暂停键
{
LCD3310_set_XY(,);
TCON ^= 0x10; //TR0 取反
if (TR0) LCD3310_print(); //显示播放符号
else LCD3310_print(); //显示暂停符号
}
else if (key == 0x2b) //键码为2b是前一曲
{
if ((Min || (Sec & 0xf0))) n--;//10秒后跳本曲开始
else n -= ; //10秒内跳前一曲
break;
}
else if (key == 0x17) //键码为17是后一曲
break; //======== 读一扇区数据或暂停 =========
if (TR0 == ) {delay(); continue;}
sd_read_sector((uchar) &addr);
addr += ; //=========== 播放时间计数 ============
Count += ;
if (Count >= )
{
Count -= ;
Sec++;
if ((Sec & 0x0f) > )
{
Sec += ;
if (Sec >= 0x60)
{
Sec = ;
Min++;
if ((Min & 0x0f) > )
{
Min += ;
if (Min > 0x60) Min = ;
}
}
}
} //======= 分时间片显示时间/标志 ========
switch (Count & )
{
case :
LCD3310_set_XY(,);
LCD3310_print(Min>>);//分钟十位
break; case :
LCD3310_set_XY(,);
LCD3310_print(Min&);//分钟个位
break; case :
LCD3310_set_XY(,);
LCD3310_print(); //分隔符
break; case :
LCD3310_set_XY(,);
LCD3310_print(Sec>>);//秒十位
break; case :
LCD3310_set_XY(,);
LCD3310_print(Sec&);//秒个位
break; case :
LCD3310_set_XY(,);
if (Count & 0x40) LCD3310_print(); //闪动播放符号
else LCD3310_print();
}
}
n++; //下一曲
n &= ; //这个SD卡只有16首歌
}//while(1);
}//main() void timer0 (void) interrupt using
{
if (TL0 & ) _nop_(); //消除中断响应时间不一致,造成的频率抖动
P1 = pbuf[++p & ]; //输出一个声音数据
}
这是3310 LCD 部分
#include <reg51.h>
#include <INTRINS.H> sbit SDIN = P3^; //P3^2
sbit SCLK = P3^;
sbit D_C = P3^;
sbit SCE = P3^; code unsigned char Font[] =
{
0x3E, 0x51, 0x49, 0x45, 0x3E , //
0x00, 0x42, 0x7F, 0x40, 0x00 , //
0x42, 0x61, 0x51, 0x49, 0x46 , //
0x21, 0x41, 0x45, 0x4B, 0x31 , //
0x18, 0x14, 0x12, 0x7F, 0x10 , //
0x27, 0x45, 0x45, 0x45, 0x39 , //
0x3C, 0x4A, 0x49, 0x49, 0x30 , //
0x01, 0x71, 0x09, 0x05, 0x03 , //
0x36, 0x49, 0x49, 0x49, 0x36 , //
0x06, 0x49, 0x49, 0x29, 0x1E , //
0x00, 0x00, 0x36, 0x36, 0x00 , // :
0x7f, 0x3e, 0x1c, 0x08, 0x00 , // >
0x3e, 0x3e, 0x00, 0x3e, 0x3e , // ||
0x00, 0x00, 0x00, 0x00, 0x00 , //" "
}; code unsigned char Level[] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,}; extern void delay(unsigned int i); void LCD3310_write_cmd(unsigned char cmd)
{
D_C = ;
SCLK = ;
SCE = ;
delay();
SDIN = cmd & 0x80;
SCLK = ;
SDIN = cmd & 0x40;
SCLK = ;
SCLK = ;
SDIN = cmd & 0x20;
SCLK = ;
SCLK = ;
SDIN = cmd & 0x10;
SCLK = ;
SCLK = ;
SDIN = cmd & 0x08;
SCLK = ;
SCLK = ;
SDIN = cmd & 0x04;
SCLK = ;
SCLK = ;
SDIN = cmd & 0x02;
SCLK = ;
SCLK = ;
SDIN = cmd & 0x01;
SCLK = ;
SCLK = ;
D_C = ;
SDIN = ;
SCE = ;
} void LCD3310_write_dat(unsigned char dat)
{
// D_C = 1;
SCLK = ;
SCE = ;
delay();
SDIN = dat & 0x80;
SCLK = ;
SDIN = dat & 0x40;
SCLK = ;
SCLK = ;
SDIN = dat & 0x20;
SCLK = ;
SCLK = ;
SDIN = dat & 0x10;
SCLK = ;
SCLK = ;
SDIN = dat & 0x08;
SCLK = ;
SCLK = ;
SDIN = dat & 0x04;
SCLK = ;
SCLK = ;
SDIN = dat & 0x02;
SCLK = ;
SCLK = ;
SDIN = dat & 0x01;
SCLK = ;
SCLK = ;
D_C = ;
SDIN = ;
SCE = ;
} void LCD3310_init(void)
{
LCD3310_write_cmd(0x21);
LCD3310_write_cmd(0xd7);
LCD3310_write_cmd(0x06);
LCD3310_write_cmd(0x20);
LCD3310_write_cmd(0x0c);
} void LCD3310_set_XY(unsigned char x,unsigned char y)
{
if (x >= ) return;
if (y >= ) return;
LCD3310_write_cmd(0x80 | x);
LCD3310_write_cmd(0x40 | y);
} void LCD3310_print(unsigned char n)
{
n = (n << ) + n;
LCD3310_write_dat(Font[n]);
LCD3310_write_dat(Font[++n]);
LCD3310_write_dat(Font[++n]);
LCD3310_write_dat(Font[++n]);
LCD3310_write_dat(Font[++n]);
}
回复【104楼】maxims
呵呵,希望能解释一下电路
-----------------------------------------------------------------------
R1、C1 组成LCD的上电复位电路。
R2~R4是上拉电阻,虽然2051的IO有内部的弱上拉,但这三个IO是LCD接口与键盘接口复用,需要上拉强一点。
R5、R6、Q1组成OC输出的反相器,当SCE为高电平时,三极管导通,键盘使能,LCD通信中止;当SCE为低电平时,LCD通信使能,键盘断开。需要注意的是图中左右两键没加隔离二极管,不要同时按下,否则引起显示错乱。
R2~R6的参数不要大幅度改动,这些参数是经过计算得到一个比较合适的值。
晶振、C3、C5没什么好说,这些都单片机系统必需的。
R7、R8是P1.0和P1.1的上拉电阻,因为这两个口是开漏输出。
R9~R24组成R2R型DAC,选取50K/100K是因为2051输出高电平的带载能力差,电阻太小将导致DAC线性变差。这里的电阻最好用1%的金属膜电阻,以改善DAC的线性度。50K电阻是非标电阻,这里用51K和2.7M电阻并联代替。
C6是高频滤波电容,以减少DAC输出的高频噪声。
C7是输出耦合电容,连接LINE OUT输出端子,输出阻抗较高,50K,只能接功放机或有源音箱。如果接耳机,需加一级放大,可以用运放做跟随器,或用TDA2822功放IC,能带个小嗽叭。
回复【105楼】jeep
//由于部分显示数据在sd卡中,所以sd卡需要存入一个特别的文件//
那个是特别文件还不明白你的意思
-----------------------------------------------------------------------
回复【108楼】wsm80828
很想知道这个
//由于部分显示数据在sd卡中,所以sd卡需要存入一个特别的文件//
-----------------------------------------------------------------------
是一个存放歌曲名称、歌手名称、歌曲首址和长度的文件,2051只有2K ROM,不可能把整个中文字库存进ROM内,只能存在SD卡中,以图片形式存贮,需要时读入。哪位能用VB或VC做一个转换工具自动生成一个playlist.dat就方便了。
U32 GetRootDir(void)
{
U32 root, fat1, fat2;
MMCRdBolckOne(0x00,Buffer); // 读取SD卡中的数据
fat1 = ((Buffer[0x0f]<<8) | Buffer[0x0e]) * 512;
fat2 = ((Buffer[0x25]<<8) | Buffer[0x24]) * 512 + fat1;
root = ((Buffer[0x25]<<8) | Buffer[0x24]) * 512 + fat2;
return root;
}
这里是使用512的缓存,可以修改成楼主的64缓存,只要读取出第 0x0e,0x0f, 0x25,0x24地址的数据就可以计算了
用于查找根目录的函数,那样就可以查找歌曲了
根目录 每32个数据表示一个文件,分辨出WAV格式的文件 找到相应的簇地址,然后进行播放
马老师你好,对于你所提及的问题,在我转换过的声音文件中也有同样体现。究其原因,主要是8BIT取样深度不够,声音电平在接近零点时,由于随机噪声的影响,导致取样值在0x80,0x79,0x81这间变化,以产生噪声。我认为这种噪声一直都存在,只是其它声音较大时掩蔽了而矣。
解决方法,可参考类似杜比动态降噪技术,作这样的处理:检测当前声音幅度,如果在持续的一段时间内(比如0.2秒)声音幅度小于一定值(比如0x80 正负1),那么都过滤为0x80,即可解决此问题。
我记得有些音频处理软件可以进行这种变换,我回去找找。即使没有,编个小程序转一下也不难。
听过【149楼】所提供的8BIT声音样本,发现其噪声很大,估计所用的商业软件在转换算法上有问题。我用WINDOWS XP附件自带的录音机,打开原始16BIT声音文件,然后另存为44KHz 8BIT,效果也比【149楼】的好得多。
回复【151楼】cowboy
听过【149楼】所提供的8bit声音样本,发现其噪声很大,估计所用的商业软件在转换算法上有问题。我用windows xp附件自带的录音机,打开原始16bit声音文件,然后另存为44khz 8bit,效果也比【149楼】的好得多。
-----------------------------------------------------------------------
谢谢!
我使用过几个商业软件,如上图中的AUDITION、天天静听等,都是如此。自己写了一个转换程序,就是直接简单的采用除256的方法,直接把16位降成8位,这样处理后,静音部分可以完全转换为静音,而且总的噪声比这些商业软件小了许多(-3db左右),但是还有,还是可以比较清晰的听到,尤其是当调节音量输出比较大的时候。
我会试一下WINDOWNS的附件,听听效果。
现在手头的项目,需要语音提示。考虑到存储容量,使用8K、8位的WAV数据,应该可以达到电话的语音质量,对于一般应用够了。其它都可以,成本也不高,就是转换数据本声的噪声。想找一种简单的处理办法。
后面我还会继续提供一些我使用过的处理办法。
另外是否其它的朋友有这方面的经验,软件或算法,只要提供一个思路就可以了,先表示感谢。
/**********************************************************************************************/
点击此处下载 ourdev_611680M0SOZB.rar(文件大小:2.32M) (原文件名:goldwave v5.23 汉化版.rar)
用这个转换成8Bit单声道PCM文件,效果很好。16Bit转8Bit不会改变采样频率,故需先转成32KHz的其它格式再转成PCM
回复【154楼】machao
回复【151楼】cowboy
听过【149楼】所提供的8bit声音样本,发现其噪声很大,估计所用的商业软件在转换算法上有问题。我用windows xp附件自带的录音机,打开原始16bit声音文件,然后另存为44khz 8bit,效果也比【149楼】的好得多。
-----------------------------------------------------------------------
谢谢!
我使用过几个商业软件,如上图中的audition、天天静听等,都是如此。自己写了一个转换程序,就是直接简单的采用除256的方法,直接把16位降成8位,这样处理后,静音部分可以完全转换为静音,而且总的噪声比这些商业软件小了许多(-3db左右),但是还有,还是可以比较清晰的听到,尤其是当调节音量输出比较大的时候。
我会试一下windowns的附件,听听效果。
现在手头的项目,......
-----------------------------------------------------------------------
马老师我提个建议吧。我做过类似的项目,是用PWM直接接一功放驱动喇叭。没有加低通滤波,当使用20K以下的采样频率WAV文件时有啸声,使用20K以上时人就听不到了。这里应该是由PWM的高低电平跳动引起的,使用DA应该没有类似问题。
所以我就没有采用8K的采样,而是使用24K采样,8:2的ADPCM编码方式。对比下文件大小:8KHz 8Bit的PCM格式64Kbps, 24KHz 8Bit ADPCM为 24*8/4 = 48Kbps,只有8K的3/4大小。而音质上压缩的肯定比降低采样频率更好一些。
这里也有一个小问题,我使用这个软件编8:4 ADPCM再解码时有很大噪音,这里是因为其码表可能与我用的不同。网上8bit的ADPCM基本上没有,我是将16位的改成8位的,所以码表是可能不同。我的解决办法是自己编码再自己解码,8:2也能达到较好的效果,听歌尚可,语音更不用说,用DA的话效果肯定更好,而加滤波的话有些音色会变。
播放BUF和读取BUF我是分开的,开辟了两个数据区A,B,这样就不用读一个播放一个。播放完BUF_A再播放BUF_B,同时BUF_A从FLASH中读取相应数据,依此循环。
回复【159楼】amazing030
谢谢您了,我会用你建议的goldwave v5.23.rar试一下的。
压缩编码的方式我知道,做过图象的压缩,JPEG,H26x等。在这个项目上,不想使用这么复杂的东西。我设计是提供一个DS卡,和规定的文件名,然后给的PC程序给用户。用户自己需要什么语音自己在PC上做,然后转换成8位的,考入SD卡就可以了。
另外,系统使用8位MCU,时钟也就10M左右,还要做其它的事情,ADPCM解码,还是不做的好。
另外,你的解释是不对的。我提供的两个文件与系统播放无关,就是在PC上转换,然后在PC上播放,采样率为44.1k。仅用PC转换,在PC播放,沙沙的噪声非常明显。与什么PWM没有关系。
解决数字音频信号传输中劣化方式(http://www.av010.com/jswz_html/jswz2280_1.html)
专业的解释,看来解决比较困难了。
/**********************************************************************************************/
回复【80楼】cowboy
-----------------------------------------------------------------------
小弟不才,
请问楼主
void timer0 (void) interrupt 1 using 1
{
if (TL0 & 1) _nop_(); //消除中断响应时间不一致,造成的频率抖动
P1 = pbuf[++p & 63]; //输出一个声音数据
}
这其中的" & 63"的作用是什么呢?
回复【167楼】hongfadg
-----------------------------------------------------------------------
p & 63 是取8位“p”中的低6位,舍弃高2位,由于缓冲区只有64字节,“++p & 63”正好循环指向pbuf[0]至pbuf[63]。
/**********************************************************************************************/
播放器升级预告,增加FAT32文件系统,也就是可以随意增减音乐文件,不必按连续的储存空间存放文件,允许有文件碎片,同时也不再需要在SD卡内存放一个经特殊制作系统文件。
硬件没改变,只是软件升级,虽然增加了FAT32部分代码,但总代码量仍在2K以内,89C2051能装得下。
测试基本通过,整理好后再上传。
上传升级版的整套工程文件,以及SD内的示范文件。
点击此处下载 ourdev_615881TB11F5.rar(文件大小:429K) (原文件名:SD_player.rar)
由于水平有限,程序可能还有很多不完善的地方,希望大家多提意见。特别是SD卡驱动和FAT32文件系统,本人理解并不深入,程序对各种SD卡的兼容性未作详细测试,有可能出现某些SD卡不能播放的情况。对SD卡的基本要求是 文件系统为FAT32格式,暂不支持FAT16;SDHC高速卡也不支持。
/**********************************************************************************************/
单片AT89C2051 + SD卡 + 3310LCD = 音乐播放器的更多相关文章
- SD卡WAV音乐播放器(quartus11.0)(FAT32)(DE2-115)
准备工具:格式工厂,Windows录音机,SD卡(小于等于2G),音箱 首先,选一首MP3,用格式工场转化成WAV格式.可以看到转化后的文件变得很大,因为WAV就是AD采样值加个文件头,所以数据量巨大 ...
- Linux终端音乐播放器cmus攻略: 操作歌单
目录 1. 安装 2. 操作说明 2.1. *PlayList歌单 2.2. 其他 3. 视图切换 4. 使响应Media/play按键 4.1. 编译安装 cmus是一款开源的终端音乐播放器.它小巧 ...
- Android大作业 --音乐播放器
1.项目成员(本次作业主要对上一次的音乐播放器进行完善) 韦家城 学号:1600802026 班级:161 博客:https://www.cnblogs.com/ln9969cc/ 邓乾尧 学号:1 ...
- Android开发6:Service的使用(简单音乐播放器的实现)
前言 啦啦啦~各位好久不见啦~博主最近比较忙,而且最近一次实验也是刚刚结束~ 好了不废话了,直接进入我们这次的内容~ 在这篇博文里我们将学习Service(服务)的相关知识,学会使用 Service ...
- Android 实现简单音乐播放器(二)
在Android 实现简单音乐播放器(一)中,我介绍了MusicPlayer的页面设计. 现在,我简单总结一些功能实现过程中的要点和有趣的细节,结合MainActivity.java代码进行说明(写出 ...
- Android实现简单音乐播放器(MediaPlayer)
Android实现简单音乐播放器(MediaPlayer) 开发工具:Andorid Studio 1.3 运行环境:Android 4.4 KitKat 工程内容 实现一个简单的音乐播放器,要求功能 ...
- android音乐播放器开发教程
android音乐播放器开发教程 Android扫描sd卡和系统文件 Android 关于录音文件的编解码 实现米聊 微信一类的录音上传的功能 android操作sdcard中的多媒体文件——音乐列表 ...
- 【竞品分析】Android音乐播放器的竞品分析
迄今为止最长的一篇博客,各位看官笑纳~~ 本次分析基于Android平台,选取了几款我体验过的播放器进行比较分析.主要分为两类,一类是大而全的,功能全面,可满足用户管理歌曲.导入导出歌单等多方面需求, ...
- Android实现简单音乐播放器(startService和bindService后台运行程序)
Android实现简单音乐播放器(MediaPlayer) 开发工具:Andorid Studio 1.3运行环境:Android 4.4 KitKat 工程内容 实现一个简单的音乐播放器,要求功能有 ...
随机推荐
- Windows线程同步(上)
先介绍一个创建线程的API,参考:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453%28v=vs.85%29.aspx ...
- Chapter 2 Open Book——14
I backpedaled. "They seemed nice enough to me. I just noticed they keptto themselves. 我改口说道,他们看 ...
- 缓存1 静态缓存-->读库保存成php文件 mkdir-->file_put_contents-->var_export -->include
@mkdir()-->file_put_contents-->$data = "<?php\nreturn ".var_export($setting, tru ...
- pureMVC java版搭建流程
转自:http://blog.csdn.net/sutaizi/article/details/6588004 pureMVC 是一个轻量级的框架 它在 flex中非常流行(和cairngorm差不多 ...
- Go-new和make
new返回指向struct的指针,new仅分配内存,而不对对象的值进行初始化 make返回到strcut的对象,而不是指针,只能创建map,slice,channel对象 make([]string, ...
- Hadoop 中关于 map,reduce 数量设置
map和reduce是hadoop的核心功能,hadoop正是通过多个map和reduce的并行运行来实现任务的分布式并行计算,从这个观点来看,如果将map和reduce的数量设置为1,那么用户的任务 ...
- 线段树 或者 并查集 Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C
http://codeforces.com/contest/722/problem/C 题目大意:给你一个串,每次删除串中的一个pos,问剩下的串中,连续的最大和是多少. 思路一:正方向考虑问题,那么 ...
- Windows 系统变量大全
来源:http://blog.csdn.net/kingwolf_javascript/article/details/2477234 %ALLUSERSPROFILE% : 列出所有用户Profil ...
- cordova sqlite
jar包在这里下载 https://github.com/litehelpers/Cordova-sqlite-storage 把SQLitePlugin 复制到自己工程目录 org.pgsqlite ...
- idea 端口占用
netstat -anp | grep 8080 lsof -i:8080 查看8080端口被什么进程占用 kill (-s 9) 12903 -s 9 强制 尽快 12903 上面查出的 PID 其 ...