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

<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;
}


2.模拟SPI

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;
}











 

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值