基础板是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)鲍照

(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 yi@2011.3.14 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);
}
浙公网安备 33010602011771号