记录下,折腾了两天终于可以播放声音了,Stm32f103 使用DAC播放wav音频文件

 

 

 00-03    52 49 46 46:RIFF的标志

04-07    24 90 01 00 :文件的长度

08-0B    57 41 56 45  :WAVE的标志

0C-0F   66 6D 74 20  :fmt的标志

10-13   10 00 00 00   :编码的格式类别,10H代表PCM形式。

14-15    01  00  :字块总数

16-17   01  00   : 通道数  1为单声道,2为双声道

18-1B  80 3E 00 00 :采样率:每秒采集二进制的位数。

1C-1F  00 7D 00 00 :每秒播放的字节数 = 通道数 x 每秒采集二进制的位数 x 采集数据的位数 / 8.  32000

20-21  02 00 :每个样点的字节数

22-23  01 00 :每个样点的数据位数

24-27 64 61 74 61 :data的标志

28-2b:00 90 01 00  文件长度

wav文件长度 3200KB

wav 的频率为16000

一般WAV数据开始的第44字节开始就是wav数据了,把wav数据取出后直接送到DAC播放。

这里的WAV的dac数据是16bit的需要进行转换成12bit

voice[i] = voice[i]+0x8000;//16bit dac 数据为补码形式的,需要进行处理+0x8000
voice[i] = voice[i] >>num; //num 一般为4 右移4位剩下12bit dac数据

设置time定时器的频率16K的采集率

arrValue = (uint16_t)(72000000/(16000-1));

 

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
//定时器TIM3初始化
TIM_TimeBaseStructure.TIM_Period = arrValue ; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =0; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_Cmd(TIM3, ENABLE); //使能TIMx

 

DAC 进行初始化:

GPIO_InitTypeDef GPIO_InitStructure;
DAC_InitTypeDef DAC_InitType;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE ); //使能PORTA通道时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE ); //使能DAC通道时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4) ;//PA.4 输出高

DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 TEN1=0
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通道1

DAC_Cmd(DAC_Channel_1, ENABLE); //使能DAC1

DAC_SetChannel1Data(DAC_Align_12b_R, 0); //DAC_Align_12b_R 12位右对齐数据格式设置DAC值

TIM3->DIER|=1<<8;//允许更新dma请求
TIM3->DIER|=1<<6;//允许触发中断
TIM3->DIER|=1<<0;//允许更新中断

打开DAC DMA功能

DMA_Cmd(DMA1_Channel3, DISABLE ); //关闭USART1 TX DMA1 所指示的通道
DMA_SetCurrDataCounter(DMA1_Channel3,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA1_Channel3, ENABLE); //使能USART1 TX DMA1 所指示的通道

这样就可以把WAV的dac数据通过DMA发送出去了

当一包的DMA数据发送完成后需要更新一包数据进行发送,通过定时器中断设置标志位后,重新配置数据,

下次改用DMA的中断试试看。

DMA_Cmd(DMA1_Channel3, DISABLE );

DAC_DMA_Config(DMA1_Channel3,(u32)&DAC->DHR12R1,(u32)DAC_SIN_BUF,DAC_SIN_SIZE); 

DMA_SetCurrDataCounter(DMA1_Channel3,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
DMA_Cmd(DMA1_Channel3, ENABLE); //使能USART1 TX DMA1 所指示的通道

 

直到把数据发送完,简单的播放wav数据就完成了。

 

posted @ 2020-11-26 17:18  xiaoyu_lin  阅读(2848)  评论(0编辑  收藏  举报