使用STM32F407+MAX98357模块+miniMP3解码库软解MP3播放音乐

首先去下载miniMP3解码库

项目地址

https://github.com/lieff/minimp3

使用

minimp3 的使用十分简单,基础解码功能使用的话只需要两个步骤,并且只需要调用以下两个函数就可以完成解码。

void mp3dec_init(mp3dec_t *dec);
int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info);

使用CubeMAX配置SDIO

选择sd 1bit,我不确定是我sd卡是低速卡的原因还是hal库有bug,我4bit模式初始化不过

为sdio配置DMA开启中断注意sdio的中断优先级一定要高于dma

配置串口用来看调试信息

配置I2s,选择全双工模式,使用飞利浦标准,16位模式,44Khz标准音频采样率

配置I2S的DMA,使能中断(注意I2S的DMA中断优先级要低于SDIO的DMA中断优先级)

配置FATFS文件系统

选择utf-8字符集支持中文,使能长文件名,扇区512默认

配置内存到内存的DMA,用于解码器和缓冲区的数据填充,不需要使能DMA中断

配置按键和LED灯

中断配置如上

时钟配置

配置定时器,播放音乐

拷贝所有库,生成单独的.c.h文件

将栈区和堆区开大些,以免解码过程中栈溢出导致程序卡死

FIL file;
FRESULT f_res;
DWORD tolt,freesize,datasize;
UINT fnum;
BYTE Readebuff[512]={0};
BYTE Write_buff[512]={
 "This is STM32F407 write"
};


 int main(void)
{

  /* USER CODE BEGIN 1 */
  FATFS *fs=&SDFatFS;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SDIO_SD_Init();
  MX_I2S2_Init();
  MX_FATFS_Init();
  MX_USART1_UART_Init();
  MX_TIM6_Init();
  /* USER CODE BEGIN 2 */
	
  f_res = f_mount(&SDFatFS,"0:",1);
	HAL_Delay(100);
	
	f_res =f_open(&SDFile,"0:/holle.txt",FA_CREATE_ALWAYS|FA_WRITE|FA_READ);
	if(f_res==FR_OK){
	  printf("创建成功\n");
	}
	f_res =f_write(&SDFile,Write_buff,sizeof(Write_buff),&fnum);
  if(f_res==FR_OK){
	  printf("写入成功\n");
	}
	f_res =f_sync(&SDFile);
	HAL_Delay(100);
	f_res =f_read(&SDFile,Readebuff,sizeof(Readebuff),&fnum);
  if(f_res==FR_OK){
	  printf("读入成功\n");
	}
	f_res =f_close(&SDFile);
	f_res=f_getfree("0:",&tolt,&fs);
  if(f_res==FR_OK){
	  datasize=(fs->n_fatent-2)*(fs->csize/2);
		freesize=tolt*(fs->csize/2);
		printf("总容量:  %ldMB\n",datasize/1024);
		printf("剩余容量:%ldMB\n",freesize/1024);
	}

先测试sd卡的读写是否异常

#include "minimp3.h" 
#include "minimp3_interface.h"
#include "tim.h"
#include "stdbool.h"

extern I2S_HandleTypeDef hi2s2;
extern DMA_HandleTypeDef hdma_spi2_tx;
extern DMA_HandleTypeDef hdma_memtomem_dma2_stream0;
extern DMA_HandleTypeDef hdma_memtomem_dma2_stream1;
extern TIM_HandleTypeDef htim6;
// 增大缓冲区大小,避免帧跨缓冲区问题(MP3帧最大约1440字节,8192更安全)
#define MP3_BUFFER_SIZE 8192
#define MP3_FIFO_SIZE 12
#define MP3_HIGH_BIT 10
#define MP3_LOW_BIT  8

mp3dec_t mp3d;
mp3dec_frame_info_t info;
short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
short pcmbuf1[MINIMP3_MAX_SAMPLES_PER_FRAME];
short pcmbuf2[MINIMP3_MAX_SAMPLES_PER_FRAME];
BYTE buffer[MP3_BUFFER_SIZE];  // 增大缓冲区
FRESULT fr;
UINT bytes_read;
UINT bytes_remaining = 0;  // 重命名变量,更清晰表示"剩余未处理数据"
const BYTE *data_ptr;      // 重命名变量,明确为数据指针
UINT byte_data;//文件剩余大小

short pcm_fifo_buf[MINIMP3_MAX_SAMPLES_PER_FRAME*MP3_FIFO_SIZE]; //fifo缓冲区
	
typedef struct Pcm_fifo{

	short *handbuf;
	short *tailbuf;
	short *buftailaddr;
  UINT number;

}PCM_Fifo;

PCM_Fifo pcm_back;
bool Play_stop_bit = false;
volatile uint16_t snubber = 0;   // 0:快速写缓冲区 1:等待缓冲区数据拿走
volatile UINT play_stage = 0;    // 0:无状态 2:播放中
volatile uint16_t key_mode = 0;  // 0:播放/暂停 1:上一曲 2:下一曲
volatile uint16_t up_play = 0;
volatile uint16_t down_play = 0;
static uint32_t audio_sample_rate = 0;
static uint16_t audio_channels = 0;
 

建立一些变量,为MP3解码开辟缓冲区和FIFO队列

//fifo 初始化
void Fifo_Init(PCM_Fifo *pcm_fifo){

     pcm_fifo->handbuf=pcm_fifo_buf;
	 pcm_fifo->tailbuf=pcm_fifo_buf;
	 pcm_fifo->buftailaddr=&pcm_fifo_buf[MINIMP3_MAX_SAMPLES_PER_FRAME*MP3_FIFO_SIZE];
	 pcm_fifo->number=0;
	
}
void Fifo_wirte_data(PCM_Fifo *pcm_fifo,short *data){
	
      if(pcm_fifo->handbuf>=pcm_fifo->buftailaddr){
			      pcm_fifo->handbuf=pcm_fifo_buf;
			}
	      HAL_DMA_Start(&hdma_memtomem_dma2_stream0,(uint32_t)data,(uint32_t)pcm_fifo->handbuf,MINIMP3_MAX_SAMPLES_PER_FRAME);
	      HAL_DMA_PollForTransfer(&hdma_memtomem_dma2_stream0,HAL_DMA_FULL_TRANSFER,10);
		  HAL_DMA_Abort(&hdma_memtomem_dma2_stream0);
//			memmove(pcm_fifo->handbuf,data,MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(short));
          pcm_fifo->handbuf+=MINIMP3_MAX_SAMPLES_PER_FRAME;
		  pcm_fifo->number++;
}

void Fifo_read_data(PCM_Fifo *pcm_fifo,short *data){
	
     if(pcm_fifo->number>0){
			  if(pcm_fifo->tailbuf>=pcm_fifo->buftailaddr){
			      pcm_fifo->tailbuf=pcm_fifo_buf;
			  }
		      HAL_DMA_Start(&hdma_memtomem_dma2_stream1,(uint32_t)pcm_fifo->tailbuf,(uint32_t)data,MINIMP3_MAX_SAMPLES_PER_FRAME);
		        HAL_DMA_PollForTransfer(&hdma_memtomem_dma2_stream1,HAL_DMA_FULL_TRANSFER,10);
			  HAL_DMA_Abort(&hdma_memtomem_dma2_stream1);
//				memmove(data,pcm_fifo->tailbuf,MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(short));
		    pcm_fifo->tailbuf+=MINIMP3_MAX_SAMPLES_PER_FRAME;
			  pcm_fifo->number--;
		 }

}

FIFO的实现,使用FIFO可以缓存一部分解码完成的数据,避免卡的情况发生

// 配置定时器频率以匹配音频采样率
void ConfigureTimerForSampleRate(uint32_t sample_rate) {
    if (sample_rate == 0) return;
    
    // 计算定时器周期:每个音频帧的播放时间(ms)
    // MINIMP3_MAX_SAMPLES_PER_FRAME通常是1152
    uint32_t frame_duration = (MINIMP3_MAX_SAMPLES_PER_FRAME * 1000) / sample_rate;
    
    // 配置定时器周期
    TIM_HandleTypeDef *htim = &htim6;
    HAL_TIM_Base_Stop_IT(htim);
    htim->Init.Period = ((((SystemCoreClock) / (htim->Init.Prescaler+1) / 1000) * frame_duration ));
    HAL_TIM_Base_Init(htim);
    HAL_TIM_Base_Start_IT(htim);
	  __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE);
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    
    if(htim->Instance==TIM6){
		    if(pcm_back.number>0&&play_stage==2){
					  HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_9);
//					  Fifo_read_data(&pcm_back,pcmbuf1);
//						HAL_I2S_Transmit_DMA(&hi2s2,pcmbuf1,MINIMP3_MAX_SAMPLES_PER_FRAME);
					  HAL_I2S_Transmit_DMAEx(&hi2s2,pcmbuf1,pcmbuf2,MINIMP3_MAX_SAMPLES_PER_FRAME);
					  __HAL_TIM_CLEAR_FLAG(&htim6,TIM_FLAG_UPDATE);
				}
		}

}

根据解码信息配置定时器的时间匹配播放帧率

void DMAEx_XferCpltCallback(DMA_HandleTypeDef *hdma){

   Fifo_read_data(&pcm_back,pcmbuf1);
   //HAL_I2S_DMAStop(&hi2s2);
}
void DMAEx_XferM1CpltCallback(DMA_HandleTypeDef *hdma){

   Fifo_read_data(&pcm_back,pcmbuf2);
   //HAL_I2S_DMAStop(&hi2s2);
}
void DMAEx_XferErrorCallback(DMA_HandleTypeDef *hdma){



}

HAL_StatusTypeDef HAL_I2S_Transmit_DMAEx(I2S_HandleTypeDef *hi2s, uint16_t *FirstBuff,uint16_t *SecondBuff,uint16_t Size)
{
  uint32_t tmpreg_cfgr;

  if ((FirstBuff == NULL) || (Size == 0U) || (SecondBuff == NULL))
  {
    return  HAL_ERROR;
  }

  if (hi2s->State != HAL_I2S_STATE_READY)
  {
    return HAL_BUSY;
  }

  /* Process Locked */
  __HAL_LOCK(hi2s);

  /* Set state and reset error code */
  hi2s->State = HAL_I2S_STATE_BUSY_TX;
  hi2s->ErrorCode = HAL_I2S_ERROR_NONE;
  hi2s->pTxBuffPtr = FirstBuff;

  tmpreg_cfgr = hi2s->Instance->I2SCFGR & (SPI_I2SCFGR_DATLEN | SPI_I2SCFGR_CHLEN);

  if ((tmpreg_cfgr == I2S_DATAFORMAT_24B) || (tmpreg_cfgr == I2S_DATAFORMAT_32B))
  {
    hi2s->TxXferSize = (Size << 1U);
    hi2s->TxXferCount = (Size << 1U);
  }
  else
  {
    hi2s->TxXferSize = Size;
    hi2s->TxXferCount = Size;
  }

  /* Set the I2S Tx DMA Half transfer complete callback */
  hi2s->hdmatx->XferHalfCpltCallback = NULL;
  hi2s->hdmatx->XferM1HalfCpltCallback=NULL;
  /* Set the I2S Tx DMA transfer complete callback */
  hi2s->hdmatx->XferCpltCallback = DMAEx_XferCpltCallback;
  hi2s->hdmatx->XferM1CpltCallback=DMAEx_XferM1CpltCallback;
  /* Set the DMA error callback */
  hi2s->hdmatx->XferErrorCallback = DMAEx_XferErrorCallback;

  /* Enable the Tx DMA Stream/Channel */
  if (HAL_OK != HAL_DMAEx_MultiBufferStart_IT(hi2s->hdmatx,
                                 (uint32_t)FirstBuff,
	                               (uint32_t)&hi2s->Instance->DR,
	                               (uint32_t)SecondBuff,
                                 hi2s->TxXferSize))
  {
    /* Update SPI error code */
    SET_BIT(hi2s->ErrorCode, HAL_I2S_ERROR_DMA);
    hi2s->State = HAL_I2S_STATE_READY;

    __HAL_UNLOCK(hi2s);
    return HAL_ERROR;
  }
  __HAL_UNLOCK(hi2s);

  /* Check if the I2S Tx request is already enabled */
  if (HAL_IS_BIT_CLR(hi2s->Instance->CR2, SPI_CR2_TXDMAEN))
  {
    /* Enable Tx DMA Request */
    SET_BIT(hi2s->Instance->CR2, SPI_CR2_TXDMAEN);
  }

  /* Check if the I2S is already enabled */
  if (HAL_IS_BIT_CLR(hi2s->Instance->I2SCFGR, SPI_I2SCFGR_I2SE))
  {
    /* Enable I2S peripheral */
    __HAL_I2S_ENABLE(hi2s);
  }

  return HAL_OK;
}

我参考野火的DMA双缓冲区,重写HAL库的I2s的DMA双缓冲区发送函数,实现连续不间断的音频数据播放

// MP3解码函数
void doc_mp3(const char *filename) {
	  //初始化fifo
	  __HAL_I2S_ENABLE(&hi2s2);
	  Fifo_Init(&pcm_back);//初始化fifo
	  audio_sample_rate=0;
	  up_play=0;    // 清除上一曲状态
		down_play=0;  // 清除下一曲状态
	  play_stage=0; // 清除播放状态
	  Play_stop_bit=false;//清除暂停状态
    // 打开MP3文件
    fr = f_open(&SDFile, filename, FA_OPEN_EXISTING | FA_READ);
    if (fr != FR_OK) {
        printf("文件打开失败: %d\n", fr);  // 输出错误码,便于调试
        return;
    }
		byte_data=f_size(&SDFile);
		printf("文件大小%d byte\n",byte_data);
    printf("文件打开成功\n");
    fr=f_lseek(&SDFile,0);
    // 初始化解码器
    mp3dec_init(&mp3d);
    printf("MP3解码器初始化成功\n");

    // 初始化缓冲区
    bytes_remaining = 0;
    memset(buffer, 0, MP3_BUFFER_SIZE);
 
    do {
			  if(up_play||down_play){
				    break;
				}
        // 读取数据到缓冲区剩余空间
//			  __disable_irq();
        fr = f_read(&SDFile, buffer + bytes_remaining, sizeof(buffer) - bytes_remaining, &bytes_read);
//			  __enable_irq();
        if (fr != FR_OK) {
            printf("文件读取错误: %d\n", fr);
            break;
        }
        
        // 更新总可用数据量(原有剩余数据 + 新读取数据)
        bytes_remaining += bytes_read;
        data_ptr = buffer;
        byte_data-=bytes_read;
        // 循环解码缓冲区中的所有完整帧
        while (bytes_remaining > 0) {
						if(up_play||down_play){
							   break;
						}
            // 解码一帧
            int samples = mp3dec_decode_frame(&mp3d, data_ptr, bytes_remaining, pcm, &info);
            // 处理解码结果
            if (info.frame_bytes == 0) {
                // 帧字节数为0的可能情况:
                // 1. 数据不足(需继续读数据)
                // 2. 真正的错误或文件结束
                    break;
            }

            // 解码成功,处理PCM数据(播放等操作)
            if (samples > 0) {
								 if(pcm_back.number<MP3_FIFO_SIZE && snubber==0){
											Fifo_wirte_data(&pcm_back,pcm);//开始缓冲
									    if(pcm_back.number>MP3_HIGH_BIT){
											   snubber=1;//缓冲结束
											}
								 }
					  		 if(pcm_back.number<MP3_FIFO_SIZE && snubber==1){
								      while(1){
												  play_stage=2;//开始播放
													if(pcm_back.number<MP3_LOW_BIT){
														   snubber=0;//开始缓冲
													   	 break;
													}
													if(up_play||down_play){
															break;
													}
											}
								 }
						if (audio_sample_rate == 0 && info.hz > 0) {
                    audio_sample_rate = info.hz;
                    audio_channels = info.channels;
                    ConfigureTimerForSampleRate(audio_sample_rate);
                    printf("配置音频: 采样率=%dHz, 声道数=%d\n", audio_sample_rate, audio_channels);
            }	 
								
//                printf("解码成功: 采样数=%d, 采样率=%dHz, 声道数=%d\n", 
//                       samples, info.hz, info.channels);
//						   HAL_I2S_Transmit_DMA(&hi2s2,pcm,MINIMP3_MAX_SAMPLES_PER_FRAME);
//							 HAL_Delay(26);
                // 这里添加播放PCM数据的代码(根据你的音频输出接口实现)
            }

            // 移动指针,处理剩余数据
            bytes_remaining -= info.frame_bytes;
            data_ptr += info.frame_bytes;
        }

        // 将剩余未解码数据移动到缓冲区头部
        if (bytes_remaining > 0) {
            memmove(buffer, data_ptr, bytes_remaining);
        }

    } while(byte_data >0);  // 直到文件结束且无剩余数据
//		
		__HAL_I2S_DISABLE(&hi2s2);
    HAL_TIM_Base_Stop_IT(&htim6);
    // 关闭文件
    f_close(&SDFile);
    printf("MP3解码完成,文件已关闭\n");
		
}

MP3解码流程,我采用流式解码,在FIFO缓冲区没有低于低水位时,快速读取sd卡的MP3原数据并调用miniMP3解码函数完成一帧的解码,并加载到FIFO缓冲区,当FIFO缓冲区数据到达高水位时,等待数据下降到低水位,再次重复以上操作,直到音乐播放完成

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){

    
    if(GPIO_Pin==GPIO_PIN_8){
		   
			  if(++key_mode>=3){
				    key_mode=0;
				}
		  
		}
		if(GPIO_Pin==GPIO_PIN_9){
		    
			   switch(key_mode){
					 case 0:
						 Play_stop_bit=!Play_stop_bit;
				     if(Play_stop_bit){
							  play_stage=0;
							  __HAL_I2S_DISABLE(&hi2s2);
						    HAL_TIM_Base_Stop_IT(&htim6);
							  
						 }else{
							  play_stage=2;
							  __HAL_I2S_ENABLE(&hi2s2);
						    HAL_TIM_Base_Start_IT(&htim6);
						 }
					 break;
					 case 1:
						    up_play=1;
					 break;
					 case 2:
						    down_play=1;  
					 break;
					 
				 }
		
		}

}

按键使用外部中断方式触发,控制上一曲,下一曲,播放,暂停操作

//获取根目录列表
uint16_t get_mulu_list(const char *path,char (*psr)[40],uint16_t maxlen){
	
				DIR dpath;
	      FRESULT rse;
	      FILINFO info;
	      uint16_t index = 0;
	      rse = f_opendir(&dpath,path);
				if(rse == FR_OK){
				   printf("目录打开成功\n");
					 while(1){ 
						   rse=f_readdir(&dpath,&info);
						   if(rse!=FR_OK||info.fname[0]==0){//文件读取到末尾
							       break;
							 }
							 if(info.fattrib && AM_DIR){
								 printf("0:/%s\n",info.fname);
							 }else{
								 printf("%s\n",info.fname);
							 }
               sprintf(psr,"0:/%s",info.fname);	
							 psr++;
               if(++index>=maxlen){
							    break;
							 }		 
					 }
					 printf ("目录条数%d\n",index);
				   f_closedir(&dpath);
				}else{
				 printf("目录打开失败\n");
					f_closedir(&dpath);
				}
				
        return index;
}

//获取音乐列表
uint16_t get_music_list(const char *path,char (*psr)[40],uint16_t maxlen,uint16_t scanum){
	
				DIR dpath;
	      FRESULT rse;
	      FILINFO info;
	      TCHAR *Path=path;
	      uint16_t index = 0;
	      for(int Path_num=0;Path_num<scanum;Path_num++){
						rse = f_opendir(&dpath,Path);
						if(rse == FR_OK){
							 printf("目录打开成功\n");
							 while(1){ 
									 rse=f_readdir(&dpath,&info);
									 if(rse!=FR_OK||info.fname[0]==0){//文件读取到末尾
												 break;
									 }
									 if(info.fattrib && AM_DIR){
										 printf("0:/%s\n",info.fname);
									 }else{
										 printf("%s\n",info.fname);
									 }
									 if(strstr(info.fname,"mp3")!=NULL){
											 sprintf(psr,"%s/%s",Path,info.fname);	
											 psr++;
											 if(++index>=maxlen){
													break;
											 }
									 }									 
							 }
							 printf ("音乐条数%d\n",index);
							 f_closedir(&dpath);
						}else{
						 printf("目录打开失败\n");
						 f_closedir(&dpath);
						}
						Path+=40;
			 }
		   return index;
}

读取播放列表,和根目录文件夹操作

#ifndef __MP3_INTERFACE_H_
#define __MP3_INTERFACE_H_

#include "fatfs.h"


void doc_mp3(const char *filenames);
uint16_t get_mulu_list(const char *path,char (*psr)[40],uint16_t maxlen);
uint16_t get_music_list(const char *path,char (*psr)[40],uint16_t maxlen,uint16_t scanum);
#endif

函数声明

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "dma.h"
#include "fatfs.h"
#include "i2s.h"
#include "sdio.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "minimp3_interface.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define MAX_list  20
#define MU_list  100

FIL file;
FRESULT f_res;
DWORD tolt,freesize,datasize;
UINT fnum;
BYTE Readebuff[512]={0};
BYTE Write_buff[512]={
 "This is STM32F407 write"
};
char Path[] = {"0:/"}; //根目录
char Pathlist[MAX_list][40]={0};
char Mulist[MU_list][40]={0};

int Path_num;
int Music_num;
int Music_index;
extern volatile uint16_t up_play;
extern volatile uint16_t down_play;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */


/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* USER CODE BEGIN 1 */
  FATFS *fs=&SDFatFS;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SDIO_SD_Init();
  MX_I2S2_Init();
  MX_FATFS_Init();
  MX_USART1_UART_Init();
  MX_TIM6_Init();
  /* USER CODE BEGIN 2 */
	
  f_res = f_mount(&SDFatFS,"0:",1);
	HAL_Delay(100);
	
	f_res =f_open(&SDFile,"0:/holle.txt",FA_CREATE_ALWAYS|FA_WRITE|FA_READ);
	if(f_res==FR_OK){
	  printf("创建成功\n");
	}
	f_res =f_write(&SDFile,Write_buff,sizeof(Write_buff),&fnum);
  if(f_res==FR_OK){
	  printf("写入成功\n");
	}
	f_res =f_sync(&SDFile);
	HAL_Delay(100);
	f_res =f_read(&SDFile,Readebuff,sizeof(Readebuff),&fnum);
  if(f_res==FR_OK){
	  printf("读入成功\n");
	}
	f_res =f_close(&SDFile);
	f_res=f_getfree("0:",&tolt,&fs);
  if(f_res==FR_OK){
	  datasize=(fs->n_fatent-2)*(fs->csize/2);
		freesize=tolt*(fs->csize/2);
		printf("总容量:  %ldMB\n",datasize/1024);
		printf("剩余容量:%ldMB\n",freesize/1024);
	}
	
  Path_num=get_mulu_list(Path,Pathlist,MAX_list);
	Music_num=get_music_list(Pathlist[0],Mulist,MU_list,Path_num);//更新列表
	for(int i = 0;i<Music_num;i++){
	   
		 printf("path %s\n",Mulist[i]);
	   
	}
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {    
		   printf("Music_index%d\n",Music_index);
		   if(Music_index>=Music_num){
			       Music_index=0;
			 }
//		 for(int i=0;i<Music_num;i++){
			 doc_mp3(Mulist[Music_index]);//根据列表播放音乐
		   if(up_play == 0 && down_play == 0){
					 HAL_Delay(20);
				   Music_index++;
			 }
			 if(up_play>=1 && down_play == 0){
			     Music_index-=1;
				   if(Music_index<0){
					    Music_index=Music_num-1;
					 }
					 HAL_Delay(20);
			 }else if(down_play>=1 && up_play == 0){
			     Music_index+=1;
			     if(Music_index>=Music_num){
					     Music_index=0;
					 }
					 HAL_Delay(20);
			 } 
//		 }
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

代码整体逻辑控制,通过控制mp3路径的索引,来控制上一曲,下一曲

调试信息打印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值