ADC音频采集的问题

2019-08-14 07:04发布

最近在做ADC的音频采样,之前做8位,8K,单声道采样的时候都是没有问题的,现在想改成16位、16K立体声采样,采集直接手机播放的音乐文件,现在的问题是有杂音且速度很快。我的第一个问题是想确定一下8位的音频采样是不是是无符号的,而16位是要考虑符号?
我现在是按有符号的方式来考虑的,下面是我的相关代码首先是ADC初始化代码:
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  //ADC工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE;  //扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //AD单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;          //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 2;
ADC_Init(ADC1, &ADC_InitStructure);   

ADC_RegularChannelConfig(ADC1, ADC_Channel_1,  1, ADC_SampleTime_13Cycles5);  //Channel1~2,即PA1、PA2用来采集通过功放输入的音频数据
ADC_RegularChannelConfig(ADC1, ADC_Channel_2,  2, ADC_SampleTime_13Cycles5); 

然后是控制采样率的TIM2,因为我是系统默认的初始化所以APB1应该是2分频,所以TIM2应该是72M的时钟
TIM_TimeBaseStructure.TIM_Period = 24; 
TIM_TimeBaseStructure.TIM_Prescaler = 2880000/16000-1; 
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  //设置时钟分频因子  
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  //定时器初始化函数,初始化TIM2

然后是DMA的代码:
u16 ADCConvertedValue[Adc_Buff_Size];
#define ADC_Channels     2
#define A_SECTOR                512     
#define ADC_SamplingRate    16000  
#define FileSamplingRate         16000   
#define Adc_Buff_Size       (2 * ADC_SamplingRate / FileSamplingRate * A_SECTOR * ADC_Channels)  //这里是上下半区所以乘了2
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;             //DMA对应的外设基地址
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADCConvertedValue;     //内存存储基地址,对应的一个数组
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;           //DMA转换模式为SRC模式,由外设搬移到内存
  DMA_InitStructure.DMA_BufferSize = Adc_Buff_Size;          //DMA缓存大小(设置DMA在传输时缓冲区的长度)
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;    //接收一次数据后设备地址禁止后移也就是说地址保持不变(设置DMA的外设递增模式)
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;      //关闭接收一次数据后目标内存地址后移(设置DMA内存递增模式)
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;      //外设数据宽度半字
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         //存储器数据宽度半字
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;               //DMA的传输模式为循环
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;           //DMA的通道拥有高优先级
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                  //非内存到内存传输
  DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
然后是DMA的中断函数,我采用的是上下半区的方式:
void DMA1_Channel1_IRQHandler(void)
{
    if (DMA_GetITStatus(DMA1_IT_HT1) == SET){
           DMA_ClearITPendingBit(DMA1_IT_HT1);
           DMA_ClearFlag(DMA1_FLAG_HT1);
          //检查过半标志,有效,清除标志,处理前半段数据    
         TreatData(0);
    }

    if (DMA_GetITStatus(DMA1_IT_TC1) == SET){   
         DMA_ClearITPendingBit(DMA1_IT_TC1);
         DMA_ClearFlag(DMA1_FLAG_TC1);
         //检查完成标志,有效,清除标志,处理后半段数据
        TreatData(Adc_Buff_Size>>1);
    }
}

然后是 TreatData
#define REC_DATA_LEN    1024
#define CYCLE_COUNT     512 
static s16 ChannelData[REC_DATA_LEN]; 

s32 i, j, Pos;
s32 temp;
for(i=0,j=0; i<CYCLE_COUNT; i++){
      Pos = i*2+Offset; 
      temp = GetADCValue(Pos+0);
      temp = temp-2048;
      ChannelData[j] = temp*16;
      //ChannelData[j] = (GetADCValue(Pos+5)-(s16)2048)*16;  
      j++;
      temp = GetADCValue(Pos+1);
      temp = temp-2048;
      ChannelData[j] = temp*16;
      //ChannelData[j] = (GetADCValue(Pos+6)-(s16)2048)*16;  
      j++; 
}

还有就是GetADCValue
u16 GetADCValue(u16 index)
{
    return ADCConvertedValue[index];
}


SaveRecording();
}

最后是SaveRecording
u8 SaveRecording(void)
{
       if (Is_Recording == TRUE){
             u8 i, res;
             u16 offset;
             for (i=0; i<2; i++){
                      offset = i * 512;
                      //将录音数据分两次写入到SD卡中
                     res = f_write(&fdst, ChannelData+offset, 512, &bw1); 
                     if(res != FR_OK){
                           ErrorEvent = WriteRecordingError;
                           return res;
                     }
             } 

             SectorCount++;    //每写入一块到SD卡中,都需要进行计数
        }
        return 0;
}
请大家帮我看看问题出在哪里
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
6条回答
csf4824521
2019-08-14 08:14
我已经完成了立体声16位、16K音频的ADC采集,噪音小,效果不错,既然坛子里面没有兄弟来回答,我就借着我自己提出的问题来进行一下解答,希望对同样有问题的朋友有帮助。
首先可以肯定的是16位的采样是需要考虑符号的,我上面贴出来的整个代码的大框架是没有问题的,主要是在计算采样率和存放采样数据的内存大小上有问题。
作如下修改:
①控制采样率的TIM2,这里TIM2的时钟应该是36M,所以TIM_Prescaler应该是1440000/16000-1
②其实最关键的问题就在这里SaveRecording,之前采集正弦波的时候发现数据老是出现断层,有很大的一个跳变,后来发现是f_write的使用问题,f_write这个函数是按字节写入的,其第三个参数不是写入的数据的个数,而是写入的数据的字节数,之前8位数据写入时之所以没有出现也是因为这个原因,假设我要写入512个u8数据到SD卡的文件中,那么就相当于写512个字节的数据,但是对于s16的数据要写入1024个字节才能写完这512个数据,所以问题就出在这里,当写16位数据时512个数据的实际字节数应该是1024.

一周热门 更多>