由于这几天比较忙,没及时上传代码,不好意思,详见http://www.openedv.com/posts/list/10961.htm
//定时器4中断服务程序 mp3 DAC输出音频,由于我的PA5有它用,所以只输出了单通道。
extern u8 DACbz_mp3;
extern u8 CH_mp3;
extern u16 DApc_mp3;
extern u8 buffer_switch;
void TIM4_IRQHandler(void)
{
if(TIM4->SR&0X0001)//溢出中断
{
if(CH_mp3==1)//单声道
{
if(buffer_switch==0)
{
DAC->DHR12R1=(((short)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
// DAC->DHR12R2=(((short)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
DApc_mp3++;
DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
}else
{
DAC->DHR12R1=(((short)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
// DAC->DHR12R2=((buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
DApc_mp3++;
DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
}
}
else //if(CH_mp3==2)//立体声 10110010 10110010
{
if(buffer_switch==0)
{
DAC->DHR12R1=(((short)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
DApc_mp3++;
// DAC->DHR12R2=(((short)buffer1[DApc_mp3]+0x8000)>>4);//*10/volume;
DApc_mp3++;
DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
}else
{
DAC->DHR12R1=(((short)buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
DApc_mp3++;
// DAC->DHR12R1=((buffer2[DApc_mp3]+0x8000)>>4);//*10/volume;
DApc_mp3++;
DAC->SWTRIGR|=0x03;//软件启动两个通道的转换
}
}
if(DApc_mp3==2304) //1帧MP3输出2304数据
{ DApc_mp3=0;
DACbz_mp3=1;
}
}
TIM4->SR&=~(1<<0);//清除中断标志位
}
//通用定时器4中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器4!
void Timer4_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<2;//TIM4时钟使能
TIM4->ARR=arr; //设定计数器自动重装值//刚好1ms
TIM4-> SC=psc; //预分频器7200,得到10Khz的计数时钟
//这两个东东要同时设置才可以使用中断
TIM4->DIER|=1<<0; //允许更新中断
TIM4->DIER|=1<<6; //允许触发中断
TIM4->CR1|=0x01; //使能定时器4
MY_NVIC_Init(1,3,TIM4_IRQChannel,2);//抢占1,子优先级3,组2
}
//DAC通道1输出初始化 要用双通道的还要加上DAC2的初始化
void Dac1_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
RCC->APB1ENR|=1<<29; //使能DAC时钟
GPIOA->CRL&=0XFFF0FFFF;
GPIOA->CRL|=0X00000000;//PA4 模拟输入(虽然是输入,但是STM32 内部会连接在DAC 模拟输出上)
DAC->CR|=1<<0; //使能DAC1
DAC->CR|=0<<1; //DAC1输出缓存使能 BOFF1=0
DAC->CR|=0<<2; //不使用触发功能 TEN1=0
DAC->CR|=0<<3; //DAC TIM6 TRGO,不过要TEN1=1才行
DAC->CR|=0<<6; //不使用波形发生
DAC->CR|=0<<8; //屏蔽、幅值设置
DAC->CR|=0<<12; //DAC1 DMA不使能
DAC->DHR12R1=0;
DAC->DHR12L1=0;
DAC->SWTRIGR|=0x01;//通道1软件启动转换
}
void mp3play(void)//MP3播放,这个函数在压缩包里面有
{
// int err;
u32 br;
FRESULT res;
Outpcmbuf=buffer1;
LCD_Clear(WHITE); //黑屏
hMP3Decoder=MP3InitDecoder(); //初始化解码器
Dac1_Init(); //用DAC播放
res=f_open(&f_MP3,"0:/1.MP3",FA_OPEN_EXISTING|FA_READ);//打开MP3文件
bytesLeft=0; //复位计数器
while(1)
{
res=f_read(&f_MP3,readBuf,READBUF_SIZE,(UINT*)&br); //读出2048个字节
if(res!=FR_OK||br==0) break;
readPtr=readBuf;
bytesLeft = br;
buffer_switch=0; //双缓存切换标志
init=0;
while(1)
{
offset=MP3FindSyncWord(readPtr, bytesLeft);//寻找下一帧头 帧同步
if(offset<0)break;
readPtr+=offset; //data start point
bytesLeft-=offset; //in buffer
MP3Decode(hMP3Decoder,&readPtr,&bytesLeft,Outpcmbuf,0);//解码
// err=MP3Decode(hMP3Decoder,&readPtr,&bytesLeft,Outpcmbuf,0);//解码
if(bytesLeft<READBUF_SIZE) //补充数据
{
memmove(readBuf,readPtr,bytesLeft);
res=f_read(&f_MP3,readBuf+bytesLeft,READBUF_SIZE-bytesLeft,(UINT*)&br);
if((res)||(br==0)) break;
if(br<READBUF_SIZE-bytesLeft)
memset(readBuf+bytesLeft+br,0,READBUF_SIZE-bytesLeft-br);
bytesLeft=READBUF_SIZE;
readPtr=readBuf;
}
// if (err != ERR_MP3_NONE)
// {
// switch (err)
// {
// case ERR_MP3_INDATA_UNDERFLOW:
// printf("\r\n 错误1"); //打印
// break;
// case ERR_MP3_MAINDATA_UNDERFLOW:
// printf("\r\n 错误2"); //打印
// break;
// default: // 跳过此帧
// printf("\r\n 错误3"); //打印
// break;
// }
// }
MP3GetLastFrameInfo(hMP3Decoder, &mp3FrameInfo); //获得解码
if(init==0) //根据MP3帧信息初始化音频接口
{
// printf("MP3信息:%x\n",mp3FrameInfo.outputSamps); //打印
if(mp3FrameInfo.nChans==1)Show_Str(60,120,"声道: 单声道",16,1);
else Show_Str(60,120,"声道: 立体声",16,1);
Show_Str(60,140,"采样率: Hz",16,1);
LCD_ShowNum(60+80,140,mp3FrameInfo.samprate,5,16);//采样率
Timer4_Init(1000000/(mp3FrameInfo.samprate),71);//1MHz的计数频率,产生和采样率一样的中断频率
CH_mp3=mp3FrameInfo.nChans; //几声道
LCD_ShowNum(60+80,160,mp3FrameInfo.outputSamps,5,16); //打印=2304 //PCM数据个数
init=1; //1帧MP3输出2304pcm数据
}
if(mp3FrameInfo.nChans==1)Convert_Mono(Outpcmbuf);//单声道
else Convert_Stereo(Outpcmbuf);//立体声
while(!DACbz_mp3); //等待转换完成
DACbz_mp3=0; //定时器中断会置1
if(buffer_switch == 0) //双缓存切换
{
Outpcmbuf=buffer1;
buffer_switch = 1;
}
else
{
Outpcmbuf=buffer2;
buffer_switch = 0;
}
LED=!LED;
}
f_close(&f_MP3);//关闭文件
}
TIM4->CR1&=~0x01;//关定时器,切歌时不产生噪音
DAC->CR&=0<<0; //关闭DAC1
}
|