本程序为应用级,可以根据实际情况修改后用到你的项目中,本代码例程是运用STM32F407的标准库,可以运用到APM32407上完全兼容运行。
这里采用的是STM32F407VET6标准库 DMA+DAC 的方式播放16Khz 8bit数据,只实现了DAC1 右对齐8位数数据播放方式,使用了TIM6 作为DAC触发基准,由于频率较高,这里使用了双缓冲的方式,加载音频数据 两个buff交替加载
本程序据有音量调节功能,最小音量级数30级(可以自己定义,在.h文件中由宏MAXVolume设置)。
这里播放的是原始wav文件没有经过任何裁剪,具体wav数据头文件原理请参考其他说明。
//Audio.c文件的初始化配置:
#include "Audio.h"
#include "soundlib.h" //音频库头文件
#include "W25Qxx.h" //读取外置flash内的音频
#include "rs485.h" //调试用
//DAC数据寄存器地址
#define Audio_DR8R (0x40007410)
#define AUdio_DR12R (0x40007408)
#define Audio_DHR8R (0x40007428)
Audio_Info *Audio;
void Audio_DMA_8K(u8 *dat,u16 len);
//内部外部播放需要的参数
Play_Flag Inplay={0},Explay={0};
//音频数据指针
static u8 *ExData;
//DMA双缓冲数据buff
static u8 Audiobuf0[mallocLen]={0},Audiobuf1[mallocLen]={0};
//DAC 配置初始化
void Audio_DAC_Init(void)
{
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitType;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; //模拟输入
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//下拉
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_DeInit(TIM6);
TIM_SetAutoreload(TIM6, 5250); //16KHz=84000000/5250
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
TIM_Cmd(TIM6, ENABLE);
//DAC1 12R
DMA_DeInit(DMA1_Stream5);
while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){} //等待DMA可配置
DMA_InitStructure.DMA_Channel = DMA_Channel_7; //通道选择
DMA_InitStructure.DMA_PeripheralBaseAddr =Audio_DR8R ; //DMA外设地址
DMA_InitStructure.DMA_Memory0BaseAddr = 0; //DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //存储器->外设
DMA_InitStructure.DMA_BufferSize = 0; //数据传输量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8位
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte; //存储器数据长度:8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //使用普通模式
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //非常高等优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
DMA_Init(DMA1_Stream5, &DMA_InitStructure); //初始化DMA Stream
DMA_ITConfig(DMA1_Stream5,DMA_IT_TC|DMA_IT_HT,ENABLE);
DMA_Cmd(DMA1_Stream5, DISABLE); //关闭DMA传输
DAC_InitType.DAC_Trigger=DAC_Trigger_T6_TRGO; //使用TIM6触发
DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None; //不使用波形发生
DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ; //DAC1输出缓存关闭 BOFF1=1
DAC_Init(DAC_Channel_1,&DAC_InitType);
DAC_DMACmd(DAC_Channel_1,ENABLE);
DAC_Cmd(DAC_Channel_1,ENABLE); //使能DAC通道1
AudioEN=0; //这里是使能功放
}
//DMA传输开始函数
void Audio_DMA_8K(unsigned char *dat,u16 len)
{
DMA_Cmd(DMA1_Stream5, DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){} //确保DMA可以被设置
DMA1_Stream5->M0AR=(uint32_t)dat;
DMA_SetCurrDataCounter(DMA1_Stream5,len); //数据传输量
DMA_Cmd(DMA1_Stream5, ENABLE); //开启DMA传输
}
//DMA 传输过半,传输完成中断 使用时需要开启DMA中断,这里就不贴代码了
void DMA1_Stream5_IRQHandler(void)
{
if(DMA_GetITStatus(DMA1_Stream5,DMA_IT_TCIF5)!=RESET)
{
DMA_ClearITPendingBit(DMA1_Stream5,DMA_IT_TCIF5); //传输完成
if(Inplay.Alllen>Inplay.ReadAddr)
Inplay.TCIFFg=1;
if(Explay.Alllen>Explay.ReadAddr)
Explay.TCIFFg=1;
}
if(DMA_GetITStatus(DMA1_Stream5,DMA_IT_HTIF5)!=RESET) //传输过半
{
DMA_ClearITPendingBit(DMA1_Stream5,DMA_IT_HTIF5);
if(Inplay.Alllen>Inplay.ReadAddr)
Inplay.HTIFFg=1;
if(Explay.Alllen>Explay.ReadAddr)
Explay.HTIFFg=1;
}
}
//内置Flash存储传输过半
void Interior_Signal_HTIFx(void)
{
u16 i;
//传输过半
if(Inplay.HTIFFg==1)
{
Inplay.HTIFFg=0;
if(Inplay.SubCNT>mallocLen)
{
Inplay.DMAlen=mallocLen;
Inplay.SubCNT-=mallocLen;
}
else
{
Inplay.DMAlen=Inplay.SubCNT;
Inplay.SubCNT-=Inplay.SubCNT;
}
if(Inplay.bufSel==0)
{
memcpy(Audiobuf1,ExData+Inplay.ReadAddr,Inplay.DMAlen);
for(i=0;i<Inplay.DMAlen;i++)
{
if(sysSrtting.volume==MAXVolume)
Audiobuf1=0;
else
Audiobuf1/=sysSrtting.volume;
}
Inplay.bufSel=1;
}
else
{
memcpy(Audiobuf0,ExData+Inplay.ReadAddr,Inplay.DMAlen);
for(i=0;i<Inplay.DMAlen;i++)
{
if(sysSrtting.volume==MAXVolume)
Audiobuf0=0;
else
Audiobuf0/=sysSrtting.volume;
}
Inplay.bufSel=0;
}
}
//传输完成
if(Inplay.TCIFFg==1)
{
Inplay.TCIFFg=0;
if(Inplay.bufSel==0)
Audio_DMA_8K(Audiobuf0,Inplay.DMAlen);
else
Audio_DMA_8K(Audiobuf1,Inplay.DMAlen);
Inplay.ReadAddr+=Inplay.DMAlen;
if(Inplay.ReadAddr>=Inplay.Alllen) //整段音频播放完成
{
#if Debug
logDebugCam("Audio play done\r\n");
#endif
Inplay.ReadAddr=0;
Inplay.Alllen=0;
}
}
}
//内置Flash音频函数播放索引 需要播放时调用此函数一次并输入索引
void Audioplay_index(u8 index)
{
u16 i;
memset((u8 *)&Inplay,0,sizeof(Play_Flag));
if(sysSrtting.volume==0)
sysSrtting.volume=1;
DMA_Cmd(DMA1_Stream5, DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){} //确保DMA可以被设置
switch(index)
{
case Person: //播放1号音频
Audio=(Audio_Info *)AudioPerson; //这里是将WAV文件转成的C语言数组,并设置为const unsigned char数据类型
#if Debug
logDebugCam("Audio play Person\r\n");
#endif
break;
case Car: //播放2号音频
Audio=(Audio_Info *)AudioCars;
#if Debug
logDebugCam("Audio play Car\r\n");
#endif
break;
case Volume: //播放3号音频
Audio=(Audio_Info *)voldata;
break;
default:
break;
}
Inplay.Alllen=Audio->SubChunck2Size.Vu32;
Inplay.SubCNT=Audio->SubChunck2Size.Vu32;
ExData=&Audio->data;
if(Inplay.SubCNT>mallocLen)
{
Inplay.DMAlen=mallocLen;
Inplay.SubCNT-=mallocLen;
}
else
{
Inplay.DMAlen=Inplay.SubCNT;
Inplay.SubCNT-=Inplay.SubCNT;
}
memcpy(Audiobuf0,ExData,Inplay.DMAlen);
Inplay.ReadAddr+=Inplay.DMAlen;
for(i=0;i<Inplay.DMAlen;i++)
{
if(sysSrtting.volume==MAXVolume)
Audiobuf0=0;
else
Audiobuf0/=sysSrtting.volume;
}
Audio_DMA_8K(Audiobuf0,Inplay.DMAlen);
}
/********************************************************************************************************************************************/
//外部存储Flash传输过半信号
void External_Signal_HTIFx(void)
{
u16 i;
//传输过半
if(Explay.HTIFFg==1)
{
Explay.HTIFFg=0;
if(Explay.SubCNT>mallocLen)
{
Explay.DMAlen=mallocLen;
Explay.SubCNT-=mallocLen;
}
else
{
Explay.DMAlen=Explay.SubCNT;
Explay.SubCNT-=Explay.SubCNT;
}
if(Explay.bufSel==0)
{
W25QXX_Read(Audiobuf1,Explay.EXAddres+Explay.ReadAddr,Explay.DMAlen);
for(i=0;i<Explay.DMAlen;i++)
{
if(sysSrtting.volume==MAXVolume)
Audiobuf1=0;
else
Audiobuf1/=sysSrtting.volume;
}
Explay.bufSel=1;
}
else
{
W25QXX_Read(Audiobuf0,Explay.EXAddres+Explay.ReadAddr,Explay.DMAlen);
for(i=0;i<Explay.DMAlen;i++)
{
if(sysSrtting.volume==MAXVolume)
Audiobuf0=0;
else
Audiobuf0/=sysSrtting.volume;
}
Explay.bufSel=0;
}
}
//传输完成
if(Explay.TCIFFg==1)
{
Explay.TCIFFg=0;
if(Explay.bufSel==0)
Audio_DMA_8K(Audiobuf0,Explay.DMAlen);
else
Audio_DMA_8K(Audiobuf1,Explay.DMAlen);
Explay.ReadAddr+=Explay.DMAlen;
if(Explay.ReadAddr>=Explay.Alllen)
{
if(Showx[Person].TIMFg==True)
Showx[Person].TIMFg=Done;
if(Showx[Car].TIMFg==True)
Showx[Car].TIMFg=Done;
Explay.ReadAddr=0;
Explay.Alllen=0;
}
}
}
//自定义音频信号开始传输
void Person_Audio_Udefined(void)
{
u16 i;
memset((u8 *)&Explay,0,sizeof(Play_Flag));
if(sysSrtting.volume==0)
sysSrtting.volume=1;
DMA_Cmd(DMA1_Stream5, DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){} //确保DMA可以被设置
Explay.EXAddres=AddrAudioPerson; //外部Flash 音频基地址
W25QXX_Read(Audiobuf0,Explay.EXAddres,44);
Audio=(Audio_Info *)Audiobuf0;
Explay.Alllen=Audio->SubChunck2Size.Vu32; //获取音频有效数据总长
Explay.SubCNT=Audio->SubChunck2Size.Vu32; //获取音频有效数据总长
if(Explay.SubCNT>mallocLen)
{
Explay.DMAlen=mallocLen;
Explay.SubCNT-=mallocLen;
}
else
{
Explay.DMAlen=Explay.SubCNT;
Explay.SubCNT-=Explay.SubCNT;
}
Explay.EXAddres+=44;
W25QXX_Read(Audiobuf0,Explay.EXAddres+Explay.ReadAddr,Explay.DMAlen);
Explay.ReadAddr+=Explay.DMAlen;
for(i=0;i<Explay.DMAlen;i++) //设置音量
{
if(sysSrtting.volume==MAXVolume)
Audiobuf0=0;
else
Audiobuf0/=sysSrtting.volume;
}
Audio_DMA_8K(Audiobuf0,Explay.DMAlen); //开启传输
}
//自定义音频信号开始传输
void Car_Audio_Udefined(void)
{
u16 i;
Explay.Alllen=0;
Explay.bufSel=0;
Explay.DMAlen=0;
Explay.ReadAddr=0;
if(sysSrtting.volume==0)
sysSrtting.volume=1;
DMA_Cmd(DMA1_Stream5, DISABLE); //关闭DMA传输
while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){} //确保DMA可以被设置
Explay.EXAddres=AddrAudioCar; //外部Flash 音频基地址
W25QXX_Read(Audiobuf0,Explay.EXAddres,44);
Audio=(Audio_Info *)Audiobuf0;
Explay.Alllen=Audio->SubChunck2Size.Vu32;
Explay.SubCNT=Audio->SubChunck2Size.Vu32;
if(Explay.SubCNT>mallocLen)
{
Explay.DMAlen=mallocLen;
Explay.SubCNT-=mallocLen;
}
else
{
Explay.DMAlen=Explay.SubCNT;
Explay.SubCNT-=Explay.SubCNT;
}
Explay.EXAddres+=44;
W25QXX_Read(Audiobuf0,Explay.EXAddres+Explay.ReadAddr,Explay.DMAlen);
Explay.ReadAddr+=Explay.DMAlen;
for(i=0;i<Explay.DMAlen;i++) //设置音量
{
if(sysSrtting.volume==MAXVolume)
Audiobuf0=0;
else
Audiobuf0/=sysSrtting.volume;
}
Audio_DMA_8K(Audiobuf0,Explay.DMAlen); //开启传输
}
/*************************************************************************************分隔符*************************************************************************************************************/
//Audio.h 头文件
#ifndef __AUDIO_H
#define __AUDIO_H
#include "system.h"
typedef union
{
unsigned char Vu8[4];
unsigned int Vu32;
}Byte_Word;
//WAV 文件数据头信息为文件开头0-43字节的数据
typedef struct
{
Byte_Word ChunkID; //'RIFF' (0x52494646) 大端
Byte_Word ChunkSize; //fileSize - 8
Byte_Word Format; //'WAVE'(0x57415645) 大端
Byte_Word SchunkID; //'fmt ' (0x666D7420) 大端
Byte_Word SchunkSize; //16
unsigned char Aformat[2]; //音频格式
unsigned char Channels[2]; //声道数
Byte_Word SampleRate; //采样率
Byte_Word ByteRate; //每秒数据字节数
unsigned char BlockAlign[2]; //数据块对齐
unsigned char BitsPSample[2]; //采样位数
Byte_Word SubChunck2ID; //'data' (0x64617461) 大端
Byte_Word SubChunck2Size; //有效数据长度
unsigned char data; //音频数据
}Audio_Info;
//数据播放期间需要的一些参数
typedef struct
{
u32 Alllen; //数据总长
u32 ReadAddr; //读取地址
u32 EXAddres; //基地址外部地址
u32 SubCNT; //剩余长度
u32 DMAlen; //发送长度
u8 bufSel; //缓存选择 buf0 或buf1
u8 TCIFFg; //传输完成
u8 HTIFFg; //传输过半
}Play_Flag;
#define mallocLen 4096 //双缓冲数据长度 单位:字节
#define MAXVolume 30 //最大音量级数
extern Audio_Info *Audio;
//DAC初始化
void Audio_DAC_Init(void);
//DAC播放索引,运行一次自动播放
void Audioplay_index(u8 index);
//内置 在main while中运行
void Interior_Signal_HTIFx(void);
//外置 在main while中运行
void External_Signal_HTIFx(void);
//自定义音频信号开始传输
void Person_Audio_Udefined(void);
//自定义音频信号开始传输
void Car_Audio_Udefined(void);
//下面是播放示例:
int main(void)
{
/*
你自己的其他初始化函数
*/
//音频初始化函数
Audio_DAC_Init();
Audioplay_index(0);//开始播放索引0的音频文件,只需调用一次
while(1)
{
External_Signal_HTIFx();
Interior_Signal_HTIFx();
}
} |