標(biāo)題: 基于STM32+VS1053B的MP3設(shè)計與制作 附源程序 [打印本頁]
作者: 廖恒 時間: 2020-5-23 21:06
標(biāo)題: 基于STM32+VS1053B的MP3設(shè)計與制作 附源程序
stm32_MP3學(xué)習(xí)筆記
一、整體介紹
話不多說,先看看整體原理圖:
原理圖.png (352.87 KB, 下載次數(shù): 127)
下載附件
2020-5-23 21:05 上傳
制作出來的實物圖如下:
IMG_20200518_155134_BURST028.jpg (1.89 MB, 下載次數(shù): 89)
下載附件
2020-5-23 21:10 上傳
整體上,其實也就四個部分:
(1) STM32主控部分;
(2) VS1053B音頻解碼部分;
(3) 按鍵控制部分;
(4) OLED顯示部分;
上電,通過一系列的測試和檢測后,進(jìn)入音樂播放界面,如圖:
第一排顯示的是我的標(biāo)簽,
第二行,顯示的是當(dāng)前播放歌曲的索引、總歌曲數(shù)目以及當(dāng)前聲音大小,
第三行,顯示的是當(dāng)前歌曲的播放進(jìn)度以及位率,
第四行,顯示的是當(dāng)前歌曲名(因為沒有取字庫,所以我就把他翻譯成了英文,肯定是不準(zhǔn)確的,主要目的只是提示自己)。
此外,通過按鍵,可以對播放歌曲進(jìn)行切換和音量的控制。
下面我們來分別看看這四個部分:
二、模塊介紹
1. stm32主控
這里我們使用的是stm32F103VET6,內(nèi)部Flash有512K,100pin的外部引腳,屬于大容量芯片,足夠我們diy。對于本設(shè)計,stm32這一塊用到的知識點有:SDIO驅(qū)動SD卡,SPI驅(qū)動VS1053B芯片,IIC驅(qū)動OLED;對于程序,用的是stm32標(biāo)準(zhǔn)庫,小伙伴們可以根據(jù)自己的需要,自行決定是否需要補一下相關(guān)方面的知識。
主控就不再多做介紹了,因為太常見了,這里只是提一下。
2. VS1053B音頻解碼
這一部分的原理圖如圖:
下載.png (173.59 KB, 下載次數(shù): 94)
下載附件
2020-5-23 21:05 上傳
VS1053B,是一款功能比較強大的音頻解碼芯片,該芯片可以實現(xiàn)對MP3/OGG/WMA/FLAC/WAV/AAC/MIDI等音頻格式的解碼,同時還可以支持ADPCM/OGG等格式的編碼,經(jīng)過我的測試,建議大家用最常用的.MP3 格式的音樂文件;
具體的介紹,請看資料里面的資料手冊,那里說的很清楚,我再多說,顯得就很尷尬了。
3. 按鍵
這個常見到不能再常見了,因為需要按鍵對歌曲進(jìn)行切換和音量大小的控制,所以,這里只是簡單的把他列出來而已。
4. OLED顯示
OLED只是用來顯示提示的作用,這里我們用的是0.96寸4pin的IIC驅(qū)動的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); //卡相對地址
printf("CardCapacity:%d MB\r\n",(u32)(SDCardInfo.CardCapacity>>20)); //顯示容量
printf("CardBlockSize:%d\r\n\r\n",SDCardInfo.CardBlockSize); //顯示塊大小
}
intmain(void)
{
delay_init(); //延時函數(shù)初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設(shè)置中斷優(yōu)先級分組為組2:2位搶占優(yōu)先級,2位響應(yīng)優(yōu)先級
uart_init(115200); //串口初始化為115200
LED_Init(); //初始化與LED連接的硬件接口
KEY_Init(); //初始化按鍵
VS_Init(); //初始化VS1053
delay_ms(1000); //適當(dāng)延時
OLED_Init(); //OLED初始化
OLED_ColorTurn(0);//0正常顯示,1 反色顯示
OLED_DisplayTurn(0);//0正常顯示 1 屏幕翻轉(zhuǎn)顯示
OLED_Refresh();
delay_ms(1000); //適當(dāng)延時
my_mem_init(SRAMIN); //初始化內(nèi)部內(nèi)存池
exfuns_init(); //為fatfs相關(guān)變量申請內(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); //錯誤提示信息閃爍
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;//歌曲文件位率
//顯示播放時間,比特率 信息
//lenth:歌曲總長度
void mp3_msg_show(u32 lenth)
{
staticu16 playtime=0;//播放時間標(biāo)記
u16 time=0;// 時間變量
u16sec=0;// 時間變量
u16temp=0;
if(f_kbps==0xffff)//未更新過
{
playtime=0;
f_kbps=VS_Get_HeadInfo(); //獲得比特率
}
time=VS_Get_DecodeTime();//得到解碼時間
if(playtime==0)playtime=time;
elseif((time!=playtime)&&(time!=0))//1s時間到,更新顯示數(shù)據(jù)
{
playtime=time;//更新時間
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;//非法位率
//顯示播放時間
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)文件的總個數(shù)
//path:路徑
//返回值:總有效文件數(shù)
u16 mp3_get_tnum(u8 *path)
{
u8res;
u16rval=0;
DIR tdir; //臨時目錄
FILINFOtfileinfo; //臨時文件信息
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); //讀取目錄下的一個文件
if(res!=FR_OK||tfileinfo.fname[0]==0)break; //錯誤了/到末尾了,退出
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); //申請2*totmp3num個字節(jié)的內(nèi)存,用于存放音樂文件索引
while(mp3fileinfo.lfname==NULL||pname==NULL||mp3indextbl==NULL)//內(nèi)存分配出錯
{
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,顯示的時候,按照公式(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); //讀取目錄下的一個文件
if(res!=FR_OK||mp3fileinfo.fname[0]==0)break; //錯誤了/到末尾了,退出
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); //讀取目錄下的一個文件
if(res!=FR_OK||mp3fileinfo.fname[0]==0)break; //錯誤了/到末尾了,退出
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); //播放這個MP3
if(key==2) //上一曲
{
if(curindex)curindex--;
elsecurindex=totmp3num-1;
}else if(key<=1)//下一曲
{
curindex++;
if(curindex>=totmp3num)curindex=0;//到末尾的時候,自動從頭開始
}else break; //產(chǎn)生了錯誤
}
myfree(SRAMIN,mp3fileinfo.lfname); //釋放內(nèi)存
myfree(SRAMIN,pname); //釋放內(nèi)存
myfree(SRAMIN,mp3indextbl); //釋放內(nèi)存
}
//播放一曲指定的歌曲
//返回值:0,正常播放完成
// 1,下一曲
// 2,上一曲
// 0XFF,出現(xiàn)錯誤了
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));//申請內(nèi)存
databuf=(u8*)mymalloc(SRAMIN,4096); //開辟4096字節(jié)的內(nèi)存區(qū)域
if(databuf==NULL||fmp3==NULL)rval=0XFF;//內(nèi)存申請失敗.
if(rval==0)
{
VS_Restart_Play(); //重啟播放
VS_Set_All(); //設(shè)置音量等信息
VS_Reset_DecodeTime(); //復(fù)位解碼時間
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個字節(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,顯示的時候,按照公式(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,顯示的時候,按照公式(vol-100)/5,顯示,也就是0~30
break;
}
mp3_msg_show(fmp3->fsize);//顯示信息
}
}while(i<4096);//循環(huán)發(fā)送4096個字節(jié)
if(br!=4096||res!=0)
{
rval=0;
break;//讀完了.
}
}
f_close(fmp3);
}elserval=0XFF;//出現(xiàn)錯誤
}
myfree(SRAMIN,databuf);
myfree(SRAMIN,fmp3);
returnrval;
}
全部程序51hei下載地址:
STM32_MP3.7z
(1.32 MB, 下載次數(shù): 211)
2020-5-24 00:25 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者: 廖恒 時間: 2020-5-23 21:09
實物圖如下:
IMG_20200518_155134_BURST028.jpg (1.89 MB, 下載次數(shù): 94)
下載附件
2020-5-23 21:09 上傳
作者: 廖恒 時間: 2020-5-23 23:04
有需要實物的,可以聯(lián)系我,QQ:3012772245
作者: 0x00000000 時間: 2020-11-3 09:23
感謝樓主的例子!一直想用這顆芯片都沒用上,希望盡快能上手。
作者: wrp19881104 時間: 2022-12-25 21:47
為什么我測試可以讀卡讀不到文件夾 sd卡也創(chuàng)建了music文件夾和音樂文件
作者: LULOF 時間: 2023-7-31 21:21
有用,感謝樓主!
作者: 173396840 時間: 2023-12-5 09:08
VS1053B現(xiàn)在停產(chǎn)沒?
作者: yyyyyll 時間: 2024-3-24 20:07
求仿真文件
作者: yyyyyll 時間: 2024-3-26 00:16
求仿真文件,原理圖,實物有圖嗎?
歡迎光臨 (http://m.zg4o1577.cn/bbs/) |
Powered by Discuz! X3.1 |
主站蜘蛛池模板:
www男人天堂|
又色又爽又黄18网站
|
三级黄色片
|
欧美国产精品
|
国产日韩欧美在线观看
|
亚洲精品a
|
国产一区免费视频
|
一区二区三区国产视频
|
97在线免费
|
国产精品日韩欧美
|
久久久精品影院
|
少妇av在线
|
久久久久久久九九九九
|
色综合久久88
|
亚洲人成在线播放
|
国产91一区
|
国产综合亚洲精品一区二
|
国产精品一区二区免费
|
天天爽夜夜爽夜夜爽
|
久久亚洲免费视频
|
午夜在线视频观看日韩17c
|
久久精品三级
|
亚洲精品大片
|
国产激情视频
|
久草网在线观看
|
日日夜夜狠狠干
|
日本在线看片
|
成人黄色一级片
|
天天爽天天干
|
日韩精品一区二区在线
|
欧美三根一起进三p
|
亚洲天堂2014
|
人与拘一级a毛片
|
欧美做受69
|
久久成人毛片
|
黄色一级片免费
|
黄色一级大片在线免费看产
|
精品免费国产一区二区三区四区
|
91成人看片
|
国产精品毛片久久久久久久
|
国产成人在线免费观看
|