⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vs1003x.c

📁 基于stm32的MP3播放器
💻 C
字号:
#include "vs1003.h"	 

//VS1003的全功能函数
//支持SIN测试和RAM测试
//并加入了VS1003的频谱显示代码,不过说实话不咋地,还不如自己写的频谱分析,怀疑是不是真实的频谱变换?  
//正点原子@SCUT
//V1.1

//VS1003设置参数
//0,henh.1,hfreq.2,lenh.3,lfreq 5,主音量
u8 vs1003ram[5]={0,0,0,0,250};
//保存VS1003的设置
//EEPROM地址:486~490 共五个
void Save_VS_Set(void)
{
	u8 t;
	for(t=0;t<5;t++)FM24C16_WriteOneByte(488+t,vs1003ram[t]);//vs1003ram保存 	 
}
//读取VS1003的设置
//EEPROM地址:486~490 共五个
void Read_VS_Set(void)
{
	u8 t;
	for(t=0;t<5;t++)vs1003ram[t]=FM24C16_ReadOneByte(488+t);//vs1003ram调用
}	 					 
//SPI1口读写一个字节
//TxData:要发送的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{
	while((SPI1->SR&1<<1)==0);//等待发送区空				  
	SPI1->DR=TxData;	 	  //发送一个byte   
	while((SPI1->SR&1<<0)==0);//等待接收完一个byte  
	return SPI1->DR;          //返回收到的数据				    
} 
//设置SPI1的速度
//SpeedSet:1,高速;0,低速;
void SPI1_SetSpeed(u8 SpeedSet)
{
	SPI1->CR1&=0XFFC7;
	if(SpeedSet==1)//高速
	{
		SPI1->CR1|=6<<3;//Fsck=Fpclk/64=1.125Mhz	
	}else//低速
	{
		SPI1->CR1|=6<<3; //Fsck=Fpclk/128=562.5Khz
	}
	SPI1->CR1|=1<<6; //SPI设备使能	  
} 
//软复位VS1003
void Vs1003SoftReset(void)
{	 
	u8 retry; 				   
	while((GPIOC->IDR&MP3_DREQ)==0);//等待软件复位结束
	SPI1_ReadWriteByte(0X00);//启动传输
	retry=0;
	while(Vs1003_REG_Read(SPI_MODE)!=0x0804)// 软件复位,新模式  
	{
		Vs1003_CMD_Write(SPI_MODE,0x0804);// 软件复位,新模式
		delay_ms(2);//等待至少1.35ms 
		if(retry++>100)break; 
	}	 				  
	while ((GPIOC->IDR & MP3_DREQ) == 0);//等待软件复位结束	   

	retry=0;
	while(Vs1003_REG_Read(SPI_CLOCKF)!=0X9800)//设置vs1003的时钟,3倍频 ,1.5xADD 
	{
		Vs1003_CMD_Write(SPI_CLOCKF,0X9800);//设置vs1003的时钟,3倍频 ,1.5xADD
		if(retry++>100)break; 
	}		   
	retry=0;
	while(Vs1003_REG_Read(SPI_AUDATA)!=0XBB81)//设置vs1003的时钟,3倍频 ,1.5xADD 
	{
		Vs1003_CMD_Write(SPI_AUDATA,0XBB81);
		if(retry++>100)break; 
	}

	//Vs1003_CMD_Write(SPI_CLOCKF,0X9800); 	    
	//Vs1003_CMD_Write(SPI_AUDATA,0XBB81); //采样率48k,立体声	 
	set1003();//设置VS1003的音效				 
	ResetDecodeTime();//复位解码时间	    
    //向vs1003发送4个字节无效数据,用以启动SPI发送
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0XFF);
	SPI1_ReadWriteByte(0XFF);
	SPI1_ReadWriteByte(0XFF);
	SPI1_ReadWriteByte(0XFF);
	MP3_DCS_SET(1);//取消数据传输
	delay_ms(20);
} 
//硬复位MP3
void Mp3Reset(void)
{
	MP3_RST_SET(0);
	delay_ms(20);
	MP3_DCS_SET(1);//取消数据传输
	MP3_CCS_SET(1);//取消数据传输
	MP3_RST_SET(1);    
	while((GPIOC->IDR & MP3_DREQ)==0);	//等待DREQ为高
	delay_ms(20);				 
}
//正弦测试 
void VsSineTest(void)
{											    
	Mp3Reset();	 
	Vs1003_CMD_Write(0x0b,0X2020);	  //设置音量	 
 	Vs1003_CMD_Write(SPI_MODE,0x0820);//进入vs1003的测试模式	    
	while ((GPIOC->IDR & MP3_DREQ) == 0);     //等待DREQ为高
 	//向vs1003发送正弦测试命令:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
 	//其中n = 0x24, 设定vs1003所产生的正弦波的频率值,具体计算方法见vs1003的datasheet
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0x53);
	SPI1_ReadWriteByte(0xef);
	SPI1_ReadWriteByte(0x6e);
	SPI1_ReadWriteByte(0x24);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1); 
    //退出正弦测试
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0x45);
	SPI1_ReadWriteByte(0x78);
	SPI1_ReadWriteByte(0x69);
	SPI1_ReadWriteByte(0x74);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1);		 

    //再次进入正弦测试并设置n值为0x44,即将正弦波的频率设置为另外的值
    MP3_DCS_SET(0);//选中数据传输      
	SPI1_ReadWriteByte(0x53);
	SPI1_ReadWriteByte(0xef);
	SPI1_ReadWriteByte(0x6e);
	SPI1_ReadWriteByte(0x44);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1);
    //退出正弦测试
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0x45);
	SPI1_ReadWriteByte(0x78);
	SPI1_ReadWriteByte(0x69);
	SPI1_ReadWriteByte(0x74);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1);	 
}	 
//ram 测试 																				 
void VsRamTest(void)
{
	u16 regvalue ;	   
	Mp3Reset();     
 	Vs1003_CMD_Write(SPI_MODE,0x0820);// 进入vs1003的测试模式
	while ((GPIOC->IDR&MP3_DREQ)==0); // 等待DREQ为高
 	MP3_DCS_SET(0);	       			  // xDCS = 1,选择vs1003的数据接口
	SPI1_ReadWriteByte(0x4d);
	SPI1_ReadWriteByte(0xea);
	SPI1_ReadWriteByte(0x6d);
	SPI1_ReadWriteByte(0x54);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(50);  
	MP3_DCS_SET(1);
	regvalue=Vs1003_REG_Read(SPI_HDAT0); // 如果得到的值为0x807F,则表明完好。
	printf("regvalueH:%x\n",regvalue>>8);//输出结果 
	printf("regvalueL:%x\n",regvalue&0xff);//输出结果 
}     
//向VS1003写命令
//address:命令地址
//data:命令数据
void Vs1003_CMD_Write(u8 address,u16 data)
{  
    while((GPIOC->IDR&MP3_DREQ)==0);//等待空闲
	SPI1_SetSpeed(0);//低速 
	 
	MP3_DCS_SET(1); //MP3_DATA_CS=1;
	MP3_CCS_SET(0); //MP3_CMD_CS=0; 
	
	SPI1_ReadWriteByte(VS_WRITE_COMMAND);//发送VS1003的写命令
	SPI1_ReadWriteByte(address); //地址
	SPI1_ReadWriteByte(data>>8); //发送高八位
	SPI1_ReadWriteByte(data);	 //第八位
	MP3_CCS_SET(1);          //MP3_CMD_CS=1; 
	SPI1_SetSpeed(1);//高速
} 
//向VS1003写数据
void Vs1003_DATA_Write(u8 data)
{
	MP3_DCS_SET(0);   //MP3_DATA_CS=0;
	SPI1_ReadWriteByte(data);
	MP3_DCS_SET(1);   //MP3_DATA_CS=1;
	MP3_CCS_SET(1);   //MP3_CMD_CS=1; 
}         
//读VS1003的寄存器           
//读VS1003
//注意不要用倍速读取,会出错
u16 Vs1003_REG_Read(u8 address)
{ 
	u16 temp=0; 
    while((GPIOC->IDR&MP3_DREQ)==0);//非等待空闲状态 
	SPI1_SetSpeed(0);//低速 
	MP3_DCS_SET(1);       //MP3_DATA_CS=1;
	MP3_CCS_SET(0);       //MP3_CMD_CS=0;
	SPI1_ReadWriteByte(VS_READ_COMMAND);//发送VS1003的读命令
	SPI1_ReadWriteByte(address);        //地址
	temp=SPI1_ReadWriteByte(0xff);		//读取高字节
	temp=temp<<8;
	temp+=SPI1_ReadWriteByte(0xff); 	//读取低字节
	MP3_CCS_SET(1);      //MP3_CMD_CS=1; 
	SPI1_SetSpeed(1);//高速
    return temp; 
}  
//FOR WAV HEAD0 :0X7761 HEAD1:0X7665    
//FOR MIDI HEAD0 :other info HEAD1:0X4D54
//FOR WMA HEAD0 :data speed HEAD1:0X574D
//FOR MP3 HEAD0 :data speed HEAD1:ID
//比特率预定值
const u16 bitrate[2][16]=
{ 
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}, 
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}
};
//返回Kbps的大小
//得到mp3&wma的波特率
u16 GetHeadInfo(void)
{
	unsigned int HEAD0;
	unsigned int HEAD1;            
    HEAD0=Vs1003_REG_Read(SPI_HDAT0); 
    HEAD1=Vs1003_REG_Read(SPI_HDAT1);
    switch(HEAD1)
    {        
        case 0x7665:return 0;//WAV格式
        case 0X4D54:return 1;//MIDI格式 
        case 0X574D://WMA格式
        {
            HEAD1=HEAD0*2/25;
            if((HEAD1%10)>5)return HEAD1/10+1;
            else return HEAD1/10;
        }
        default://MP3格式
        {
            HEAD1>>=3;
            HEAD1=HEAD1&0x03; 
            if(HEAD1==3)HEAD1=1;
            else HEAD1=0;
            return bitrate[HEAD1][HEAD0>>12];
        }
    } 
}  
//重设解码时间                          
void ResetDecodeTime(void)
{
	Vs1003_CMD_Write(SPI_DECODE_TIME,0x0000);
	Vs1003_CMD_Write(SPI_DECODE_TIME,0x0000);//操作两次
}
//得到mp3的播放时间n sec
u16 GetDecodeTime(void)
{ 
    return Vs1003_REG_Read(SPI_DECODE_TIME);   
} 
//加载频谱分析的代码到VS1003
void LoadPatch(void)
{
	u16 i;
	for (i=0;i<943;i++)Vs1003_CMD_Write(atab[i],dtab[i]); 
	delay_ms(10);
}
//得到频谱数据
void GetSpec(u8 *p)
{
	u8 byteIndex=0;
	u8 temp;
	Vs1003_CMD_Write(SPI_WRAMADDR,0x1804);                                                                                             
	for (byteIndex=0;byteIndex<14;byteIndex++) 
	{                                                                               
		temp=Vs1003_REG_Read(SPI_WRAM)&0x63;//取小于100的数    
		*p++=temp;
	} 
}
void SPI1_RST(void)
{
	RCC->APB2RSTR|=1<<12;//复位SPI1
	delay_ms(10); 	
	RCC->APB2RSTR&=~(1<<12);//结束复位SPI1
	delay_ms(10); 
	SPI1->CR1|=0<<10;//全双工模式	
	SPI1->CR1|=1<<9; //软件nss管理
	SPI1->CR1|=1<<8;  

	SPI1->CR1|=1<<2; //SPI主机
	SPI1->CR1|=0<<11;//8bit数据格式	
	SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
	SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1  
	SPI1->CR1|=6<<3; //Fsck=Fpclk/128 =562.5khz
	SPI1->CR1|=0<<7; //MSBfirst 
	
	SPI1->CR1|=1<<6; //SPI设备使能
}	  
//设定vs1003播放的音量和高低音 
void set1003(void)
{
    u8 t;
    u16 bass=0; //暂存音调寄存器值
    u16 volt=0; //暂存音量值
    u8 vset=0;  //暂存音量值 	 
    vset=255-vs1003ram[4];//取反一下,得到最大值,表示最大的表示 
    volt=vset;
    volt<<=8;
    volt+=vset;//得到音量设置后大小
     //0,henh.1,hfreq.2,lenh.3,lfreq        
    for(t=0;t<4;t++)
    {
        bass<<=4;
        bass+=vs1003ram[t]; 
    }     
	Vs1003_CMD_Write(SPI_BASS,bass);//BASS   
    Vs1003_CMD_Write(SPI_VOL,volt); //设音量 
}    

//初始化VS1003的IO口	 
void Vs1003_Init(void)
{
	RCC->APB2ENR|=1<<2;       //PORTA时钟使能  
	RCC->APB2ENR|=1<<12;      //SPI1时钟使能	 
	
	//存储器映射,不用理    
	#ifdef  VECT_TAB_RAM  									   
	  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
	#else   							 
	  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
	#endif  
			    
	GPIOA->CRL&=0X000FFFFF;//PA5.6.7复用输出
	GPIOA->CRL|=0XBBB00000; 	 
	GPIOA->ODR|=0X00E0;//PA5.6.7上拉  
	
	SPI1->CR1|=0<<10;//全双工模式	
	SPI1->CR1|=1<<9; //软件nss管理
	SPI1->CR1|=1<<8;  

	SPI1->CR1|=1<<2; //SPI主机
	SPI1->CR1|=0<<11;//8bit数据格式	
	SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
	SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1  
	SPI1->CR1|=6<<3; //Fsck=Fpclk/128 =562.5khz
	SPI1->CR1|=0<<7; //MSBfirst 
	
	SPI1->CR1|=1<<6; //SPI设备使能
	//以上初始化VS1003的SPI连接口,SPI1口	
	//所以上拉之前,必须使能时钟.才能实现真正的上拉输出
	RCC->APB2ENR|=1<<2;    //PA时钟使能
	RCC->APB2ENR|=1<<4;    //PC时钟使能
	RCC->APB2ENR|=1<<0;    //开启辅助时钟
	AFIO->MAPR=0X04000000;//关闭JTAG,只有关闭JTAG,才能使用PA14 

	GPIOA->CRH&=0XF0FFFFF0;//PA.8/14推挽输出
	GPIOA->CRH|=0X03000003; 
	GPIOA->ODR|=0X4100;    //上拉

	GPIOC->CRH&=0XFFFFFF00;
  	GPIOC->CRH|=0X00000083;//PC.8输出 ,PC9输入
	GPIOC->ODR|=1<<8;      //PC.8上拉   
	GPIOC->ODR|=1<<9; 	   //PC.9上拉	  

}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -