tag 标签: vs1053

相关博文
  • 热度 21
    2013-4-13 23:01
    2406 次阅读|
    1 个评论
      第五十章 录音机实验     上一章,我们实现了一个简单的音乐播放器,本章我们将在上一章的基础上,实现一个简单的录音机,实现WAV录音。本章分为如下几个部: 50.1 WAV简介 50.2 硬件设计 50.3 软件设计 50.4 下载验证   50.1 WAV简介 WAV即WAVE文件,WAV是计算机领域最常用的数字化声音文件格式之一,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio),由于其扩展名为"*.wav"。它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM,CCITT A LAW等多种压缩运算法,支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几! ALIENTEK战舰STM32开发板板载的VS1053支持2种格式的WAV录音:PCM格式或者IMA ADPCM格式,其中PCM(脉冲编码调制)是最基本的WAVE文件格式,这种文件直接存储采样的声音数据没有经过任何的压缩。而IAM ADPCM则是使用了压缩算法,压缩比率为4:1。 本章,我们主要讨论PCM,因为这个最简单。我们将利用VS1053实现16位,8Khz采样率的单声道WAV录音(PCM格式)。要想实现WAV录音得先了解一下WAV文件的格式,WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk、 Format Chunk、 Fact Chunk(可选)和 Data Chunk。每个Chunk由块标识符、数据大小和数据三部分组成,如图50.1.1所示:   图50.1.1 Chunk结构示意图        其中块标识符由4个ASCII码构成,数据大小则标出紧跟其后的数据的长度(单位为字节),注意这个长度不包含块标识符和数据大小的长度,即不包含最前面的8个字节。所以实际Chunk的大小为数据大小加8。 首先,我们来看看RIFF块(RIFF WAVE Chunk),该块以“RIFF”作为标示,紧跟wav文件大小(该大小是wav文件的总大小-8),然后数据段为“WAVE”,表示是wav文件。RIFF块的Chunk结构如下: //RIFF块 typedef __packed struct {     u32 ChunkID;             //chunk id;这里固定为"RIFF",即0X46464952     u32 ChunkSize ;            //集合大小;文件总大小-8     u32 Format;                //格式;WAVE,即0X45564157 }ChunkRIFF ; 接着,我们看看Format块(Format Chunk),该块以“fmt ”作为标示(注意有个空格!),一般情况下,该段的大小为16个字节,但是有些软件生成的wav格式,该部分可能有18个字节,含有2个字节的附加信息。Format块的Chunk结构如下: //fmt块 typedef __packed struct {     u32 ChunkID;             //chunk id;这里固定为"fmt ",即0X20746D66     u32 ChunkSize ;            //子集合大小(不包括ID和Size);这里为:20.     u16 AudioFormat;        //音频格式;0X10,表示线性PCM;0X11表示IMA ADPCM        u16 NumOfChannels;    //通道数量;1,表示单声道;2,表示双声道;        u32 SampleRate;           //采样率;0X1F40,表示8Khz        u32 ByteRate;               //字节速率;        u16 BlockAlign;            //块对齐(字节);        u16 BitsPerSample;              //单个采样数据大小;4位ADPCM,设置为4 }ChunkFMT;  接下来,我们再看看Fact块(Fact Chunk),该块为可选块,以“fact”作为标示,不是每个WAV文件都有,在非PCM格式的文件中,一般会在Format结构后面加入一个Fact块,该块Chunk结构如下: //fact块 typedef __packed struct {     u32 ChunkID;                    //chunk id;这里固定为"fact",即0X74636166;     u32 ChunkSize ;                 //子集合大小(不包括ID和Size);这里为:4.     u32 DataFactSize;               //数据转换为PCM格式后的大小 }ChunkFACT; DataFactSize是这个Chunk中最重要的数据,如果这是某种压缩格式的声音文件,那么从这里就可以知道他解压缩后的大小。对于解压时的计算会有很大的好处!不过本章我们使用的是PCM格式,所以不存在这个块。 最后,我们来看看数据块(Data Chunk),该块是真正保存wav数据的地方,以“data”'作为该Chunk的标示。然后是数据的大小。紧接着就是wav数据。根据Format Chunk中的声道数以及采样bit数,wav数据的bit位置可以分成如表50.1.1所示的几种形式: 单声道 取样1 取样2 取样3 取样4 8 位量化 声道0 声道0 声道0 声道0 双声道 取样1 取样2 8 位量化 声道0(左) 声道1(右) 声道0(左) 声道1(右) 单声道 取样1 取样2 16 位量化 声道0(低字节) 声道0(高字节) 声道0(低字节) 声道0(高字节) 双声道 取样1 16 位量化 声道0 (左,低字节) 声道0 (左,高字节) 声道1 (右,低字节) 声道1 (右,高字节) 表50.1.1 WAVE文件数据采样格式        本章,我们采用的是16位,单声道,所以每个取样为2个字节,低字节在前,高字节在后。数据块的Chunk结构如下: //data块 typedef __packed struct {     u32 ChunkID;             //chunk id;这里固定为"data",即0X61746164     u32 ChunkSize ;            //子集合大小(不包括ID和Size);文件大小-60. }ChunkDATA;        通过以上学习,我们对WAVE文件有了个大概了解。接下来,我们看看如何使用VS1053实现WAV(PCM格式)录音。        激活PCM 录音 VS1053激活PCM录音需要设置的寄存器和相关位如表50.1.2所示:   图50.1.2 VS1053激活PCM录音相关寄存器        通过设置SCI_MODE寄存器的2、12、14位,来激活PCM录音,SCI_MODE的各位描述见表49.1.4(也可以参考VS1053的数据手册)。SCI_AICTRL0寄存器用于设置采样率,我们本章用的是8K的采样率,所以设置这个值为8000即可。SCI_AICTRL1寄存器用于设置AGC,1024相当于数字增加1,这里建议大家设置AGC在4(4*1024)左右比较合适。SCI_AICTRL2用于设置自动AGC的时候的最大值,当设置为0的时候表示最大64(65536),这个大家按自己的需要设置即可。最后,SCI_AICTRL3,我们本章用到的是咪头线性PCM单声道录音,所以设置该寄存器值为6。 通过这几个寄存器的设置,我们就激活VS1053的PCM录音了。不过,VS1053的PCM录音有一个小BUG,必须通过加载patch才能解决,如果不加载patch,那么VS1053是不输出PCM数据的,VLSI提供了我们这个patch,只需要通过软件加载即可。        读取PCM 数据 在激活了PCM录音之后,SCI_HDAT0和SCI_HDAT1有了新的功能。VS1053的PCM采样缓冲区由1024个16位数据组成,如果SCI_HDAT1大于0,则说明可以从SCI_HDAT0读取至少SCI_HDAT1个16位数据,如果数据没有被及时读取,那么将溢出,并返回空的状态。 注意,如果SCI_HDAT1≥896,最好等待缓冲区溢出,以免数据混叠。所以,对我们来说,只需要判断SCI_HDAT1的值非零,然后从SCI_HDAT0读取对应长度的数据,即完成一次数据读取,以此循环,即可实现PCM数据的持续采集。 最后,我们看看本章实现WAV录音需要经过哪些步骤: 1) 设置VS1053 PCM 采样参数 这一步,我们要设置PCM的格式(线性PCM)、采样率(8K)、位数(16位)、通道数(单声道)等重要参数,同时还要选择采样通道(咪头),还包括AGC设置等。可以说这里的设置直接决定了我们wav文件的性质。 2) 激活VS1053 的PCM 模式,加载 patch 通过激活VS1053的PCM格式,让其开始PCM数据采集,同时,由于VS1053的BUG,我们需要加载patch,以实现正常的PCM数据接收。 3) 创建WAV 文件,并保存wav 头 在前两部设置成功之后,我们即可正常的从SCI_HDAT0读取我们需要的PCM数据了,不过在这之前,我们需要先在创建一个新的文件,并写入wav头,然后才能开始写入我们的PCM数据。 4) 读取PCM 数据 经过前面几步的处理,这一步就比较简单了,只需要不停的从SCI_HDAT0读取数据,然后存入wav文件即可,不过这里我们还需要做文件大小统计,在最后的时候写入wav头里面。 5) 计算整个文件大小,重新保存wav 头并关闭文件 在结束录音的时候,我们必须知道本次录音的大小(数据大小和整个文件大小),然后更新wav头,重新写入文件,最后因为FATFS,在文件创建之后,必须调用f_close,文件才会真正体现在文件系统里面,否则是不会写入的!所以最后还需要调用f_close,以保存文件。 50.2 硬件设计 本章实验功能简介:开机的时候先检测字库,然后初始化VS1053,进行RAM测试和正弦测试,之后,检测SD卡根目录是否存在RECORDER文件夹,如果不存在则创建,如果创建失败,则报错。在找到SD卡的RECORDER文件夹后,即设置VS1053进入录音模式,此时可以在耳机听到VS1053采集的音频。KEY0用于开始/暂停录音,KEY2用于保存并停止录音,WK_UP用于AGC增加、KEY1用于AGC减小,TPAD用于播放最近一次的录音。当我们按下KEY0的时候,可以在屏幕上看到录音文件的名字,以及录音时间,然后通过KEY2可以保存该文件,同时停止录音(文件名和时间也都将清零),在完成一个录音后,我们可以通过按TPAD按键,来试听刚刚的录音。DS0用于提示程序正在运行,DS1用于指示当前是否处于录音暂停状态。 本实验用到的资源如下: 1)  指示灯DS0和DS1 2)  五个按键(WK_UP/KEY0/KEY1/KEY2/TPAD) 3)  串口 4)  TFTLCD模块 5)  SD卡 6)  SPI FLASH 7)  VS1053 8)  74HC4052 9)  TDA1308 本章用到的硬件资源同上一章基本一样,就多了一个TPAD按键,用于播放最近一次录音。 本实验,大家需要准备1个SD卡和一个耳机,分别插入SD卡接口和耳机接口,然后下载本实验就可以实现一个简单的录音机了。 50.3 软件设计 打开上一章的工程,首先在APP文件夹下面新建recorder.c和recorder.h两个文件,然后将recorder.c加入到工程的APP组下。 因为recorder.c代码比较多,我们这里仅介绍其中的三个函数,首先是设置VS1053进入PCM模式的函数:recoder_enter_rec_mode,该函数代码如下: //进入PCM 录音模式 //agc:0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍             void recoder_enter_rec_mode(u16 agc) {        //如果是IMA ADPCM,采样率计算公式如下:       //采样率=CLKI/256*d;         //假设d=0,并2倍频,外部晶振为12.288M.那么Fc=(2*12288000)/256*6=16Khz        //如果是线性PCM,采样率直接就写采样值      VS_WR_Cmd(SPI_BASS,0x0000);          VS_WR_Cmd(SPI_AICTRL0,8000);   //设置采样率,设置为8Khz       VS_WR_Cmd(SPI_AICTRL1,agc);             //设置增益,0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍       VS_WR_Cmd(SPI_AICTRL2,0);         //设置增益最大值,0,代表最大值65536=64X       VS_WR_Cmd(SPI_AICTRL3,6);         //左通道(MIC单声道输入)        VS_WR_Cmd(SPI_CLOCKF,0X2000);       //设置VS10XX的时钟,MULT:2倍频;ADD:不允许;CLK:12.288Mhz        VS_WR_Cmd(SPI_MODE,0x1804);    //MIC,录音激活          delay_ms(5);                                      //等待至少1.35ms       VS_Load_Patch((u16*)wav_plugin,40);//VS1053的WAV录音需要patch } 该函数就是用我们前面介绍的方法,激活VS1053的PCM模式,本章,我们使用的是8Khz采样率,16位单声道线性PCM模式,AGC通过函数参数设置。最后加载patch(用于修复VS1053录音BUG)。 第二个函数是初始化wav头的函数:recoder_wav_init,该函数代码如下: //初始化WAV头. void recoder_wav_init(__WaveHeader* wavhead) //初始化WAV头                   {        wavhead-riff.ChunkID=0X46464952;        //"RIFF"        wavhead-riff.ChunkSize=0;                      //还未确定,最后需要计算        wavhead-riff.Format=0X45564157;          //"WAVE"        wavhead-fmt.ChunkID=0X20746D66;      //"fmt "        wavhead-fmt.ChunkSize=16;                   //大小为16个字节        wavhead-fmt.AudioFormat=0X01;           //0X01,表示PCM;0X01,表示IMA ADPCM       wavhead-fmt.NumOfChannels=1;             //单声道       wavhead-fmt.SampleRate=8000;               //8Khz采样率 采样速率       wavhead-fmt.ByteRate=wavhead-fmt.SampleRate*2;//16位,即2个字节       wavhead-fmt.BlockAlign=2;                     //块大小,2个字节为一个块       wavhead-fmt.BitsPerSample=16;                     //16位PCM      wavhead-data.ChunkID=0X61746164;       //"data"       wavhead-data.ChunkSize=0;                     //数据大小,还需要计算 } 该函数初始化wav头的绝大部分数据,这里我们设置了该wav文件为8Khz采样率,16位线性PCM格式,另外由于录音还未真正开始,所以文件大小和数据大小都还是未知的,要等录音结束才能知道。该函数__WaveHeader结构体就是由前面介绍的三个Chunk组成,结构为: //wav头 typedef __packed struct {        ChunkRIFF riff;     //riff块        ChunkFMT fmt;  //fmt块        //ChunkFACT fact; //fact块 线性PCM,没有这个结构体        ChunkDATA data;   //data块         }__WaveHeader; 最后,我们介绍recoder_play函数,是录音机实现的主循环函数,该函数代码如下:    非常抱歉,由于编辑器篇幅所限,剩下内容,请看附件。
  • 热度 25
    2013-4-11 23:12
    2400 次阅读|
    0 个评论
    第四十九章 音乐播放器实验        前几年,MP3曾经风行一时,几乎人手一个。如果能自己做一个MP3,我想对于很多朋友来说,是十分骄傲的事情。ALIENTEK战舰STM32开发板自带了一颗非常强劲的MP3解码芯片:VS1053,利用该芯片,我们可以实现MP3/OGG/WMA/WAV/FLAC/AAC/MIDI等各种音频文件的播放。本章,我们将利用战舰STM32开发板实现一个简单的MP3播放器。本章分为如下几个部: 49.1 MP3简介 49.2 硬件设计 49.3 软件设计 49.4 下载验证 49.1 VS1053简介    VS1053是继VS1003后荷兰VLSI公司出品的又一款高性能解码芯片。该芯片可以实现对MP3/OGG/WMA/FLAC/WAV/AAC/MIDI等音频格式的解码,同时还可以支持ADPCM/OGG等格式的编码,性能相对以往的VS1003提升不少。VS1053拥有一个高性能的DSP处理器核VS_DSP,16K的指令RAM,0.5K的数据RAM,通过SPI控制,具有8个可用的通用IO口和一个串口,芯片内部还带了一个可变采样率的立体声ADC(支持咪头/咪头+线路/2线路)、一个高性能立体声DAC及音频耳机放大器。 VS1053的特性如下: ●支持众多音频格式解码,包括OGG/MP3/WMA/WAV/FLAC(需要加载patch)/MIDI/AAC等。 ●对话筒输入或线路输入的音频信号进行OGG(需要加载patch)/IMA ADPCM编码 ●高低音控制 ●带有EarSpeaker空间效果(用耳机虚拟现场空间效果) ●单时钟操作12..13MHz ●内部PLL锁相环时钟倍频器 ●低功耗 ●内含高性能片上立体声DAC,两声道间无相位差 ●过零交差侦测和平滑的音量调整 ●内含能驱动30 欧负载的耳机驱动器 ●模拟,数字,I/O 单独供电 ●为用户代码和数据准备的16KB片上RAM ●可扩展外部DAC的I2S接口 ●用于控制和数据的串行接口(SPI) ●可被用作微处理器的从机 ●特殊应用的SPI Flash引导 ●供调试用途的UART接口 ●新功能可以通过软件和8 GPIO 添加 VS1053相对于它的前辈VS1003,增加了编解码格式的支持(比如支持OGG/FLAC,还支持OGG编码,VS1003不支持)、增加了GPIO数量到8个(VS1003只有4个)、增加了内部指令RAM容量到16KiB(VS1003只有5.5KiB)、增加了I2S接口(VS1003没有)、支持EarSpeaker空间效果(VS1003不支持)等。同时VS1053的DAC相对于VS1003有不少提高,同样的歌曲,用VS1053播放,听起来比1003效果好很多。 VS1053的封装引脚和VS1003完全兼容,所以如果你以前用的是VS1003,则只需要把VS1003换成VS1053,就可以实现硬件更新,电路板完全不用修改。不过需要注意的是VS1003的CVDD是2.5V,而VS1053的CVDD是1.8V,所以你还需要把稳压芯片也变一下,其他都可以照旧了。 VS1053通过SPI接口来接受输入的音频数据流,它可以是一个系统的从机,也可以作为独立的主机。这里我们只把它当成从机使用。我们通过SPI口向VS1053不停的输入音频数据,它就会自动帮我们解码了,然后从输出通道输出音乐,这时我们接上耳机就能听到所播放的歌曲了。 ALIENTEK战舰STM32开发板,自带了一颗VS1053音频编解码芯片,所以,我们直接可以通过开发板来播放各种音频格式,实现一个音乐播放器。战舰STM32开发板自带的VS1053解码芯片电路原理图,如图49.1.1所示:     图49.1.1 ALIENTEK 音频解码模块原理图          VS1053通过7根线同STM32连接,他们是:VS_MISO、VS_MOSI、VS_SCK、VS_XCS、VS_XDCS、VS_DREQ和VS_RST。这7根线同STM32的连接关系如表49.1.1所示:     表49.1.1 VS1053各信号线与STM32连接关系        其中VS_RST是VS1053的复位信号线,低电平有效。VS_DREQ是一个数据  请求信号,用来通知主机,VS1053可以接收数据与否。VS_MISO、VS_MOSI和VS_SCK则是VS1053的SPI接口他们在VS_XCS和VS_XDCS下面来执行不同的操作。从上表可以看出,VS1053的SPI是接在STM32的SPI1上面的。        VS1053的SPI支持两种模式:1,VS1002有效模式(即新模式)。2,VS1001兼容模式。这里我们仅介绍VS1002有效模式(此模式也是VS1053的默认模式)。表49.1.2是在新模式下VS1053的SPI信号线功能描述:     表49.1.2 VS1053新模式下SPI口信号线功能        VS1053的SPI数据传送,分为SDI和SCI,分别用来传输数据/命令。SDI和前面介绍的SPI协议一样的,不过VS1053的数据传输是通过DREQ控制的,主机在判断DREQ有效(高电平)之后,直接发送即可(一次可以发送32个字节)。        这里我们重点介绍一下SCI。SCI串行总线命令接口包含了一个指令字节、一个地址字节和一个16位的数据字。读写操作可以读写单个寄存器,在SCK的上升沿读出数据位,所以主机必须在下降沿刷新数据。SCI的字节数据总是高位在前低位在后的。第一个字节指令字节,只有2个指令,也就是读和写,读为0X03,写为0X02。        一个典型的SCI读时序如图49.1.2所示:     图49.1.2 SCI读时序        从图49.1.2可以看出,向VS1053读取数据,通过先拉低XCS(VS_XCS),然后发送读指令(0X03),再发送一个地址,最后,我们在SO线(VS_MISO)上就可以读到输出的数据了。而同时SI(VS_MOSI)上的数据将被忽略。        看完了SCI的读,我们再来看看SCI的写时序,如图49.1.3所示:     图49.1.3 SCI写时序        图49.1.3中,其时序和图49.1.2基本类似,都是先发指令,再发地址。不过写时序中,我们的指令是写指令(0X02),并且数据是通过SI写入VS1053的, SO则一直维持低电平。细心的读者可能发现了,在这两个图中,DREQ信号上都产生了一个短暂的低脉冲,也就是执行时间。这个不难理解,我们在写入和读出VS1053的数据之后,它需要一些时间来处理内部的事情,这段时间,是不允许外部打断的,所以,我们在SCI操作之前,最好判断一下DREQ是否为高电平,如果不是,则等待DREQ变为高。        了解了VS1053的SPI读写,我们再来看看VS1053的SCI寄存器,VS1053的所有SCI寄存器如表49.1.3所示: SCI寄存器 寄存器 类型 复位值 缩写 描述 0X00 RW 0X0800 MODE 模式控制 0X01 RW 0X000C STATUS VS0153状态 0X02 RW 0X0000 BASS 内置低音/高音控制 0X03 RW 0X0000 CLOCKF 时钟频率+倍频数 0X04 RW 0X0000 DECODE_TIME 解码时间长度(秒) 0X05 RW 0X0000 AUDATA 各种音频数据 0X06 RW 0X0000 WRAM RAM 写/读 0X07 RW 0X0000 WRAMADDR RAM 写/读的基址 0X08 R 0X0000 HDAT0 流的数据标头0 0X09 R 0X0000 HDAT1 流的数据标头1 0X0A RW 0X0000 AIADDR 应用程序起始地址 0X0B RW 0X0000 VOL 音量控制 0X0C RW 0X0000 AICTRL0 应用控制寄存器0 0X0D RW 0X0000 AICTRL1 应用控制寄存器1 0X0E RW 0X0000 AICTRL2 应用控制寄存器2 0X0F RW 0X0000 AICTRL3 应用控制寄存器3   表49.1.3 SCI寄存器        VS1053总共有16个SCI寄存器,这里我们不介绍全部的寄存器,仅仅介绍几个我们在本章需要用到的寄存器。        首先是MODE寄存器,该寄存器用于控制VS1053的操作,是最关键的寄存器之一,该寄存器的复位值为0x0800,其实就是默认设置为新模式。表49.1.4是MODE寄存器的各位描述:     表49.1.4 MODE寄存器各位描述        这个寄存器,我们这里只介绍一下第2和第11位,也就是SM_RESET和SM_SDINEW。其他位,我们用默认的即可。这里SM_RESET,可以提供一次软复位,建议在每播放一首歌曲之后,软复位一次。SM_SDINEW为模式设置位,这里我们选择的是VS1002新模式(本地模式),所以设置该位为1(默认的设置)。其他位的详细介绍,请参考VS1053的数据手册。        接着我们看看BASS寄存器,该寄存器可以用于设置VS1053的高低音效。该寄存器的各位描述如表49.1.5所示: 表49.1.5 BASS寄存器各位描述        通过这个寄存器以上位的一些设置,我们可以随意配置自己喜欢的音效(其实就是高低音的调节)。VS1053的EarSpeaker效果则由MODE寄存器控制,请参考表49.1.4。        接下来,我们介绍一下CLOCKF寄存器,这个寄存器用来设置时钟频率、倍频等相关信息,该寄存器的各位描述如表49.1.6所示:     表49.1.6 CLOCKF寄存器各位描述        此寄存器,重点说明SC_FREQ,SC_FREQ是以4Khz为步进的一个时钟寄存器,当外部时钟不是12.288M的时候,其计算公式为: SC_FREQ=(XTALI-8000000)/4000        式中为XTALI的单位为Hz。表49.1.6中CLKI是内部时钟频率,XTALI是外部晶振的时钟频率。由于我们使用的是12.288M的晶振,在这里设置此寄存器的值为0X9800,也就是设置内部时钟频率为输入时钟频率的3倍,倍频增量为1.0倍。        接下来,我们看看DECODE_TIME这个寄存器。该寄存器是一个存放解码时间的寄存器,以秒钟为单位,我们通过读取该寄存器的值,就可以得到解码时间了。不过它是一个累计时间,所以我们需要在每首歌播放之前把它清空一下,以得到这首歌的准确解码时间。        HDAT0和HDTA1是两个数据流头寄存器,不同的音频文件,读出来的值意义不一样,我们可以通过这两个寄存器来获取音频文件的码率,从而可以计算音频文件的总长度。这两个寄存器的详细介绍,请参考VS1053的数据手册。        最后我们介绍一下VOL这个寄存器,该寄存器用于控制VS1053的输出音量,该寄存器可以分别控制左右声道的音量,每个声道的控制范围为0~254,每个增量代表0.5db的衰减,所以该值越小,代表音量越大。比如设置为0X0000则音量最大,而设置为0XFEFE则音量最小。注意:如果设置VOL的值为0XFFFF,将使芯片进入掉电模式!        关于VS1053的介绍,我们就介绍到这里,更详细的介绍请看VS1053的数据手册。接下来我们说说如何控制通过最简单的步骤,来控制VS1053播放一首歌曲。 1)  复位VS1053 这里包括了硬复位和软复位,是为了让VS1053的状态回到原始状态,准备解码下一首歌曲。这里建议大家在每首歌曲播放之前都执行一次硬件复位和软件复位,以便更好的播放音乐。 2)  配置VS1053 的相关寄存器 这里我们配置的寄存器包括VS1053的模式寄存器(MODE)、时钟寄存器(CLOCKF)、音调寄存器(BASS)、音量寄存器(VOL)等。 3)  发送音频数据 当经过以上两步配置以后,我们剩下来要做的事情,就是往VS1053里面扔音频数据了,只要是VS1053支持的音频格式,直接往里面丢就可以了,VS1053会自动识别,并进行播放。不过发送数据要在DREQ信号的控制下有序的进行,不能乱发。这个规则很简单:只要DREQ变高,就向VS1053发送32个字节。然后继续等待DREQ变高,直到音频数据发送完。 经过以上三步,我们就可以播放音乐了。这一部分就先介绍到这里。 49.2 硬件设计 本章实验功能简介:开机先检测字库是否存在,如果检测无问题,则对VS1053进行RAM测试和正弦测试,测试完后开始循环播放SD卡MUSIC文件夹里面的歌曲(必须在SD卡根目录建立一个MUSIC文件夹,并存放歌曲在里面),在TFTLCD上显示歌曲名字、播放时间、歌曲总时间、歌曲总数目、当前歌曲的编号等信息。KEY0用于选择下一曲,KEY2用于选择上一曲,WK_UP和KEY1用来调节音量。DS0还是用于指示程序运行状态,DS1用于指示VS1053正在初始化。 本实验用到的资源如下: 1)  指示灯DS0和DS1 2)  四个按键(WK_UP/KEY0/KEY1/KEY2) 3)  串口 4)  TFTLCD模块 5)  SD卡 6)  SPI FLASH 7)  VS1053 8)  74HC4052 9)  TDA1308 这些硬件我们都已经介绍过了,其中74HC4052和TDA1308分别是用作音频选择和耳机驱动,在第四十章,我们已经介绍过。本章,我们使用的VS1053同STM32的连接关系详见表49.1.1。 本实验,大家需要准备1个SD卡(在里面新建一个MUSIC文件夹,并存放一些歌曲在MUSIC文件夹下)和一个耳机,分别插入SD卡接口和耳机接口,然后下载本实验就可以通过耳机来听歌了。 49.3 软件设计 打开上一章的工程,首先在HARDWARE文件夹所在的文件夹下新建一个APP的文件夹。在该文件夹里面新建mp3player.c和mp3player.h两个文件。并将APP文件夹加入头文件包含路径。 然后在HARDWARE文件夹下新建一个VS10XX的文件夹,在该文件夹里面新建VS10XX.c、VS10XX.h和flac.h等三个文件。 首先打开VS10XX.c,里面的代码我们不一一贴出了,这里挑几个重要的函数给大家介绍一下,首先要介绍的是VS_Soft_Reset,该函数用于软复位VS1003,其代码如下: void VS_Soft_Reset(void) {            u8 retry=0;                                    while(VS_DQ==0); //等待软件复位结束              VS_SPI_ReadWriteByte(0Xff);//启动传输        retry=0;        while(VS_RD_Reg(SPI_MODE)!=0x0800)// 软件复位,新模式        {               VS_WR_Cmd(SPI_MODE,0x0804);// 软件复位,新模式                    delay_ms(2);//等待至少1.35ms               if(retry++100)break;               }                          while(VS_DQ==0);//等待软件复位结束            retry=0;        while(VS_RD_Reg(SPI_CLOCKF)!=0X9800)//设置VS10XX的时钟,3倍频 ,1.5xADD        {               VS_WR_Cmd(SPI_CLOCKF,0X9800);//设置VS10XX的时钟,3倍频 ,1.5xADD               if(retry++100)break;               }                                                                                                  delay_ms(20); } 非常抱歉,由于编辑器篇幅所限,剩下内容,请看附件。  
  • 热度 17
    2011-12-6 16:17
    1493 次阅读|
    0 个评论
    //-------------------------------- // load a plugin // 1 Read register address number addr and repeat number n; // 2 if (n 0x8000u),write the next word n times to register addr; // 3.Else write next n words to register addr; // 4.continue until array has been exhausted. //--------------------------------- void LoadUserCode(void) { int i = 0; unsigned int addr, n, val; unsigned char valh,vall;  i =sizeof(plugin );   while (isizeof(plugin)/sizeof(plugin ))  {      addr = plugin ;     n = plugin ;     if (n 0x8000U)   { /* RLE run, replicate n samples */        n = 0x7FFF;        val = plugin ;   valh = (val0xff00) 8;   vall = val0x00ff;        while (n--)    {    Vs1053WriteRegister(addr,valh,vall);           }       }  else    {           /* Copy run, copy n samples */        while (n--)    {           val = plugin ;    valh = (val0xff00) 8;    vall = val0x00ff;    Vs1053WriteRegister(addr,valh,vall);           }       }    } }
相关资源