zoukankan      html  css  js  c++  java
  • stm32 DAC输出音频

    
    #define DAC_DHR8R1_Address      0x40007410
    
    // Init Structure definition 
    DAC_InitTypeDef            DAC_InitStructure;
    DMA_InitTypeDef            DMA_InitStructure;
    TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;
    
    
    
    
    
    void RCC_Configuration(void);
    void GPIO_Configuration(void);
    void NVIC_Configuration(void);
    u16 GetARRValue(u16 sample);
    
    //rcc 配置时钟频率
    void RCC_Configuration(void)
    {   
      /* RCC system reset(for debug purpose) */
      RCC_DeInit();
    
      /* Enable HSE */
      RCC_HSEConfig(RCC_HSE_ON);
    
      /* Wait till HSE is ready */
      HSEStartUpStatus = RCC_WaitForHSEStartUp();
    
      if(HSEStartUpStatus == SUCCESS)
      {
        /* Enable Prefetch Buffer */
        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    
        /* Flash 2 wait state */
        FLASH_SetLatency(FLASH_Latency_2);
     	
        /* HCLK = SYSCLK */
        RCC_HCLKConfig(RCC_SYSCLK_Div1); 
      
        /* PCLK2 = HCLK */
        RCC_PCLK2Config(RCC_HCLK_Div1); 
    
        /* PCLK1 = HCLK/2 */
        RCC_PCLK1Config(RCC_HCLK_Div2);//36MHz
    
        /* PLLCLK = 8MHz * 9 = 72 MHz */
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    
        /* Enable PLL */ 
        RCC_PLLCmd(ENABLE);
    
        /* Wait till PLL is ready */
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
        {
        }
    
        /* Select PLL as system clock source */
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    
        /* Wait till PLL is used as system clock source */
        while(RCC_GetSYSCLKSource() != 0x08)
        {
        }
      }
    
    // Enable peripheral clocks --------------------------------------------------
      
      //dma dac sinewave
      // DMA clock enable 
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
      // AFIO and GPIOA Periph clock enable 
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE);
      // DAC Periph clock enable 
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM6, ENABLE);
      // TIM8 Periph clock enable 
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
    }
    
    void GPIO_Configuration(void)
    {
      //init gpio
      GPIO_InitTypeDef GPIO_InitStructure;
      //dma dac sinewave  
      GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_4| GPIO_Pin_5;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//DAC输出 必须要设置成 模拟输入
      GPIO_Init(GPIOA, &GPIO_InitStructure);
    }
    
    int main(void)
    {
      RCC_Configuration();
      NVIC_Configuration();
      GPIO_Configuration();  
      
         //DAC output SineWave (TIM8)
     /* 
      //1>.This example describes how to use DAC dual channel mode with DMA to generate sine
      //waves on both DAC channels outputs.
      
            TIM_DeInit(TIM8);
            
            // TIM8 Configuration
            // Time base configuration
            TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
            TIM_TimeBaseStructure.TIM_Period = GetARRValue(44100);//72MHz 的CPU,输出44.1KHz 的音频,设置周期为1633 
            TIM_TimeBaseStructure.TIM_Prescaler = 0;//分频   
            TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;    
            TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
            TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);
          
            // TIM8 TRGO selection
            TIM_SelectOutputTrigger(TIM8, TIM_TRGOSource_Update);
          
            // DAC channel1 Configuration
            DAC_InitStructure.DAC_Trigger = DAC_Trigger_T8_TRGO;
            DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
            DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
            
            
            
            DAC_Init(DAC_Channel_1, &DAC_InitStructure);
          
            // DAC channel2 Configuration
            DAC_Init(DAC_Channel_2, &DAC_InitStructure);
            
    #if 1
      // DMA2 channel4 configuration
      DMA_DeInit(DMA2_Channel4);
    #else
      // DMA1 channel4 configuration
      DMA_DeInit(DMA1_Channel4);
    #endif        
            
            DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R1_Address;//DAC_DHR12RD_Address;//
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&DualSine12bit;
            
            //方向:外设是目的地,还是来源
            DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
            //DMA_DIR_PeripheralDST  外设是目的地
            //DMA_DIR_PeripheralSRC  外设是来源
            
            DMA_InitStructure.DMA_BufferSize = 512;//
            DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
            //DMA_PeripheralInc_Enable  外设地址寄存器递增
            //DMA_PeripheralInc_Disable 外设地址寄存器不变
    
            DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
            //DMA_MemoryInc_Enable  内存地址寄存器递增
            //DMA_MemoryInc_Disable 内存地址寄存器不变
            
            DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据宽度
            DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//内存数据宽度
            DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//设置CAN SPI 的DMA 模式
            //DMA_Mode_Circular 工作在循环缓存模式
            //DMA_Mode_Normal   工作在正常缓存模式
            
            DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA 通道优先级
            DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
            //enable 内存到内存输出
            //disable 内存到内存输出
            
            
    #if 1
      DMA_Init(DMA2_Channel4, &DMA_InitStructure);
      //Enable DMA2 Channel4
      DMA_Cmd(DMA2_Channel4, ENABLE);
    #else
      DMA_Init(DMA1_Channel4, &DMA_InitStructure);
      // Enable DMA1 Channel4 
      DMA_Cmd(DMA1_Channel4, ENABLE);
    #endif
            
            
            // Enable DAC Channel1 
            DAC_Cmd(DAC_Channel_1, ENABLE);
            // Enable DAC Channel2 
            DAC_Cmd(DAC_Channel_2, ENABLE);
          
    
            // Enable DMA for DAC Channel2 
            DAC_DMACmd(DAC_Channel_2, ENABLE);
            
            // TIM8 enable counter
            TIM_Cmd(TIM8, ENABLE);
    
    */
    
        //2>.DAC output SineWave (TIM)   single sinewave 单通道
            
            TIM_DeInit(TIM6);
            
            /* TIM6 Configuration */
            TIM_PrescalerConfig(TIM6, 0x0, TIM_PSCReloadMode_Update);
            TIM_SetAutoreload(TIM6, 1633);
            /* TIM6 TRGO selection */
            TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
          
            /* DAC channel1 Configuration */
            DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
            DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
            DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
            DAC_Init(DAC_Channel_1, &DAC_InitStructure);
      
      
            
    #if 1
      /* DMA2 channel3 configuration */
      DMA_DeInit(DMA2_Channel3);
    #else
      /* DMA1 channel3 configuration */
      DMA_DeInit(DMA1_Channel3);
    #endif       
            
              DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R1_Address;
              DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&thx;
              DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
              DMA_InitStructure.DMA_BufferSize = 20222;
              DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
              DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
              DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
              DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
              DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
              DMA_InitStructure.DMA_Priority = DMA_Priority_High;
              DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    
    #if 1
      DMA_Init(DMA2_Channel3, &DMA_InitStructure);
      /* Enable DMA2 Channel3 */
      DMA_Cmd(DMA2_Channel3, ENABLE);
    #else
      DMA_Init(DMA1_Channel3, &DMA_InitStructure);
      /* Enable DMA1 Channel3 */
      DMA_Cmd(DMA1_Channel3, ENABLE);
    #endif
            
            
            // Enable DAC Channel1 
            DAC_Cmd(DAC_Channel_1, ENABLE);
          
            
            DAC_DMACmd(DAC_Channel_1, ENABLE);
            
      
            // TIM8 enable counter
            TIM_Cmd(TIM6, ENABLE);
           
    while(1);
    
    }
    
    
    // 根据采样率获得定时器自动  
    // 摘自waveplayer.c  
    u16 GetARRValue(u16 sample)  
    {  
        u16 arrValue;  
        //更新OCA值以符合.WAV文件采样率 
        switch (sample)  
        {  
        case SAMPLE_RATE_8000 :  
            arrValue = (u16)(72000000/8000);  
            break; // 8KHz = 2x36MHz / 9000   
        case SAMPLE_RATE_11025:  
            arrValue = (u16)(72000000/11025);  
            break; // 11.025KHz = 2x36MHz / 6531  
        case SAMPLE_RATE_16000:  
             arrValue = (u16)(72000000/16000);  
            break; // 16KHz = 2x36MHz / 4500   
        case SAMPLE_RATE_22050:  
            arrValue = (u16)(72000000/22050);  
            break; // 22.05KHz = 2x36MHz / 2365   
        case SAMPLE_RATE_44100:  
            arrValue = (u16)(72000000/44100);  
            break; // 44.1KHz = 2x36MHz / 1633   
        case SAMPLE_RATE_48000:  
            arrValue = (u16)(72000000/48000);  
            break; // 48KHz = 2x36MHz / 1500   
        default:  
            arrValue = 0;  
            break;  
        }  
        return arrValue;  
    } 
    
    

    上面是 双通道,单通道的DAC 音频输出
    需要注意的是数据,一定要是wave的格式, 下面就有检测wave格式是否正确的代码

    /** @defgroup WAVEPLAYER_Private_Defines
      * @{
      */
    #define  CHUNK_ID                            0x52494646  /* correspond to the letters 'RIFF' */
    #define  FILE_FORMAT                         0x57415645  /* correspond to the letters 'WAVE' */
    #define  FORMAT_ID                           0x666D7420  /* correspond to the letters 'fmt ' */
    #define  DATA_ID                             0x64617461  /* correspond to the letters 'data' */
    #define  FACT_ID                             0x66616374  /* correspond to the letters 'fact' */
    #define  WAVE_FORMAT_PCM                     0x01
    #define  FORMAT_CHNUK_SIZE                   0x10
    #define  CHANNEL_MONO                        0x01
    #define  SAMPLE_RATE_8000                    8000
    #define  SAMPLE_RATE_11025                   11025
    #define  SAMPLE_RATE_22050                   22050
    #define  SAMPLE_RATE_44100                   44100
    #define  BITS_PER_SAMPLE_8                   8
    #define  WAVE_DUMMY_BYTE                     0xA5
    #define  DAC_DHLCD_REG_8LCD_REG_1_ADDRESS    0x40007410
    
    
    
    
    static ErrorCode WavePlayer_WaveParsing()
    {
      uint32_t Temp = 0x00;
      uint32_t ExtraFormatBytes = 0;
      __IO uint32_t err = 0;
    
    
      memcpy(Wavebuffer,0,20250-1);//在这里固定了数组,实际中再用其他的buffer
      memcpy(Wavebuffer,thx,20222);
      
      // Read chunkID, must be 'RIFF'  ----------------------------------------------
      Temp = ReadUnit(Wavebuffer, 0, 4, BigEndian);
      if (Temp != CHUNK_ID)
      {
        return(Unvalid_RIFF_ID);
      }
    
      // Read the file length ----------------------------------------------------
      WAVE_Format.RIFFchunksize = ReadUnit(Wavebuffer, 4, 4, LittleEndian);
    
      // Read the file format, must be 'WAVE' ------------------------------------
      Temp = ReadUnit(Wavebuffer, 8, 4, BigEndian);
      if (Temp != FILE_FORMAT)
      {
        return(Unvalid_WAVE_Format);
      }
    
      // Read the format chunk, must be'fmt ' --------------------------------------
      Temp = ReadUnit(Wavebuffer, 12, 4, BigEndian);
      if (Temp != FORMAT_ID)
      {
        return(Unvalid_FormatChunk_ID);
      }
      // Read the length of the 'fmt' data, must be 0x10 -------------------------
      Temp = ReadUnit(Wavebuffer, 16, 4, LittleEndian);
      if (Temp != 0x10)
      {
        ExtraFormatBytes = 1;
      }
      // Read the audio format, must be 0x01 (PCM) -------------------------------
      WAVE_Format.FormatTag = ReadUnit(Wavebuffer, 20, 2, LittleEndian);
      if (WAVE_Format.FormatTag != WAVE_FORMAT_PCM)
      {
        return(Unsupporetd_FormatTag);
      }
    
      // Read the number of channels, must be 0x01 (Mono) ------------------------
      WAVE_Format.NumChannels = ReadUnit(Wavebuffer, 22, 2, LittleEndian);
      if (WAVE_Format.NumChannels != CHANNEL_MONO)
      {
        return(Unsupporetd_Number_Of_Channel);
      }
    
      // Read the Sample Rate ----------------------------------------------------
      WAVE_Format.SampleRate = ReadUnit(Wavebuffer, 24, 4, LittleEndian);
      // Update the OCA value according to the .WAV file Sample Rate 
      switch (WAVE_Format.SampleRate)
      {
        case SAMPLE_RATE_8000 :
          TIM6ARRValue = 4500;
          break; // 8KHz = 36MHz / 4500
        case SAMPLE_RATE_11025:
          TIM6ARRValue = 3265;
          break; // 11.025KHz = 36MHz / 3265
        case SAMPLE_RATE_22050:
          TIM6ARRValue = 1632;
          break; // 22.05KHz = 36MHz / 1632
        case SAMPLE_RATE_44100:
          TIM6ARRValue = 816;
          break; // 44.1KHz = 36MHz / 816
        default:
          return(Unsupporetd_Sample_Rate);
      }
    
      // Read the Byte Rate ------------------------------------------------------
      WAVE_Format.ByteRate = ReadUnit(Wavebuffer, 28, 4, LittleEndian);
    
      // Read the block alignment ------------------------------------------------
      WAVE_Format.BlockAlign = ReadUnit(Wavebuffer, 32, 2, LittleEndian);
    
      // Read the number of bits per sample --------------------------------------
      WAVE_Format.BitsPerSample = ReadUnit(Wavebuffer, 34, 2, LittleEndian);
      if (WAVE_Format.BitsPerSample != BITS_PER_SAMPLE_8)
      {
        return(Unsupporetd_Bits_Per_Sample);
      }
      SpeechDataOffset = 36;
      // If there is Extra format bytes, these bytes will be defined in "Fact Chunk" 
      if (ExtraFormatBytes == 1)
      {
        // Read th Extra format bytes, must be 0x00 ------------------------------
        Temp = ReadUnit(Wavebuffer, 36, 2, LittleEndian);
        if (Temp != 0x00)
        {
          return(Unsupporetd_ExtraFormatBytes);
        }
        // Read the Fact chunk, must be 'fact' -----------------------------------
        Temp = ReadUnit(Wavebuffer, 38, 4, BigEndian);
        if (Temp != FACT_ID)
        {
          return(Unvalid_FactChunk_ID);
        }
        // Read Fact chunk data Size ---------------------------------------------
        Temp = ReadUnit(Wavebuffer, 42, 4, LittleEndian);
    
        SpeechDataOffset += 10 + Temp;
      }
      // Read the Data chunk, must be 'data' ---------------------------------------
      Temp = ReadUnit(Wavebuffer, SpeechDataOffset, 4, BigEndian);
      SpeechDataOffset += 4;
      if (Temp != DATA_ID)
      {
        return(Unvalid_DataChunk_ID);
      }
    
      // Read the number of sample data ------------------------------------------
      WAVE_Format.DataSize = ReadUnit(Wavebuffer, SpeechDataOffset, 4, LittleEndian);
      SpeechDataOffset += 4;
      wavecounter =  SpeechDataOffset;
      return(Valid_WAVE_File);
    }
    

    在处理wave 音频数据的时候

    实际数据20222 byte
    RIFFchunksize 是20214

    Read the number of sample data 20108 (SpeechDataOffset为44 )

    前面offset 是44, 而总sample data 是20108,

    20222 -44 -20108 = 70

    70就是不要的数据尾, 为了DAC 不发出杂音(爆音是接近 0或255的曲线, 128是中音)

    实际处理数据的时候 前offset +44, 后offset -(114 -44) 就可以了

    这样就没有爆音了,哈哈

  • 相关阅读:
    SQL Server 存储过程中处理多个查询条件的几种常见写法分析,我们该用那种写法
    转:SqlServer2012自增列值突然增大1000的原因及解决方法
    sql server 自增列,值突然增大1000的情况
    C# 复制数组容易踩到的坑--引用类型与值类型
    sql中的表值函数与标量值函数区别与用法
    Swift4.0复习循环
    获取视频第一帧图片
    UITableView实现行纵向颜色渐变
    iOS点击按钮第二次不能旋转View
    iOS扩大按钮的点击范围
  • 原文地址:https://www.cnblogs.com/scotth/p/4584379.html
Copyright © 2011-2022 走看看