STM32通過TIM,ADC,DMA的配合使用實現雙通道數據採樣

第一次寫博客,奉獻給STM32了,一直以來都是潛水看博客,希望能夠自己也能寫一點東西,對自己學習和工作的一個總結,希望能夠堅持下去。

項目背景:以57.6kbps的速率採集兩個通道的數據
芯片:STM32F205VCT6
總體的思路通過57.6kHz的定時器去觸發ADC採樣,採樣後的數據在通過DMA存放於緩衝區定時產生中斷。
由於需要產生57.6KHz的頻率,晶振選擇9.6MKHz,CPU主頻爲115.2MHz。
STEP1:配置定時器
通過TIM2去觸發兩路ADC,詳見配置如下

void TIM2_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd ( RCC_APB1Periph_TIM2 , ENABLE );

    TIM_DeInit ( TIM2 );

    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_Period        = (57600000/(ADC_SAMPLING_MUL*AIS_MODUL_RATE) - 1 );    //28.8M*2/100/10 = 57.6kHz
    TIM_TimeBaseStructure.TIM_Prescaler     = ( 1 - 1 );//28.8M*2 = 57.6MHz
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
    TIM_TimeBaseInit ( TIM2, &TIM_TimeBaseStructure );

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
    //TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE); //開定時器中斷測試使用

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);
   // TIM_ITConfig(TIM2,TIM_IT_CC3,ENABLE); //開定時器中斷測試使用

    TIM_Cmd ( TIM2, ENABLE );
    TIM_InternalClockConfig(TIM2);
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Enable);
    TIM_UpdateDisableConfig(TIM2, DISABLE);
}

STEP2:配置ADC
首先需要配置GPIO複用

//GPIO -PB0 PB1 -ADC1 ADC2
    GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd    = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init ( GPIOB, &GPIO_InitStructure );

然後配置ADC

void ADC_Configuration(void)
{                                       
    ADC_InitTypeDef       ADC_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 , ENABLE);

//ADC Common Init 
    ADC_CommonInitStructure.ADC_Mode                = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Prescaler           = ADC_Prescaler_Div4;
    ADC_CommonInitStructure.ADC_DMAAccessMode       = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay    = ADC_TwoSamplingDelay_20Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);

//ADC1 Init
    ADC_InitStructure.ADC_Resolution                = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode              = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode        = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge      = ADC_ExternalTrigConvEdge_Rising;
    ADC_InitStructure.ADC_ExternalTrigConv          = ADC_ExternalTrigConv_T2_CC2;
    ADC_InitStructure.ADC_DataAlign                 = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion           = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

// ADC1 regular channel 8 configuration
    ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_144Cycles);

//Enable DMA request after last transfer (Single-ADC mode) 
    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

//Enable ADC1 DMA 
    ADC_DMACmd(ADC1, ENABLE);
// Enable ADC1 
    ADC_Cmd(ADC1, ENABLE);  

// ADC2 Init 
    ADC_InitStructure.ADC_Resolution                = ADC_Resolution_12b;
    ADC_InitStructure.ADC_ScanConvMode              = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode        = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge      = ADC_ExternalTrigConvEdge_Rising;
    ADC_InitStructure.ADC_ExternalTrigConv          = ADC_ExternalTrigConv_T2_CC3;
    ADC_InitStructure.ADC_DataAlign                 = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion           = 1;
    ADC_Init(ADC2, &ADC_InitStructure);

// ADC2 regular channel 9 configuration 
    ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 1, ADC_SampleTime_144Cycles);

// Enable DMA request after last transfer (Single-ADC mode) 
    ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);

// Enable ADC2 DMA 
    ADC_DMACmd(ADC2, ENABLE);

// Enable ADC2 
    ADC_Cmd(ADC2, ENABLE);
}

STEP3 配置DMA
首先定義DMA中斷標誌和緩衝區的定義,其中DMA採用乒乓BUF的方式存儲和讀取數據。

#define DMA_ADC_BUF_BIT                         = 96 //該數據定義了多長時間產生一次DMA中斷
Uint8   Dma2Stream0Flag                         = 0;//ADC1    接收    數據標誌位1--表示有數據 0--表示無數據
Uint8   Dma2Stream2Flag                         = 0;//ADC2    接收    數據標誌位1--表示有數據 0--表示無數據
Uint16  Adc1Buf0[DMA_ADC_BUF_BIT]               = {0};//ADC1接收緩存區0
Uint16  Adc1Buf1[DMA_ADC_BUF_BIT]               = {0};//ADC1接收緩存區1
Uint16  Adc2Buf0[DMA_ADC_BUF_BIT]               = {0};//ADC2接收緩存區0
Uint16  Adc2Buf1[DMA_ADC_BUF_BIT]               = {0};//ADC2接收緩存區1

然後對DMA進行參數配置

void DMA2_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

//DMA2 Stream0 channel0 configuration------ADC1
    DMA_InitStructure.DMA_Channel               = DMA_Channel_0;  
    DMA_InitStructure.DMA_PeripheralBaseAddr    = (Uint32)&ADC1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr       = (Uint32)Adc1Buf0;
    DMA_InitStructure.DMA_DIR                   = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize            = DMA_ADC_BUF_BIT;
    DMA_InitStructure.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc             = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize        = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode                  = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority              = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode              = DMA_FIFOMode_Enable;         
    DMA_InitStructure.DMA_FIFOThreshold         = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst           = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst       = DMA_PeripheralBurst_Single;

//DMA double buffer mode
    DMA_DoubleBufferModeConfig(DMA2_Stream0,(Uint32)Adc1Buf1,DMA_Memory_0);//DMA_Memory_0首先被傳輸
    DMA_DoubleBufferModeCmd(DMA2_Stream0,ENABLE);
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);

    DMA_ITConfig( DMA2_Stream0, DMA_IT_TC, ENABLE );
    DMA_ClearITPendingBit ( DMA2_Stream0, DMA_IT_TCIF0 );

    DMA_Cmd(DMA2_Stream0, ENABLE);

//DMA2 Stream2 channel1 configuration------ADC2
    DMA_InitStructure.DMA_Channel               = DMA_Channel_1;  
    DMA_InitStructure.DMA_PeripheralBaseAddr    = (Uint32)&ADC2->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr       = (Uint32)Adc2Buf0;
    DMA_InitStructure.DMA_DIR                   = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize            = DMA_ADC_BUF_BIT;
    DMA_InitStructure.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc             = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize        = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode                  = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority              = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode              = DMA_FIFOMode_Enable;         
    DMA_InitStructure.DMA_FIFOThreshold         = DMA_FIFOThreshold_Full;
    DMA_InitStructure.DMA_MemoryBurst           = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst       = DMA_PeripheralBurst_Single;
    DMA_DoubleBufferModeConfig(DMA2_Stream2,(Uint32)Adc2Buf1,DMA_Memory_0);//DMA_Memory_0首先被傳輸
    DMA_DoubleBufferModeCmd(DMA2_Stream2,ENABLE);
    DMA_Init(DMA2_Stream2, &DMA_InitStructure);

    DMA_ITConfig( DMA2_Stream2, DMA_IT_TC, ENABLE );
    DMA_ClearITPendingBit ( DMA2_Stream2, DMA_IT_TCIF2 );

    DMA_Cmd(DMA2_Stream2, ENABLE);      
}

最後再去定義DMA的中斷優先級,中斷入口函數以及數據的使用

void NVIC_Configuration ( void )
{
    NVIC_InitTypeDef    NVIC_InitStructure;

    NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 );

    NVIC_InitStructure.NVIC_IRQChannel                      = DMA2_Stream0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel                      = DMA2_Stream2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority    = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority           = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd                   = ENABLE;
    NVIC_Init(&NVIC_InitStructure);     
}

void DMA2_Stream0_IRQHandler( void )
{
    if( DMA_GetITStatus( DMA2_Stream0, DMA_IT_TCIF0 ) != RESET )
    {
        DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
        Dma2Stream0Flag  = 1;
    }
}

void DMA2_Stream2_IRQHandler( void )
{
    if( DMA_GetITStatus( DMA2_Stream2, DMA_IT_TCIF2 ) != RESET )
    {
        DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);
        Dma2Stream2Flag  = 1;
    }
}

void RECV_Schedule( void )
{
    Uint16  i                           = 0;
    Uint16  j                           = 0;
    Uint16   Din[DMA_ADC_BUF_BIT]       = {0};

//處理ADC1採樣通道A的數據
    if( Dma2Stream0Flag == 1 )
    {
        Dma2Stream0Flag = 0;

        if( DMA_GetCurrentMemoryTarget(DMA2_Stream0) == DMA_MEMORY_NO_0 )
        {            
            for( i = 0; i < DMA_ADC_BUF_BIT; i++ )
            {
                Din[i] = Adc1Buf1[i];
            }
        }
        else
        {            
            for( i = 0; i < DMA_ADC_BUF_BIT; i++ )
            {
                Din[i] = Adc1Buf0[i];
            }
        }
    }

//處理ADC2採樣通道B的數據
    if( Dma2Stream2Flag == 1 )
    {
        Dma2Stream2Flag = 0;
        if( DMA_GetCurrentMemoryTarget(DMA2_Stream2) == DMA_MEMORY_NO_0 )
        {
            for( i = 0; i < DMA_ADC_BUF_BIT; i++ )
            {
                Din[i] = Adc2Buf1[i];
            }
        }
        else
        {        
            for( i = 0; i < DMA_ADC_BUF_BIT; i++ )
            {
                Din[i] = Adc2Buf0[i];
            }
        }      
    }
}

至此,第一篇博客完成了,寫的好粗糙,編輯工具也不會~~~~~~~~還是要多寫些~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章