记录下,折腾了两天终于可以播放声音了,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数据就完成了。