Arduino+VS1003播放音频

基础板是Arduino UNO Ver3 Board,Ethernet Shield作为SD和WebServer扩展板,vs1003作为解码器,端口A0-A4用作数字IO模拟SPI来驱动VS1003。

以前用PIC32做了一个月才做出来,今天用Arduino UNO一天就能够给弄出来了。

不过Arduino UNO的芯片Atmega 328最多最多跑到20MHZ,数组申请过了512都hold不住(BootLoader和Text一起能用掉32K?深表怀疑)

应该是芯片处理能力的限制,使得其仅能解码32Kbps的音频,对于64Kbps以上的都很卡,当时用PIC32 80MHZ能够解码128KBps。

(1)

IDE:visual studio

programmer & loader:Xloader

 (2)鲍照

Arduino+VS1003播放音频

 

(3)代码。主文件。还没有整理注释。

#include <SD.h>

#include "cfg.h"

#include "vs1003.h"

#include "softSPI.h"



///////////////////////////////////////////////////////////////////////////



//调节spi2速度,数字越小速度越大

unsigned int spi2_delay_time = SPI2_HIGH;



#define DATA_BUFFER_LEN 512

unsigned char data_buffer[DATA_BUFFER_LEN];



///////////////////////////////////////////////////////////////////////////

void spi2_init(void)

{

    pinMode(SPI2_CS,OUTPUT);

    pinMode(SPI2_MOSI,OUTPUT);

    pinMode(SPI2_CLK,OUTPUT);

    pinMode(SPI2_MISO,INPUT);

}



void spi2_high_speed_mode(){

    spi2_delay_time = SPI2_HIGH;



}



void spi2_low_speed_mode(){

    spi2_delay_time = SPI2_LOW;

}



unsigned char spi2_8TxRx(unsigned char byte)

{       

    unsigned char bit;

    SPI2_SELECT();

    for (bit = 0; bit < 8; bit++) {

        /* write MOSI on trailing edge of previous clock */

        if (byte & 0x80)

            SPI2_SETMOSI();

        else

            SPI2_CLRMOSI();

        byte <<= 1;



        /* half a clock cycle before leading/rising edge */

        //if(spi2_delay_time){

        //    delay(spi2_delay_time);

        //}

        SPI2_SETCLK();



        /* half a clock cycle before trailing/falling edge */

        //if(spi2_delay_time)  {

        //    delay(spi2_delay_time);

        //}



        /* read MISO on trailing edge */

        byte |= SPI2_READMISO();

        SPI2_CLRCLK();

    }

    SPI2_DESELECT();

    return byte;

}



///////////////////////////////////////////////////////////////////////////



//------------------------------------------------------------------------------  

//	write cmd to vs1003

//	address,data

//------------------------------------------------------------------------------

//  write cmd as following:

//	1.等待DREQ为高(当DREQ为低时,说明芯片还没有就绪)

//	2.将XCS(命令片选)拉低

//	3.写入0x02

//	4.写入寄存器地址

//	5.分别写入数据的高字节与低字节

//	6.将XCS置高

//------------------------------------------------------------------------------

void Vs1003_CMD_Write(int8u_t address,int16u_t data)

{

    unsigned char high = data >> 8;

    unsigned char low = data;



    spi2_init();//low speed init



    //wait for free

    while(MP3_DREQ_READ() == LOW)

        ;

    //MP3_DCS_DES(); //MP3_DATA_CS=1;



    //MP3_CCS_DES();

    //delay(1);

    MP3_CCS_SEL(); //MP3_CMD_CS=0;pull down XCS 



    spi2_8TxRx(VS_WRITE_COMMAND);//send write command

    spi2_8TxRx(address); //send addr

    //spi2_16TxRx(data);

    spi2_8TxRx(high); //8bits high of data

    spi2_8TxRx(low);	 //8bits low of data



    MP3_CCS_DES();   	//MP3_CMD_CS=1;

    spi2_high_speed_mode();//high speed mode for data transport

}



int16u_t Vs1003_CMD_Read(int8u_t address)

{

    int16u_t data;



    spi2_init();//low speed init



    //wait for free

    while(MP3_DREQ_READ() == LOW)

        ;

    //pull down XCS

    MP3_CCS_SEL();



    //send cmd:VS_READ_COMMAND

    spi2_8TxRx(VS_READ_COMMAND);

    //senb addr

    spi2_8TxRx(address);



    //get the uint16 data

    data = spi2_8TxRx(0X00);

    data <<= 8;

    data += spi2_8TxRx(0X00);



    MP3_CCS_DES();

    spi2_high_speed_mode();//high speed mode for data transport

    return data;

}

//------------------------------------------------------------------------------  

//	configure vs1003

//	address,data

//------------------------------------------------------------------------------

//	1.硬件复位:接XRESET拉低

//	2.延时,将XDCS、XCS、XRESET置高

//	3.向MODE中写入0X0804

//	4.等待DREQ为高

//	5.设置VS1003的时钟:SCI_CLOCKF=0x9800,3倍频 

//	6.设置VS1003的采样率:SPI_AUDATA=0xbb81,采样率48k,立体声

//	7.设置重音:SPI_BASS=0x0055

//	8.设置音量:SCI_VOL=0x2020

//	9.这一步被很多人忽视,向VS1003发送4个字节的无效数据,用以启动SPI发送

//---------------------------------------------------------------------------

void Vs1003_Init(void)

{

    spi2_init();

    SPI2_SELECT();

    

    // set pins

    pinMode(MP3_CMD_CS,OUTPUT);

    pinMode(MP3_XREST,OUTPUT);

    pinMode(MP3_DREQ,INPUT);

    pinMode(MP3_DATA_CS,OUTPUT);



    MP3_RST_SET(LOW);

    delay(10);



    MP3_CCS_DES();  		

    

    //reset

    MP3_RST_SET(HIGH); 		

    MP3_DCS_DES(); 		//xcs = 0;



    Vs1003_CMD_Write(SPI_MODE,0x0804);

   

    //wait for DREQ high

    while( MP3_DREQ_READ() == LOW )

        ;



    //step 5-9

    Vs1003_CMD_Write(SPI_CLOCKF,0xe800);

    delay(1);

    Vs1003_CMD_Write(SPI_AUDATA,0XBB81);

    delay(1);

    Vs1003_CMD_Write(SPI_BASS,0x0055);

    delay(1);

    Vs1003_CMD_Write(SPI_VOL,0x2020);

    delay(1);



    //向vs1003发送4个字节无效数据,用以启动SPI发送

    MP3_DCS_SEL();//选中数据传输

    spi2_8TxRx(0XFF);

    spi2_8TxRx(0XFF);

    spi2_8TxRx(0XFF);

    spi2_8TxRx(0XFF);

    MP3_DCS_DES();//取消数据传输

    delay(10);



    Serial.print("vs1003 init:init over\n");



    spi2_high_speed_mode();//high speed mode for data transport

}



//-------------------------------------------------------------------------

//正弦测试 

//	1.进入VS1003的测试模式:SPI_MODE=0X0820

//	2.等待DREQ为高

//	3.将XDCS接低,而XCS要置高,选择VS1003的数据接口

//	4.向VS1003发送正弦测试命令:0X53 0XEF 0X6E 0X30 0X00 0X00 0X00 0X00

//	  其中0X30为频率,用户可以修改为其它值

//	5.延时一段时间

//	6.退出正弦测试,发送命令:0X45 0X78 0X69 0X74 0X00 0X00 0X00 0X00

//	7.延时一段时间

//	8.循环以上流程

//-------------------------------------------------------------------------

void Vs1003_Sine_Test(unsigned char x)

{

    Vs1003_CMD_Write(SPI_MODE,0x0820);//进入vs1003的测试模式	    



    //等待DREQ为高

    while (MP3_DREQ_READ() == LOW)

        ;



    //向vs1003发送正弦测试命令:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00

    //其中n = 0x24, 设定vs1003所产生的正弦波的频率值,具体计算方法见vs1003的datasheet

    SPI2_SELECT();

    MP3_CCS_DES();

    MP3_DCS_SEL();//选中数据传输



    spi2_8TxRx(0x53);

    spi2_8TxRx(0xef);

    spi2_8TxRx(0x6e);

    spi2_8TxRx(x);

    spi2_8TxRx(0x00);

    spi2_8TxRx(0x00);

    spi2_8TxRx(0x00);

    spi2_8TxRx(0x00);

    delay(100);



    spi2_8TxRx(0x45);

    spi2_8TxRx(0x78);

    spi2_8TxRx(0x69);

    spi2_8TxRx(0x74);

    spi2_8TxRx(0x00);

    spi2_8TxRx(0x00);

    spi2_8TxRx(0x00);

    spi2_8TxRx(0x00);

    MP3_DCS_DES();	 

}	 



//------------------------------------------------------------------------------ 

//	xiaoyang [email protected] HIT

//	write data to vs1003

//	address,data

//------------------------------------------------------------------------------

// 	send data and paly music

//	数据写入主要看DREQ信号,在VS1003的FIFO能够接受数据的时候输出高电平。

//	每次可以写入32个字节的数据。而DREQ变低时,单片机就要停止数据的发送。

//  具体的写数据的方法如下:

//		1.将XDCS拉低

//		2.等待DREQ为高

//		3.通过SPI写入数据

//		4.在文件没有结束前不断重复2与3操作

//		5.在所有的数据都发送完毕后,最后发送2048个无效字节,用以清除VS1003的数据缓冲区

//		6.将XDCS置高

//------------------------------------------------------------------------------

void Vs1003_DATA_Write(int8u_t *data,int16u_t len)

{

    unsigned int i = 0;

    //Serial.print("Vs1003_DATA_Write");

    MP3_DCS_SEL(); 



    //send data

    for(i = 0; i < len; i++)

    {

        //wait for DREQ high

        while (MP3_DREQ_READ() == LOW)

            ;

        spi2_8TxRx(data[i]);

    }



    MP3_DCS_DES();

}         



//------------------------------------------------------------------------------  

//	write data to vs1003

//	address,data

//------------------------------------------------------------------------------

//	用于测试vs1003的各个模块

//------------------------------------------------------------------------------  

void Vs1003_Test()

{

    int i = 0;

    int16u_t data;



    Vs1003_Init();



    //raw testing

    do{

        data = 0x0;

        Serial.print("Test Start,Reg Vol data=\n");

        Serial.println(data,HEX);

        Vs1003_CMD_Write(SPI_VOL,0x2020);

        data = Vs1003_CMD_Read(SPI_VOL);

        Serial.print("Test end, Reg VOL data=");

        Serial.println(data,HEX);

        delay(10);

    }while(0);



    Serial.print("sine test..\n") ;

    for(i = 0; i< 15; i++)

    {

        Serial.print("sine test, i");

        Serial.println(i);

        Vs1003_Sine_Test(i);

    }



    Serial.print("begin to play music\n");

    //play data

    //while(1){

    //#define data_length 20480	//the length of the mp3 stream

    //Vs1003_DATA_Write(mp3_data,20480);

    //}

}





///////////////////////////////////////////////////////////////////////////





/*

 * 

 * return the bytes of a file.

 */

int 

get_file_size(char* filename){

    File rfd;

    int buf_len = 0;

    if (!SD.exists(filename)) {

        Serial.println("test.txt doesn't exist.");

        return buf_len;

    }



    rfd = SD.open(filename, FILE_READ);

    if(rfd){

        buf_len = rfd.available();

    }

    rfd.close();

    return buf_len;

}



int 

sd_test(char* filename){

    File rfd;

    const int buf_len = 512;

    char buf[buf_len];

    int rw_count = 0;



    if (!SD.exists(filename)) {

        Serial.println("test.txt doesn't exist.");

        return FAIL;

    }



    rfd = SD.open(filename, FILE_READ);

    if (rfd) {

        // read from the file until there's nothing else in it:

        while (rfd.available()) {

            rw_count = rfd.read(buf,buf_len);

            buf[rw_count] = '\0';

            Serial.print(buf);

        }

        // close the file:

        rfd.close();

    } else {

        // if the file didn't open, print an error:

        Serial.print("error opening:");

        Serial.print(filename);

    }

    

    return SUC;

}



///////////////////////////////////////////////////////////////////////////

int 

play_file(char* filename){

    File rfd;

    int rw_count = 0;



    if (!SD.exists(filename)) {

        Serial.println("File to paly doesn't exist.");

        return FAIL;

    }



    rfd = SD.open(filename, FILE_READ);

    if (rfd) {

        // read from the file until there's nothing else in it:

        while (rfd.available()) {

            rw_count = rfd.read(data_buffer,DATA_BUFFER_LEN);

            Vs1003_DATA_Write(data_buffer,rw_count);

        }

        // close the file:

        rfd.close();

    } else {

        // if the file didn't open, print an error:

        Serial.print("error opening:");

        Serial.print(filename);

    }

    

    return SUC;

}



void setup()

{

    Serial.begin(9600);

    /*wait until serial is ok*/

    while(!Serial){

        Serial.print("Serial open error,try after 1000 ms.");

        delay(1000);

        ;

    }



    Serial.print("Initializing SD card...");

    /*

     * On the Ethernet Shield, CS is pin 4. It's set as an output by default.

     * Note that even if it's not used as the CS pin, the hardware SS pin 

     * (10 on most Arduino boards, 53 on the Mega) must be left as an output 

     * or the SD library functions will not work. 

     */

    pinMode(10, OUTPUT);

    if (!SD.begin(4)) {

        Serial.print("nitialization failed.");

        delay(1000);

        return;

    }



    delay(3000);

    Serial.println("Begin vs1003 test.");



    Vs1003_Test();

    Serial.println("initialization done.");

}



void loop()

{

    //char* filename = "nokia.mp3";

    char* filenames[] = {

        "desert.mp3",

        "memory2.mp3"

    };



    //sd_test(filename);   

    play_file(filenames[1]);

    delay(3000);

    play_file(filenames[0]);

    delay(3000);

}

 

 

你可能感兴趣的:(arduino)