基于vs1053 的音樂播放器。可以播放MP3格式的音頻文件.
0.png (52.06 KB, 下載次數: 143)
下載附件
2017-4-4 14:53 上傳
0.png (48.44 KB, 下載次數: 124)
下載附件
2017-4-4 14:53 上傳
完整源碼下載:
1.MINI-V3_VS1053裸機例程.rar
(7.12 MB, 下載次數: 224)
2017-4-4 09:44 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
下面是VS1053 MP3播放程序的主要部分預覽(stm32單片機主控):
- #include "bsp_SysTick.h"
- #include "VS1053.h"
- #include "flac.h"
- #include "bsp_usart1.h"
- #include "string.h"
- //VS1053默認設置參數
- _vs1053_obj vsset=
- {
- 220, //音量:220
- 6, //低音上線 60Hz
- 15, //低音提升 15dB
- 10, //高音下限 10Khz
- 15, //高音提升 10.5dB
- 0, //空間效果
- };
- /*******************************************************************************
- * Function Name : SPI_FLASH_SendByte
- * Description : Sends a byte through the SPI interface and return the byte
- * received from the SPI bus.
- * Input : byte : byte to send.
- * Output : None
- * Return : The value of the received byte.
- *******************************************************************************/
- unsigned char SPI2_ReadWriteByte(unsigned char writedat)
- {
- /* Loop while DR register in not emplty */
- while(SPI_I2S_GetFlagStatus(VS_SPI,SPI_I2S_FLAG_TXE) == RESET);
-
- /* Send byte through the SPI1 peripheral */
- SPI_I2S_SendData(VS_SPI, writedat);
-
- /* Wait to receive a byte */
- while(SPI_I2S_GetFlagStatus(VS_SPI, SPI_I2S_FLAG_RXNE) == RESET);
-
- /* Return the byte read from the SPI bus */
- return SPI_I2S_ReceiveData(VS_SPI);
- }
- ////////////////////////////////////////////////////////////////////////////////
- //移植時候的接口
- //data:要寫入的數據
- //返回值:讀到的數據
- u8 VS_SPI_ReadWriteByte(u8 data)
- {
- return SPI2_ReadWriteByte(data);
- }
- static void SPI_SetSpeed(u8 SpeedSet)
- {
- assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
- SPI2->CR1&=0XFFC7;
- SPI2->CR1|=SpeedSet;
- SPI_Cmd(SPI2,ENABLE);
- }
- void VS_SPI_SpeedLow(void)
- {
- SPI_SetSpeed(SPI_BaudRatePrescaler_32);//設置到低速模式
- }
- void VS_SPI_SpeedHigh(void)
- {
- SPI_SetSpeed(SPI_BaudRatePrescaler_8);//設置到高速模式
- }
- //初始化VS1053的IO口
- void VS_Init(void)
- {
-
- SPI_InitTypeDef SPI_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(VS_SPIGPIO_CLK|VS_GPIO_DREQ_CLK|VS_GPIO_RST_CLK|VS_GPIO_XDCS_CLK, ENABLE);
-
- GPIO_InitStructure.GPIO_Pin = VS_DREQ; //DREQ
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //輸入
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(VS_GPIO_DREQ_PORT, &GPIO_InitStructure);
- GPIO_InitStructure.GPIO_Pin = VS_RST; //PB9
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
- GPIO_Init(VS_GPIO_RST_PORT, &GPIO_InitStructure);
-
- /*初始化STM32 SPI2接口*/
- RCC_APB1PeriphClockCmd(VS_SPI_CLK, ENABLE);
-
- GPIO_InitStructure.GPIO_Pin = VS_SCLK | VS_MISO | VS_MOSI;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 復用輸出
- GPIO_Init(VS_SPIGPIO_PORT, &GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = VS_XCS;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推免輸出
- GPIO_Init(VS_SPIGPIO_PORT, &GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = VS_XDCS;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推免輸出
- GPIO_Init(VS_GPIO_XDCS_PORT, &GPIO_InitStructure);
-
- /* SPI2 配置 */
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//
- SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
- SPI_Init(VS_SPI, &SPI_InitStructure);
-
- /* 使能 SPI2 */
- SPI_Cmd(VS_SPI, ENABLE);
- SPI2_ReadWriteByte(0xff);//啟動傳輸
-
- }
- ////////////////////////////////////////////////////////////////////////////////
- //軟復位VS10XX
- void VS_Soft_Reset(void)
- {
- u8 retry=0;
- while(VS_DREQ_IN==0); //等待軟件復位結束
- VS_SPI_ReadWriteByte(0Xff); //啟動傳輸
- retry=0;
- while(VS_RD_Reg(SPI_MODE)!=0x0800) // 軟件復位,新模式
- {
- VS_WR_Cmd(SPI_MODE,0x0804); // 軟件復位,新模式
- Delay_ms(2);//等待至少1.35ms
- if(retry++>100)break;
- }
- while(VS_DREQ_IN==0);//等待軟件復位結束
- retry=0;
- while(VS_RD_Reg(SPI_CLOCKF)!=0X9800)//設置VS1053的時鐘,3倍頻 ,1.5xADD
- {
- VS_WR_Cmd(SPI_CLOCKF,0X9800); //設置VS1053的時鐘,3倍頻 ,1.5xADD
- if(retry++>100)break;
- }
- Delay_ms(20);
- }
- //硬復位MP3
- //返回1:復位失敗;0:復位成功
- u8 VS_HD_Reset(void)
- {
- u8 retry=0;
- VS_RST_CLR;
- Delay_ms(20);
- VS_XDCS_SET;//取消數據傳輸
- VS_XCS_SET;//取消數據傳輸
- VS_RST_SET;
- while(VS_DREQ_IN==0&&retry<200)//等待DREQ為高
- {
- retry++;
- Delay_us(50);
- };
- Delay_ms(20);
- if(retry>=200)return 1;
- else return 0;
- }
- //正弦測試
- void VS_Sine_Test(void)
- {
- VS_HD_Reset();
- VS_WR_Cmd(0x0b,0X2020); //設置音量
- VS_WR_Cmd(SPI_MODE,0x0820);//進入VS10XX的測試模式
- while(VS_DREQ_IN==0); //等待DREQ為高
- //printf("mode sin:%x\n",VS_RD_Reg(SPI_MODE));
- //向VS1053發送正弦測試命令:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
- //其中n = 0x24, 設定VS1053所產生的正弦波的頻率值,具體計算方法見VS1053的datasheet
- VS_SPI_SpeedLow();//低速
- VS_XDCS_CLR;//選中數據傳輸
- VS_SPI_ReadWriteByte(0x53);
- VS_SPI_ReadWriteByte(0xef);
- VS_SPI_ReadWriteByte(0x6e);
- VS_SPI_ReadWriteByte(0x24);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- Delay_ms(100);
- VS_XDCS_SET;
- //退出正弦測試
- VS_XDCS_CLR;//選中數據傳輸
- VS_SPI_ReadWriteByte(0x45);
- VS_SPI_ReadWriteByte(0x78);
- VS_SPI_ReadWriteByte(0x69);
- VS_SPI_ReadWriteByte(0x74);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- Delay_ms(100);
- VS_XDCS_SET;
- // //再次進入正弦測試并設置n值為0x44,即將正弦波的頻率設置為另外的值
- // VS_XDCS_CLR;//選中數據傳輸
- // VS_SPI_ReadWriteByte(0x53);
- // VS_SPI_ReadWriteByte(0xef);
- // VS_SPI_ReadWriteByte(0x6e);
- // VS_SPI_ReadWriteByte(0x44);
- // VS_SPI_ReadWriteByte(0x00);
- // VS_SPI_ReadWriteByte(0x00);
- // VS_SPI_ReadWriteByte(0x00);
- // VS_SPI_ReadWriteByte(0x00);
- // Delay_ms(100);
- // VS_XDCS_SET;
- // //退出正弦測試
- // VS_XDCS_CLR;//選中數據傳輸
- // VS_SPI_ReadWriteByte(0x45);
- // VS_SPI_ReadWriteByte(0x78);
- // VS_SPI_ReadWriteByte(0x69);
- // VS_SPI_ReadWriteByte(0x74);
- // VS_SPI_ReadWriteByte(0x00);
- // VS_SPI_ReadWriteByte(0x00);
- // VS_SPI_ReadWriteByte(0x00);
- // VS_SPI_ReadWriteByte(0x00);
- // Delay_ms(100);
- // VS_XDCS_SET;
- }
- //ram 測試
- //返回值:RAM測試結果
- // VS1053如果得到的值為0x83FF,則表明完好;
- u16 VS_Ram_Test(void)
- {
- VS_HD_Reset();
- VS_WR_Cmd(SPI_MODE,0x0820);// 進入VS10XX的測試模式
- while (VS_DREQ_IN==0); // 等待DREQ為高
- VS_SPI_SpeedLow();//低速
- VS_XDCS_CLR; // xDCS = 1,選擇VS10XX的數據接口
- VS_SPI_ReadWriteByte(0x4d);
- VS_SPI_ReadWriteByte(0xea);
- VS_SPI_ReadWriteByte(0x6d);
- VS_SPI_ReadWriteByte(0x54);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- VS_SPI_ReadWriteByte(0x00);
- Delay_ms(150);
- VS_XDCS_SET;
- return VS_RD_Reg(SPI_HDAT0);// VS1053如果得到的值為0x83FF,則表明完好;
- }
- //向VS1053寫命令
- //address:命令地址
- //data:命令數據
- void VS_WR_Cmd(u8 address,u16 data)
- {
- while(VS_DREQ_IN==0);//等待空閑
- VS_SPI_SpeedLow();//低速
- VS_XDCS_SET;
- VS_XCS_CLR;
- VS_SPI_ReadWriteByte(VS_WRITE_COMMAND);//發送VS10XX的寫命令
- VS_SPI_ReadWriteByte(address); //地址
- VS_SPI_ReadWriteByte(data>>8); //發送高八位
- VS_SPI_ReadWriteByte(data); //第八位
- VS_XCS_SET;
- VS_SPI_SpeedHigh(); //高速
- }
- //向VS10XX寫數據
- //data:要寫入的數據
- void VS_WR_Data(u8 data)
- {
- VS_SPI_SpeedHigh();//高速,對VS1003B,最大值不能超過36.864/4Mhz,這里設置為9M
- VS_XDCS_CLR;
- VS_SPI_ReadWriteByte(data);
- VS_XDCS_SET;
- }
- //讀VS10XX的寄存器
- //address:寄存器地址
- //返回值:讀到的值
- //注意不要用倍速讀取,會出錯
- u16 VS_RD_Reg(u8 address)
- {
- u16 temp=0;
- while(VS_DREQ_IN==0);//非等待空閑狀態
- VS_SPI_SpeedLow();//低速
- VS_XDCS_SET;
- VS_XCS_CLR;
- VS_SPI_ReadWriteByte(VS_READ_COMMAND); //發送VS10XX的讀命令
- VS_SPI_ReadWriteByte(address); //地址
- temp=VS_SPI_ReadWriteByte(0xff); //讀取高字節
- temp=temp<<8;
- temp+=VS_SPI_ReadWriteByte(0xff); //讀取低字節
- VS_XCS_SET;
- VS_SPI_SpeedHigh();//高速
- return temp;
- }
- //讀取VS10xx的RAM
- //addr:RAM地址
- //返回值:讀到的值
- u16 VS_WRAM_Read(u16 addr)
- {
- u16 res;
- VS_WR_Cmd(SPI_WRAMADDR, addr);
- res=VS_RD_Reg(SPI_WRAM);
- return res;
- }
- //寫VS10xx的RAM
- //addr:RAM地址
- //val:要寫入的值
- void VS_WRAM_Write(u16 addr,u16 val)
- {
- VS_WR_Cmd(SPI_WRAMADDR,addr); //寫RAM地址
- while(VS_DREQ_IN==0); //等待空閑
- VS_WR_Cmd(SPI_WRAM,val); //寫RAM值
- }
- //設置播放速度(僅VS1053有效)
- //t:0,1,正常速度;2,2倍速度;3,3倍速度;4,4倍速;以此類推
- void VS_Set_Speed(u8 t)
- {
- VS_WRAM_Write(0X1E04,t); //寫入播放速度
- }
- //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
- //比特率預定值,階層III
- 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的大小
- //返回值:得到的碼率
- u16 VS_Get_HeadInfo(void)
- {
- unsigned int HEAD0;
- unsigned int HEAD1;
- HEAD0=VS_RD_Reg(SPI_HDAT0);
- HEAD1=VS_RD_Reg(SPI_HDAT1);
- //printf("(H0,H1):%x,%x\n",HEAD0,HEAD1);
- switch(HEAD1)
- {
- case 0x7665://WAV格式
- case 0X4D54://MIDI格式
- case 0X4154://AAC_ADTS
- case 0X4144://AAC_ADIF
- case 0X4D34://AAC_MP4/M4A
- case 0X4F67://OGG
- case 0X574D://WMA格式
- case 0X664C://FLAC格式
- {
- //printf("HEAD0:%d\n",HEAD0);
- HEAD1=HEAD0*2/25;//相當于*8/100
- if((HEAD1%10)>5)return HEAD1/10+1;//對小數點第一位四舍五入
- else return HEAD1/10;
- }
- default://MP3格式,僅做了階層III的表
- {
- HEAD1>>=3;
- HEAD1=HEAD1&0x03;
- if(HEAD1==3)HEAD1=1;
- else HEAD1=0;
- return bitrate[HEAD1][HEAD0>>12];
- }
- }
- }
- //得到平均字節數
- //返回值:平均字節數速度
- u32 VS_Get_ByteRate(void)
- {
- return VS_WRAM_Read(0X1E05);//平均位速
- }
- //得到需要填充的數字
- //返回值:需要填充的數字
- u16 VS_Get_EndFillByte(void)
- {
- return VS_WRAM_Read(0X1E06);//填充字節
- }
- //發送一次音頻數據
- //固定為32字節
- //返回值:0,發送成功
- // 1,VS10xx不缺數據,本次數據未成功發送
- u8 VS_Send_MusicData(u8* buf)
- {
- u8 n;
- if(VS_DREQ_IN!=0) //送數據給VS10XX
- {
- VS_XDCS_CLR;
- for(n=0;n<32;n++)
- {
- VS_SPI_ReadWriteByte(buf[n]);
- }
- VS_XDCS_SET;
- }else return 1;
- return 0;//成功發送了
- }
- //切歌
- //通過此函數切歌,不會出現切換“噪聲”
- void VS_Restart_Play(void)
- {
- u16 temp;
- u16 i;
- u8 n;
- u8 vsbuf[32];
- for(n=0;n<32;n++)vsbuf[n]=0;//清零
- temp=VS_RD_Reg(SPI_MODE); //讀取SPI_MODE的內容
- temp|=1<<3; //設置SM_CANCEL位
- temp|=1<<2; //設置SM_LAYER12位,允許播放MP1,MP2
- VS_WR_Cmd(SPI_MODE,temp); //設置取消當前解碼指令
- for(i=0;i<2048;) //發送2048個0,期間讀取SM_CANCEL位.如果為0,則表示已經取消了當前解碼
- {
- if(VS_Send_MusicData(vsbuf)==0)//每發送32個字節后檢測一次
- {
- i+=32; //發送了32個字節
- temp=VS_RD_Reg(SPI_MODE); //讀取SPI_MODE的內容
- if((temp&(1<<3))==0)break; //成功取消了
- }
- }
- if(i<2048)//SM_CANCEL正常
- {
- temp=VS_Get_EndFillByte()&0xff;//讀取填充字節
- for(n=0;n<32;n++)vsbuf[n]=temp;//填充字節放入數組
- for(i=0;i<2052;)
- {
- if(VS_Send_MusicData(vsbuf)==0)i+=32;//填充
- }
- }else VS_Soft_Reset(); //SM_CANCEL不成功,壞情況,需要軟復位
- temp=VS_RD_Reg(SPI_HDAT0);
- temp+=VS_RD_Reg(SPI_HDAT1);
- if(temp) //軟復位,還是沒有成功取消,放殺手锏,硬復位
- {
- VS_HD_Reset(); //硬復位
- VS_Soft_Reset(); //軟復位
- }
- }
- //重設解碼時間
- void VS_Reset_DecodeTime(void)
- {
- VS_WR_Cmd(SPI_DECODE_TIME,0x0000);
- VS_WR_Cmd(SPI_DECODE_TIME,0x0000);//操作兩次
- }
- //得到mp3的播放時間n sec
- //返回值:解碼時長
- u16 VS_Get_DecodeTime(void)
- {
- u16 dt=0;
- dt=VS_RD_Reg(SPI_DECODE_TIME);
- return dt;
- }
- //vs10xx裝載patch.
- //patch:patch首地址
- //len:patch長度
- void VS_Load_Patch(u16 *patch,u16 len)
- {
- u16 i;
- u16 addr, n, val;
- for(i=0;i<len;)
- {
- addr = patch[i++];
- n = patch[i++];
- if(n & 0x8000U) //RLE run, replicate n samples
- {
- n &= 0x7FFF;
- val = patch[i++];
- while(n--)VS_WR_Cmd(addr, val);
- }else //copy run, copy n sample
- {
- while(n--)
- {
- val = patch[i++];
- VS_WR_Cmd(addr, val);
- }
- }
- }
- }
- //設定VS10XX播放的音量和高低音
- //volx:音量大小(0~254)
- void VS_Set_Vol(u8 volx)
- {
- u16 volt=0; //暫存音量值
- volt=254-volx; //取反一下,得到最大值,表示最大的表示
- volt<<=8;
- volt+=254-volx; //得到音量設置后大小
- VS_WR_Cmd(SPI_VOL,volt);//設音量
- }
- //設定高低音控制
- //bfreq:低頻上限頻率 2~15(單位:10Hz)
- //bass:低頻增益 0~15(單位:1dB)
- //tfreq:高頻下限頻率 1~15(單位:Khz)
- //treble:高頻增益 0~15(單位:1.5dB,小于9的時候為負數)
- void VS_Set_Bass(u8 bfreq,u8 bass,u8 tfreq,u8 treble)
- {
- u16 bass_set=0; //暫存音調寄存器值
- signed char temp=0;
- if(treble==0)temp=0; //變換
- else if(treble>8)temp=treble-8;
- else temp=treble-9;
- bass_set=temp&0X0F; //高音設定
- bass_set<<=4;
- bass_set+=tfreq&0xf; //高音下限頻率
- bass_set<<=4;
- bass_set+=bass&0xf; //低音設定
- bass_set<<=4;
- bass_set+=bfreq&0xf; //低音上限
- VS_WR_Cmd(SPI_BASS,bass_set); //BASS
- }
- //設定音效
- //eft:0,關閉;1,最小;2,中等;3,最大.
- void VS_Set_Effect(u8 eft)
- {
- u16 temp;
- temp=VS_RD_Reg(SPI_MODE); //讀取SPI_MODE的內容
- if(eft&0X01)temp|=1<<4; //設定LO
- else temp&=~(1<<5); //取消LO
- if(eft&0X02)temp|=1<<7; //設定HO
- else temp&=~(1<<7); //取消HO
- VS_WR_Cmd(SPI_MODE,temp); //設定模式
- }
- ///////////////////////////////////////////////////////////////////////////////
- //設置音量,音效等.
- void VS_Set_All(void)
- {
- VS_Set_Vol(vsset.mvol); //設置音量
- VS_Set_Bass(vsset.bflimit,vsset.bass,vsset.tflimit,vsset.treble);
- VS_Set_Effect(vsset.effect); //設置空間效果
- }
- /*-------------- 以上是VS1053驅動部分 -------------------------*/
- /*-------------- 下面開始是音樂播放部分 -------------------------*/
- #include "ff.h"
- #include "bsp_led.h"
- /*
- ************************************************************************
- * FatFs
- ************************************************************************
- */
- FRESULT result;
- FIL file;
- UINT bw;
- static uint8_t buffer[BUFSIZE];
- //播放歌曲
- void vs1053_player_song(uint8_t *filepath)
- {
- uint16_t i=0;
-
- VS_Restart_Play();
- VS_Set_All();
- VS_Reset_DecodeTime();
-
- if(strstr((const char*)filepath,".flac")||strstr((const char*)filepath,".FLAC"))//檢索字符
- VS_Load_Patch((u16*)vs1053b_patch,VS1053B_PATCHLEN);
-
- result=f_open(&file,(const TCHAR*)filepath,FA_READ);
- if(result==0)
- {
- VS_SPI_SpeedHigh();
- while(1)
- {
- i=0;
- result=f_read(&file,buffer,BUFSIZE,(UINT*)&bw);
- do
- {
- if(VS_Send_MusicData(buffer+i)==0)
- {
- i+=32;
- }
- }while(i<bw);
-
- if(bw!=BUFSIZE||result!=0)
- {
- break;
- }
- LED2_TOGGLE;
- }
- f_close(&file);
- }
- }
- /*-------------- END OF FILE -----------------------*/
復制代碼
|