<pre name="code" class="cpp">
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">本文章使用STC单片机驱动VS1003,(STC自带SPI和模拟SPI)</span>
VS1003使用指南,中文数据手册,MP3格式说明戳http://download.csdn.net/detail/sparkstrike/7980637
单片机:STC12C5A60S2 晶振24MHZ
一.通信部分:
1.STC12C5A60S2自带SPI(VS1003的spi通信是高位先发送,需在SPCTL中设置)
//初始化spi
void init_spi(void){
SPCTL = 0xdd;//忽略SS,设置主机,spi高位先发送
SPSTAT = 0xc0;//清除状态寄存器
SPDAT = 0;//初始化数据寄存器
}
void spi_write(unsigned char sendData){
SPDAT = sendData;
while((SPSTAT&0x80)==0);
SPSTAT = 0xc0;//清除状态寄存器
SPSTAT = 0;
}
unsigned char bdata dat; //可位寻址的变量dat,用于优化SPI
sbit dat7=dat^7; //取出每一个位
sbit dat6=dat^6;
sbit dat5=dat^5;
sbit dat4=dat^4;
sbit dat3=dat^3;
sbit dat2=dat^2;
sbit dat1=dat^1;
sbit dat0=dat^0;
sbit SI =P1^5;
sbit SCLK =P1^7;
sbit SI =P1^5;
sbit SCLK =P1^7;
void spi_write(unsigned char x)
{
dat=x; //将x赋值给可位寻址的变量dat
SI=dat7; //从高位开始输出,从dat7一直到dat0
SCLK=0; //时钟的上升沿,位被写出
SCLK=1;
SI=dat6;
SCLK=0;
SCLK=1;
SI=dat5;
SCLK=0;
SCLK=1;
SI=dat4;
SCLK=0;
SCLK=1;
SI=dat3;
SCLK=0;
SCLK=1;
SI=dat2;
SCLK=0;
SCLK=1;
SI=dat1;
SCLK=0;
SCLK=1;
SI=dat0;
SCLK=0;
SCLK=1;
}
void SPI_W(unsigned char Data){
unsigned char i;
for(i = 0; i<8; i++){
Data <<= 1;
SCLK = 0;
SI = CY;//CY位是单片机在作移位运算时溢出的一位
SCLK = 1;
};
SI = 1;
}
左移 <<
0100 1111 << 左移一位:1001 1110 CY=0 ;第一位跑到CY上,最后一位补0 ;
在keil c51中,内部函数库INTRINS.H中_crol_(m,n)表示将m循环左移n位:第一位的跑到最后一位上。
右移>>
1000 1111 >> 右移一位 0100 0111 CY=1 ;第一位补0,最后一位跑到CY上;
二.VS1003引脚定义
XRESET 低电平复位
DREQ 数据请求脚
XCS SCL命令写入片选
XDCS SDI(mp3数据)写入片选
SO 串行输出,在读操作时,数据在 SCK 的下降沿处从此脚移出,在写操作时为高阻态。
SI 串行输入,如果片选有效,SI 就在 SCLK的上升沿处采样。
SCLK 时钟
三.发送SCI命令
VS1003的DREQ 脚,在 VS1003 的 FIFO 在能够接受数据的时候输出高电平。此时,VS1003 可获取至少 32Byte 的 SDI数据或一个 SCI 命令。遵循这个标准,当 DREQ 变低时,发送器必须停止发送新的数据。
注意:在每次 SCI 操作后,DREQ 线被置 0。VS1003 靠此期间操作。不允许在 DREQ 变为 1 之前开始新的SCI/SDI 操作。
发送SCI命令的顺序:
首先等待DREQ脚为高电平,再将 XCS 片选拉低以选择芯片,再通过 SI 线发送8 位的读操作码( 0x02)和 8 位的地址。随即发送 16 位的数据字。 当最后一位被移入且最后的时钟已发送,必须将 XCS 拉高以完成写操作。
具体地址和数据字说明见资料/VS1003使用指南/P5
void wr_command(unsigned char addr,unsigned char hdat,unsigned char ldat )
{
DREQ=1;
while(!DREQ);//等待直到VS1003可以接受数据
XCS=0; //开SCI片选
spi_write(0x02);//发送读操作码
spi_write(addr);//地址
spi_write(hdat);//数据字高位
spi_write(ldat);//数据字地位
XCS=1;//关<span style="font-family: Arial, Helvetica, sans-serif;">SCI片选</span>
}
四.初始化V是1003
一般初始化流程:
●硬复位,xReset = 0;
●延时,xDCS、xCS、xReset置1;
●等待DREQ为高;
●软件复位:SPI_MODE = 0x0804;
●等待DREQ为高(软件复位结束);
●设置VS1003的时钟:SCI_CLOCKF = 0x9800,3倍频;
●设置VS1003的采样率:SPI_AUDATA = 0xBB81,采样率48k,立体声;
●设置重音:SPI_BASS = 0x0055;
●设置音量:SCI_VOL = 0x2020;
●向vs1003发送4个字节无效数据,用以启动SPI发送。
void Mp3Reset(void)
{
XRESET=0;
delay(100);
XDCS=XCS=XRESET=1;
wr_command(0x00,0x08,0x04);
delay(10);
DREQ=1;
while(!DREQ);
wr_command(0x03,0x98,0x00);<span style="white-space:pre"> </span>//设置VS1003的时钟:SCI_CLOCKF = 0x9800,3倍频
delay(10);
wr_command(0x05,0xbb,0x81);<span style="white-space:pre"> </span>//设置VS1003的采样率:SPI_AUDATA = 0xBB81,采样率48k,立体声
delay(10);
wr_command(0x02,0x00,0x55);<span style="white-space:pre"> </span>//设置重音:SPI_BASS = 0x0055;
delay(10);
wr_command(0x0b,0x10,0x10); // 音量
delay(10);
spi_write(0);//向vs1003发送4个字节无效数据,用以启动SPI发送
spi_write(0);
spi_write(0);
spi_write(0);
}
五.向VS1003写入音频数据
注意:写音频数据时要开启SDI片选XDS
void send_dat(unsigned char dat)
{
DREQ=1;
while(!DREQ); //VS1003的DREQ为高才能写入数据
spi_write(dat);//通过SPI向VS1003写入一个字节的音频数据
}
六.完整程序
注:程序用音频数据music戳http://download.csdn.net/detail/sparkstrike/7980613
1.模拟spi:
/********vc1003程序(模拟SPI)*************************************************************************************/
#include <STC12C5A60S2.H> //单片机头文件
sbit led = P0^0;
sbit XRESET =P0^7;
sbit DREQ =P0^4;
sbit XCS =P0^6;
sbit XDCS =P0^5;
sbit SO =P1^6;
sbit SI =P1^5;
sbit SCLK =P1^7;
<pre name="code" class="cpp">
unsigned char bdata dat; //可位寻址的变量dat,用于优化SPIsbit dat7=dat^7; //取出每一个位sbit dat6=dat^6;sbit dat5=dat^5;sbit dat4=dat^4;sbit dat3=dat^3;sbit dat2=dat^2;sbit dat1=dat^1;sbit dat0=dat^0;void delay(unsigned int time){while(time--);} void spi_write(unsigned char x){ dat=x; //将x赋值给可位寻址的变量dat SI=dat7; //从高位开始输出,从dat7一直到dat0 SCLK=0; //时钟的上升沿,位被写出 SCLK=1; SI=dat6; SCLK=0; SCLK=1; SI=dat5; SCLK=0; SCLK=1; SI=dat4; SCLK=0; SCLK=1; SI=dat3; SCLK=0; SCLK=1; SI=dat2; SCLK=0; SCLK=1; SI=dat1; SCLK=0; SCLK=1; SI=dat0; SCLK=0; SCLK=1;}void wr_command(unsigned char addr,unsigned char hdat,unsigned char ldat ){ DREQ=1; while(!DREQ); XCS=0; spi_write(0x02); spi_write(addr); spi_write(hdat); spi_write(ldat); XCS=1;}void Mp3Reset(void){ XRESET=0; delay(100); XDCS=XCS=XRESET=1; wr_command(0x00,0x08,0x04); delay(10); DREQ=1; while(!DREQ); wr_command(0x03,0x98,0x00); delay(10); wr_command(0x05,0xbb,0x81); delay(10); wr_command(0x02,0x00,0x55); delay(10); wr_command(0x0b,0x10,0x10); // 音量 delay(10); spi_write(0); spi_write(0); spi_write(0); spi_write(0);}void send_dat(unsigned char dat) { DREQ=1; while(!DREQ); //VS1003的DREQ为高才能写入数据 spi_write(dat);//通过SPI向VS1003写入一个字节的音频数据}void main(){unsigned int i;Mp3Reset();XDCS=0;for(i=0;i<15000;i++){
send_dat(music[i]);}while(1);}
2.自带spi
#include <STC12C5A60S2.H> //单片机头文件
//VS1003IO
sbit XRESET =P0^7;
sbit DREQ =P0^4;
sbit XCS =P0^6;
sbit XDCS =P0^5;
void delay_ms(int i){
int a,b;
for(a=0;a<i;a++){
for(b=0;b<600;b++);
};
}
//******************vs1003操作*************************************************************************************************
//初始化spi
void init_spi(void){
SPCTL = 0xdd;//忽略SS,设置主机,spi高位先发送
SPSTAT = 0xc0;//清除状态寄存器
SPDAT = 0;//初始化数据寄存器
}
void spi_write(unsigned char sendData){
SPDAT = sendData;
while((SPSTAT&0x80)==0);
SPSTAT = 0xc0;//清除状态寄存器
SPSTAT = 0;
}
void delay(unsigned int time)
{
while(time--);
}
void wr_command(unsigned char addr,unsigned char hdat,unsigned char ldat )
{
DREQ=1;
while(!DREQ);
XCS=0;
spi_write(0x02);
spi_write(addr);
spi_write(hdat);
spi_write(ldat);
XCS=1;
}
//vs1003初始化
void Mp3Reset(void)
{
XRESET=0;
delay(100);
XDCS=XCS=XRESET=1;
wr_command(0x00,0x08,0x04);
delay(10);
DREQ=1;
while(!DREQ);
wr_command(0x03,0x98,0x00);
delay(10);
wr_command(0x05,0xbb,0x81);
delay(10);
wr_command(0x02,0x00,0x55);
delay(10);
wr_command(0x0b,0x2e,0x2e); // 音量
delay(10);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(0);
}
//向VS1003写入一个字节的音频数据,写之前要打开XDCS片选,XDCS=0
void send_dat(unsigned char dat)
{
DREQ=1;
while(!DREQ);//VS1003的DREQ为高才能写入数据
spi_write(dat);//通过SPI向VS1003写入一个字节的音频数据
}
void main(){ <pre name="code" class="csharp"><span style="white-space:pre"> </span>unsigned int i;
<span style="white-space:pre"> </span>init_spi();
Mp3Reset();
XDCS=0;
for(i=0;i<15000;i++){
<span> </span>send_dat(music[i]);
}
while(1);<span style="font-family: Arial, Helvetica, sans-serif;"> </span>
}
附1:正弦测试
x调整正弦频率
void Sintest(unsigned char x)
{
wr_command(0x00,0x08,0x20);
DREQ=1;
while(!DREQ);
XDCS=0;XCS=1;
spi_write(0x53);
spi_write(0xef);
spi_write(0x6e);
spi_write(x);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(0);
delay(5000);
spi_write(0x45);
spi_write(0x78);
spi_write(0x69);
spi_write(0x74);
spi_write(0);
spi_write(0);
spi_write(0);
spi_write(0);
delay(5000);
XDCS=1;
}