51单片机驱动VS1003(模拟spi/自带SPI)

来源:互联网 发布:javascript 清空数组 编辑:程序博客网 时间:2024/05/18 11:47

<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中设置)

//初始化spivoid 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;}


2.模拟SPI

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;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> //单片机头文件//VS1003IOsbit 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操作*************************************************************************************************//初始化spivoid 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=0void 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;}











0 0
原创粉丝点击