中级会员
 
- 积分
- 369
- 金钱
- 369
- 注册时间
- 2013-12-23
- 在线时间
- 32 小时
|
学习STM32的DAC方式的音频输出,采用FATFS和DMA、DAC、TIM6,读sd卡上的wav音频文件来播放,参考了一下网上的代码有一些不明白的地方请教一下高人。
第一个就是为什么参考代码中对TIM的设置代码只有这几句
/* TIM6配制 */
TIM_DeInit(TIM6);
TIM_SetAutoreload(TIM6, TIM6ARRValue);
/* TIM6 TRGO选择 */
TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
然后在播放函数中有一个
WavePlayer_Init(); //我这里应该不用配置,使用的都是一样的8位
/* 启动TIM6 */
TIM_Cmd(TIM6, ENABLE);
上面三句代码在waveplayer_Init函数中。
这样就可以让TIM6正常工作了吗?
第二个就是代码采用的先发上半段512字节到DMA,然后再发下半段512字节到DMA的方式,但我在学习ADC的时候都是先在NVIC中设置DMA1_Channel1_IRQn然后再在中断函数中来做上下半段的传输就像这样
void DMA1_Channel1_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_HT1) == SET)
{
DMA_ClearITPendingBit(DMA1_IT_HT1);
DMA_ClearFlag(DMA1_FLAG_HT2);
//检查过半标志,有效,清除标志,处理前半段数据
TreatData(0);
}
if (DMA_GetITStatus(DMA1_IT_TC1) == SET)
{
DMA_ClearITPendingBit(DMA1_IT_TC1);
DMA_ClearFlag(DMA1_FLAG_TC1);
//检查完成标志,有效,清除标志,处理后半段数据
TreatData(adc_buff_size>>1);
}
}
但是我的参考代码采用的这种方式
/* 根据wav文件信息配制播放器 -----------------------------------------------*/
WavePlayer_Init();
/* 启动TIM6 */
TIM_Cmd(TIM6, ENABLE);
LCD_SetFrontColor(0x2A4C);
LCD_FillRect(0,200,399,215);
LCD_SetFrontColor(LGRAY);
/* 开始播放 ----------------------------------------------------------------*/
while(WaveDataLength) //这是从WAV头文件读取到的数据长度
{
res = f_read(&fp, Wavebuffer2, BUF_SIZE, &br);
printf("res = %d", res);
if((res!=FR_OK) || (br==0))
{
f_close(&fp);
return Invalid_WAVE_File;
}
if(WAVE_Format.BitsPerSample==BITS_PER_SAMPLE_16) //这是16比特每秒采样精度
{
ChangeData(Wavebuffer2); //这里为什么要changeData?
}/**/
if(WaveDataLength)
{
WaveDataLength -= BUF_SIZE;
}
if(WaveDataLength < BUF_SIZE)
{
WaveDataLength = 0;
}
while(DMA_GetFlagStatus(DMA2_FLAG_TC3) == RESET) //转换完成标志
{
tmp=(u16)((u32)((WAVE_Format.DataSize-WaveDataLength)*400)/WAVE_Format.DataSize);
LCD_DrawYLine(tmp, 202, 213);
}
DMA2->IFCR = DMA2_FLAG_TC3; // 清除DMA2中断标志
DMA2_Channel3->CCR = 0x0; // 清除DMA2通道3设置寄存器配制
DMA2_Reconfig((u32)&Wavebuffer2); //这里为什么这样?
res=f_read(&fp, Wavebuffer, BUF_SIZE, &br);
if((res!=FR_OK) && (br==0))
{
f_close(&fp);
return Invalid_WAVE_File;
}
if(WAVE_Format.BitsPerSample==BITS_PER_SAMPLE_16)
{
ChangeData(Wavebuffer);
}/**/
if(WaveDataLength)
{
WaveDataLength -= BUF_SIZE;
}
if(WaveDataLength < BUF_SIZE)
{
WaveDataLength = 0;
}
while(DMA_GetFlagStatus(DMA2_FLAG_TC3) == RESET)
{
tmp=(u16)((u32)((WAVE_Format.DataSize-WaveDataLength)*400)/WAVE_Format.DataSize);
LCD_DrawYLine(tmp, 202, 213);
}
DMA2->IFCR = DMA2_FLAG_TC3; // 清除DMA2中断标志
DMA2_Channel3->CCR = 0x0; // 清除DMA2通道3设置寄存器配制
DMA2_Reconfig((u32)&Wavebuffer); //这里为什么要这么做且和第一次不同,是在用之前重置一下吗?
}
/* 播放结束 ----------------------------------------------------------------*/
DMA2_Channel3->CCR = 0x0; // 清除DMA2通道3设置寄存器配制
/* 禁止TIM6 */
TIM_Cmd(TIM6, DISABLE);
WaveDataLength = 0;
f_close(&fp); // 关闭文件
void ChangeData(uint8_t table[])
{
int16_t *tab = (int16_t *)&table[0];
uint16_t i;
for(i=0;i<(BUF_SIZE/2);i++)
{
tab += 32768;
}
}
我的理解是先传512字节然后清DMA标志然后再传512字节,可是为什么要这样呢?这样怎么就能达到正确发送的目的呢,还有就是每当传到最后,后面的那个f_read就会因为if为真而退出整个函数,后面的播放结束操作无法进行。 DMA2_Reconfig的内容就是重新设置了一下DMA的传输数据大小,通道内存地址和通道设置寄存器。它的参数赋值给了DMA2_Channel3->CMAR。Wavebuffer和Wavebuffer2都是定义的长度512的数组。求教高人了!!谢谢 |
|