久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 7558|回復(fù): 8
打印 上一主題 下一主題
收起左側(cè)

基于STM32+VS1053B的MP3設(shè)計(jì)與制作 附源程序

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
stm32_MP3學(xué)習(xí)筆記
一、整體介紹
話不多說,先看看整體原理圖:


制作出來的實(shí)物圖如下:



整體上,其實(shí)也就四個(gè)部分:
(1)    STM32主控部分;
(2)    VS1053B音頻解碼部分;
(3)    按鍵控制部分;
(4)    OLED顯示部分;
上電,通過一系列的測試和檢測后,進(jìn)入音樂播放界面,如圖:
第一排顯示的是我的標(biāo)簽,
第二行,顯示的是當(dāng)前播放歌曲的索引、總歌曲數(shù)目以及當(dāng)前聲音大小,
第三行,顯示的是當(dāng)前歌曲的播放進(jìn)度以及位率,
第四行,顯示的是當(dāng)前歌曲名(因?yàn)闆]有取字庫,所以我就把他翻譯成了英文,肯定是不準(zhǔn)確的,主要目的只是提示自己)。
此外,通過按鍵,可以對(duì)播放歌曲進(jìn)行切換和音量的控制。
下面我們來分別看看這四個(gè)部分:
二、模塊介紹
1.     stm32主控
這里我們使用的是stm32F103VET6,內(nèi)部Flash有512K,100pin的外部引腳,屬于大容量芯片,足夠我們diy。對(duì)于本設(shè)計(jì),stm32這一塊用到的知識(shí)點(diǎn)有:SDIO驅(qū)動(dòng)SD卡,SPI驅(qū)動(dòng)VS1053B芯片,IIC驅(qū)動(dòng)OLED;對(duì)于程序,用的是stm32標(biāo)準(zhǔn)庫,小伙伴們可以根據(jù)自己的需要,自行決定是否需要補(bǔ)一下相關(guān)方面的知識(shí)。
主控就不再多做介紹了,因?yàn)樘R娏耍@里只是提一下。
2.     VS1053B音頻解碼
這一部分的原理圖如圖:

VS1053B,是一款功能比較強(qiáng)大的音頻解碼芯片,該芯片可以實(shí)現(xiàn)對(duì)MP3/OGG/WMA/FLAC/WAV/AAC/MIDI等音頻格式的解碼,同時(shí)還可以支持ADPCM/OGG等格式的編碼,經(jīng)過我的測試,建議大家用最常用的.MP3 格式的音樂文件;
具體的介紹,請(qǐng)看資料里面的資料手冊(cè),那里說的很清楚,我再多說,顯得就很尷尬了。
3.     按鍵
這個(gè)常見到不能再常見了,因?yàn)樾枰存I對(duì)歌曲進(jìn)行切換和音量大小的控制,所以,這里只是簡單的把他列出來而已。
4.     OLED顯示
OLED只是用來顯示提示的作用,這里我們用的是0.96寸4pin的IIC驅(qū)動(dòng)的OLED,也是非常常見的玩意兒,不清楚使用的,可以看看相關(guān)的資料。
三、程序代碼:
main.c文件:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"                       
#include "oled.h"
#include "bmp.h"
#include "key.h"      
#include "malloc.h"
#include "sdio_sdcard.h"  
#include "vs10xx.h"
#include "mp3player.h"
#include "exfuns.h"
//通過串口打印SD卡相關(guān)信息
void show_sdcard_info(void)
{
         switch(SDCardInfo.CardType)
         {
                  caseSDIO_STD_CAPACITY_SD_CARD_V1_1:printf("Card Type:SDSCV1.1\r\n");break;
                  caseSDIO_STD_CAPACITY_SD_CARD_V2_0:printf("Card Type:SDSCV2.0\r\n");break;
                  caseSDIO_HIGH_CAPACITY_SD_CARD:printf("Card Type:SDHC V2.0\r\n");break;
                  caseSDIO_MULTIMEDIA_CARD:printf("Card Type:MMC Card\r\n");break;
         }      
      printf("Card ManufacturerID:%d\r\n",SDCardInfo.SD_cid.ManufacturerID);    //制造商ID
        printf("CardRCA:%d\r\n",SDCardInfo.RCA);                 //卡相對(duì)地址
         printf("CardCapacity:%d MB\r\n",(u32)(SDCardInfo.CardCapacity>>20));        //顯示容量
        printf("CardBlockSize:%d\r\n\r\n",SDCardInfo.CardBlockSize);                          //顯示塊大小
}
intmain(void)
{      
         delay_init();                   //延時(shí)函數(shù)初始化         
         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設(shè)置中斷優(yōu)先級(jí)分組為組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí)
         uart_init(115200);          //串口初始化為115200
        LED_Init();                               //初始化與LED連接的硬件接口
         KEY_Init();                                  //初始化按鍵
         VS_Init();                         //初始化VS1053
         delay_ms(1000);   //適當(dāng)延時(shí)
         OLED_Init();   //OLED初始化
         OLED_ColorTurn(0);//0正常顯示,1 反色顯示
         OLED_DisplayTurn(0);//0正常顯示 1 屏幕翻轉(zhuǎn)顯示
         OLED_Refresh();  
         delay_ms(1000);   //適當(dāng)延時(shí)
         my_mem_init(SRAMIN);                  //初始化內(nèi)部內(nèi)存池
         exfuns_init();                             //為fatfs相關(guān)變量申請(qǐng)內(nèi)存  
        f_mount(fs[0],"0:",1);            //掛載SD卡
        f_mount(fs[1],"1:",1);            //掛載FLASH.
        while(SD_Init())//檢測不到SD卡
         {
                  OLED_ShowString(0,0,"SD_ERROR!!",16);    //錯(cuò)誤提示信息閃爍
                  delay_ms(200);
                  OLED_ShowString(0,0,"          ",16);
                  delay_ms(200);
                  LED1=!LED1;//DS1閃爍
         }
         show_sdcard_info();       //打印SD卡相關(guān)信息
         //檢測SD卡成功
         OLED_ShowString(0,0,"SD_OK      ",16);         
         delay_ms(1000);
         OLED_ShowString(0,0,"LHSMD- MP3",16);
         while(1)
         {
                  LED1=0;
                  OLED_ShowString(0,16,"storagetest",16);
                  printf("RamTest:0X%04X\r\n",VS_Ram_Test());//打印RAM測試結(jié)果
                  OLED_ShowString(0,16,"sintest    ",16);
                  VS_Sine_Test();   //正弦波測試
                  delay_ms(1000);
                  LED1=1;
                  OLED_Clear();
                  OLED_ShowString(0,0,"  LHSMD - MP3",16);
                  mp3_play();  //放歌操作
         }   
}
mp3player.c文件:
#include "mp3player.h"
#include "vs10xx.h"         
#include "delay.h"
#include "led.h"
#include "key.h"
//#include "lcd.h"            
#include "malloc.h"
//#include "text.h"
#include "string.h"
#include "exfuns.h"  
#include "ff.h"   
#include "flac.h"     
#include "usart.h"   
#include "oled.h"
//顯示曲目索引
//index:當(dāng)前索引
//total:總文件數(shù)
void mp3_index_show(u16 index,u16 total)
{
         //顯示當(dāng)前曲目的索引,及總曲目數(shù)
         OLED_ShowNum(0,16,index,3,16);
         OLED_ShowString(24,16,"/",16);  
         OLED_ShowNum(32,16,total,3,16);
}
//顯示當(dāng)前音量
void mp3_vol_show(u8 vol)
{                                      
         OLED_ShowString(64,16,"VOL:",16);   
         OLED_ShowNum(105,16,vol,2,16);       //顯示音量
}
u8 time_buf[16];
u16 f_kbps=0;//歌曲文件位率     
//顯示播放時(shí)間,比特率 信息
//lenth:歌曲總長度
void mp3_msg_show(u32 lenth)
{      
         staticu16 playtime=0;//播放時(shí)間標(biāo)記            
        u16 time=0;// 時(shí)間變量
         u16sec=0;// 時(shí)間變量
         u16temp=0;   
         if(f_kbps==0xffff)//未更新過
         {
                  playtime=0;
                  f_kbps=VS_Get_HeadInfo();     //獲得比特率
         }               
         time=VS_Get_DecodeTime();//得到解碼時(shí)間
         if(playtime==0)playtime=time;
         elseif((time!=playtime)&&(time!=0))//1s時(shí)間到,更新顯示數(shù)據(jù)
         {
                  playtime=time;//更新時(shí)間                                       
                  temp=VS_Get_HeadInfo();//獲得比特率                                    
                  if(temp!=f_kbps)
                  {
                          f_kbps=temp;//更新KBPS                                          
                  }                          
                  if(f_kbps)sec=(lenth/f_kbps)/125;//得到秒鐘數(shù)(文件長度(字節(jié))/(1000/8)/比特率=持續(xù)秒鐘數(shù)
                  elsesec=0;//非法位率                  
                  //顯示播放時(shí)間     
                  sprintf((char*)time_buf,"%02d:%02d/%02d:%02d%003d",time/60,time%60,sec/60,sec%60,f_kbps);
                  OLED_ShowString(0,32,time_buf,16);
                  LED1=!LED1;            //DS0翻轉(zhuǎn)
         }            
}                                         
//得到path路徑下,目標(biāo)文件的總個(gè)數(shù)
//path:路徑               
//返回值:總有效文件數(shù)
u16 mp3_get_tnum(u8 *path)
{         
         u8res;
         u16rval=0;
        DIR tdir;                  //臨時(shí)目錄
         FILINFOtfileinfo;    //臨時(shí)文件信息            
         u8*fn;                                                                          
   res=f_opendir(&tdir,(const TCHAR*)path); //打開目錄
      tfileinfo.lfsize=_MAX_LFN*2+1;                                                //長文件名最大長度
         tfileinfo.lfname=mymalloc(SRAMIN,tfileinfo.lfsize);   //為長文件緩存區(qū)分配內(nèi)存
         if(res==FR_OK&&tfileinfo.lfname!=NULL)
         {
                  while(1)//查詢總的有效文件數(shù)
                  {
                res=f_readdir(&tdir,&tfileinfo);                       //讀取目錄下的一個(gè)文件
                if(res!=FR_OK||tfileinfo.fname[0]==0)break;      //錯(cuò)誤了/到末尾了,退出               
                    fn=(u8*)(*tfileinfo.lfname?tfileinfo.lfname:tfileinfo.fname);                       
                          res=f_typetell(fn);  
                          if((res&0XF0)==0X40)//取高四位,看看是不是音樂文件   
                          {
                                   rval++;//有效文件數(shù)增加1
                          }         
                  }  
         }
         myfree(SRAMIN,tfileinfo.lfname);
         returnrval;
}
//播放音樂
void mp3_play(void)
{
         u8res;
        DIR mp3dir;                     //目錄
         FILINFOmp3fileinfo;//文件信息
         u8*fn;                           //長文件名
         u8*pname;                      //帶路徑的文件名
         u16totmp3num;            //音樂文件總數(shù)
         u16curindex;           //圖片當(dāng)前索引
         u8key;                               //鍵值               
        u16 temp;
         u16*mp3indextbl; //音樂索引表
        while(f_opendir(&mp3dir,"0:/music"))//打開圖片文件夾
        {           
                  OLED_ShowString(0,32,"musicfile ERR!",16);            
delay_ms(200);      
                  OLED_ShowString(0,32,"               ",16);
                  delay_ms(200);               
         }                                                                             
         totmp3num=mp3_get_tnum("0:/music");//得到總有效文件數(shù)
      while(totmp3num==NULL)//音樂文件總數(shù)為0         
        {           
                  OLED_ShowString(0,32,"nomusic file  ",16); //沒有音樂文件提示
                  delay_ms(200);                                                            
         }                                                                                         
      mp3fileinfo.lfsize=_MAX_LFN*2+1;                                                  //長文件名最大長度
         mp3fileinfo.lfname=mymalloc(SRAMIN,mp3fileinfo.lfsize);       //為長文件緩存區(qū)分配內(nèi)存
        pname=mymalloc(SRAMIN,mp3fileinfo.lfsize);    //為帶路徑的文件名分配內(nèi)存
        mp3indextbl=mymalloc(SRAMIN,2*totmp3num);        //申請(qǐng)2*totmp3num個(gè)字節(jié)的內(nèi)存,用于存放音樂文件索引
        while(mp3fileinfo.lfname==NULL||pname==NULL||mp3indextbl==NULL)//內(nèi)存分配出錯(cuò)
        {           
                  OLED_ShowString(0,32,"storageERR    ",16);
                  delay_ms(200);                                                   
         }     
         VS_HD_Reset();    //VS1053硬復(fù)位
         VS_Soft_Reset();  //VS1053軟復(fù)位
         vsset.mvol=200;                                                 //默認(rèn)設(shè)置音量為200.
         mp3_vol_show((vsset.mvol-100)/5);    //音量限制在:100~250,顯示的時(shí)候,按照公式(vol-100)/5,顯示,也就是0~30   
         //記錄索引
   res=f_opendir(&mp3dir,"0:/music"); //打開目錄
         if(res==FR_OK)
         {
                  curindex=0;//當(dāng)前索引為0
                  while(1)//全部查詢一遍
                  {
                          temp=mp3dir.index;                                                                     //記錄當(dāng)前index
                res=f_readdir(&mp3dir,&mp3fileinfo);                  //讀取目錄下的一個(gè)文件
                if(res!=FR_OK||mp3fileinfo.fname[0]==0)break;        //錯(cuò)誤了/到末尾了,退出               
                    fn=(u8*)(*mp3fileinfo.lfname?mp3fileinfo.lfname:mp3fileinfo.fname);                     
                          res=f_typetell(fn);  
                          if((res&0XF0)==0X40)//取高四位,看看是不是音樂文件   
                          {
                                   mp3indextbl[curindex]=temp;//記錄索引
                                   curindex++;
                          }         
                  }
         }   
     curindex=0;                                                                                             //從0開始顯示
     res=f_opendir(&mp3dir,(constTCHAR*)"0:/music");  //打開目錄
         while(res==FR_OK)//打開成功
         {      
                  dir_sdi(&mp3dir,mp3indextbl[curindex]);                       //改變當(dāng)前目錄索引      
       res=f_readdir(&mp3dir,&mp3fileinfo);                  //讀取目錄下的一個(gè)文件
       if(res!=FR_OK||mp3fileinfo.fname[0]==0)break;        //錯(cuò)誤了/到末尾了,退出
           fn=(u8*)(*mp3fileinfo.lfname?mp3fileinfo.lfname:mp3fileinfo.fname);                     
                  strcpy((char*)pname,"0:/music/");                                  //復(fù)制路徑(目錄)
                  strcat((char*)pname,(constchar*)fn);                          //將文件名接在后面
                OLED_ShowString(0,48,"                ",16);     //清楚之前的顯示
                  OLED_ShowString(0,48,fn,16);                                //顯示歌曲名字
                  mp3_index_show(curindex+1,totmp3num);
                  key=mp3_play_song(pname);                                                //播放這個(gè)MP3   
                  if(key==2)                 //上一曲
                  {
                          if(curindex)curindex--;
                          elsecurindex=totmp3num-1;
                }else if(key<=1)//下一曲
                  {
                          curindex++;                  
                          if(curindex>=totmp3num)curindex=0;//到末尾的時(shí)候,自動(dòng)從頭開始
                }else break;     //產(chǎn)生了錯(cuò)誤         
         }                                                                                               
         myfree(SRAMIN,mp3fileinfo.lfname);  //釋放內(nèi)存                          
         myfree(SRAMIN,pname);                                 //釋放內(nèi)存                          
         myfree(SRAMIN,mp3indextbl);                       //釋放內(nèi)存      
}
//播放一曲指定的歌曲                                                                                                                                       
//返回值:0,正常播放完成
//              1,下一曲
//      2,上一曲
//      0XFF,出現(xiàn)錯(cuò)誤了
u8 mp3_play_song(u8 *pname)
{      
        FIL* fmp3;
   u16 br;
         u8res,rval;        
         u8*databuf;                    
         u16i=0;
         u8key;               
                             
         rval=0;         
         fmp3=(FIL*)mymalloc(SRAMIN,sizeof(FIL));//申請(qǐng)內(nèi)存
         databuf=(u8*)mymalloc(SRAMIN,4096);               //開辟4096字節(jié)的內(nèi)存區(qū)域
         if(databuf==NULL||fmp3==NULL)rval=0XFF;//內(nèi)存申請(qǐng)失敗.
         if(rval==0)
         {         
               VS_Restart_Play();                                           //重啟播放
                  VS_Set_All();                                              //設(shè)置音量等信息                          
                  VS_Reset_DecodeTime();                                          //復(fù)位解碼時(shí)間     
                  res=f_typetell(pname);                                   //得到文件后綴                                                                                       
                  if(res==0x4c)//如果是flac,加載patch
                  {      
                          VS_Load_Patch((u16*)vs1053b_patch,VS1053B_PATCHLEN);
                  }                                                                                                                  
                  res=f_open(fmp3,(constTCHAR*)pname,FA_READ);//打開文件        
                if(res==0)//打開成功.
                  {
                          VS_SPI_SpeedHigh();      //高速                                                   
                          while(rval==0)
                          {
                                   res=f_read(fmp3,databuf,4096,(UINT*)&br);//讀出4096個(gè)字節(jié)  
                                   i=0;
                                   do//主播放循環(huán)
                              {     
                                            if(VS_Send_MusicData(databuf+i)==0)//給VS10XX發(fā)送音頻數(shù)據(jù)
                                            {
                                                     i+=32;
                                            }else   
                                            {
                                                     key=KEY_Scan(0);
                                                     switch(key)
                                                     {
                                                             caseKEY1_PRES:
                                                                      rval=1;              //下一曲
                                                                      break;
                                                             caseKEY3_PRES:
                                                                      rval=2;              //上一曲
                                                                      break;
                                                             caseKEY2_PRES:    //音量增加
                                                                      if(vsset.mvol<250)
                                                                      {
                                                                               vsset.mvol+=5;
                                                                              VS_Set_Vol(vsset.mvol);         
                                                                      }elsevsset.mvol=250;
                                                                      mp3_vol_show((vsset.mvol-100)/5);//音量限制在:100~250,顯示的時(shí)候,按照公式(vol-100)/5,顯示,也就是0~30   
                                                                      break;
                                                             caseKEY4_PRES:    //音量減
                                                                      if(vsset.mvol>100)
                                                                      {
                                                                               vsset.mvol-=5;
                                                                              VS_Set_Vol(vsset.mvol);         
                                                                       }else vsset.mvol=100;
                                                                      mp3_vol_show((vsset.mvol-100)/5);    //音量限制在:100~250,顯示的時(shí)候,按照公式(vol-100)/5,顯示,也就是0~30   
                                                                      break;
                                                     }
                                                     mp3_msg_show(fmp3->fsize);//顯示信息      
                                            }                       
                                   }while(i<4096);//循環(huán)發(fā)送4096個(gè)字節(jié)
                                   if(br!=4096||res!=0)
                                   {
                                            rval=0;
                                            break;//讀完了.               
                                   }                                                           
                          }
                          f_close(fmp3);
                  }elserval=0XFF;//出現(xiàn)錯(cuò)誤         
         }                                                               
         myfree(SRAMIN,databuf);                                    
         myfree(SRAMIN,fmp3);
         returnrval;                                      
}

全部程序51hei下載地址:
STM32_MP3.7z (1.32 MB, 下載次數(shù): 211)

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏13 分享淘帖 頂2 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:379551 發(fā)表于 2020-5-23 21:09 | 只看該作者

實(shí)物圖如下:

回復(fù)

使用道具 舉報(bào)

板凳
ID:379551 發(fā)表于 2020-5-23 23:04 | 只看該作者
有需要實(shí)物的,可以聯(lián)系我,QQ:3012772245
回復(fù)

使用道具 舉報(bào)

地板
ID:691028 發(fā)表于 2020-11-3 09:23 | 只看該作者
感謝樓主的例子!一直想用這顆芯片都沒用上,希望盡快能上手。
回復(fù)

使用道具 舉報(bào)

5#
ID:664301 發(fā)表于 2022-12-25 21:47 | 只看該作者
為什么我測試可以讀卡讀不到文件夾    sd卡也創(chuàng)建了music文件夾和音樂文件
回復(fù)

使用道具 舉報(bào)

6#
ID:1089862 發(fā)表于 2023-7-31 21:21 | 只看該作者
有用,感謝樓主!
回復(fù)

使用道具 舉報(bào)

7#
ID:1102634 發(fā)表于 2023-12-5 09:08 | 只看該作者
VS1053B現(xiàn)在停產(chǎn)沒?
回復(fù)

使用道具 舉報(bào)

8#
ID:1073903 發(fā)表于 2024-3-24 20:07 | 只看該作者
求仿真文件
回復(fù)

使用道具 舉報(bào)

9#
ID:1073903 發(fā)表于 2024-3-26 00:16 | 只看該作者
求仿真文件,原理圖,實(shí)物有圖嗎?
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 亚洲高清视频在线观看 | 久久精品亚洲国产奇米99 | 伊人二区 | 一区二区三区亚洲 | 国产高清一区二区三区 | 久久精品国产一区二区电影 | 亚洲成人观看 | 久久99国产精品 | 成人一区二区视频 | 国产亚洲一区二区三区在线观看 | 国产精品成人在线播放 | 精品国产欧美一区二区三区成人 | 成人av电影免费在线观看 | 久久久www成人免费精品 | 日韩一区精品 | 久久网站黄 | 精品国产一区二区三区日日嗨 | 欧美日韩国产在线观看 | 久久福利网站 | 爱爱小视频 | 久久久精品视频免费 | 亚洲一区三区在线观看 | 国产91久久精品一区二区 | 麻豆久久久久久久 | 99日韩 | 亚洲精品一二三 | 国产精品美女久久久久aⅴ国产馆 | 中文字字幕一区二区三区四区五区 | 一级a爱片久久毛片 | 国产精品久久久久久久久久久新郎 | 九九久久国产 | www四虎com| 欧美一二区 | 三区在线| 一区二区三区四区在线视频 | 美女在线国产 | 国产乱人伦 | 影音先锋欧美资源 | 久久精品视频9 | 亚洲黄色av网站 | 欧美亚洲国产一区 |