STM32F407定时采样模拟量的ADC DMA定时器配置指南

STM32F407 ADC+DMA+定时器 定时采样模拟量

文章目录

  • STM32F407 ADC+DMA+定时器 定时采样模拟量
  • 前言
  • 一、硬件原理
  • 1.1 ADC
  • 1.2 定时器
  • 3. DMA
  • 二、代码实现
  • 2.1初始化
  • 2.1.1 PIN initial
  • 2.2 ADC 初始化 代码
  • 2.3 DMA 初始化 代码
  • 3.1 定时器初始化
  • 3.2 函数调用
  • 总结

  • 前言

    项目中需要对多个通道的电压进行一定频率的AD采样,由于采样过程贯穿整个任务,为了使采样过程尽可能不占用CPU资源,采用定时器触发的多通道ADC扫描采样,且采样数据由DMA传到RAM中的缓存。
    这样做有以下几个好处:1、由定时器触发ADC采样,这样采样的频率可控,且定时器触发不会占用任何CPU资源;2、DMA进一步降低了任务对CPU的占有率。


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、硬件原理

    1.1 ADC

    STM32F 407的ADC的规则通道扫描采样,配置好规则通道后,可以采用软件触发的方式开启AD转换,也可通过外部触发,如下图所示。可以通过定时器以及外部中断方式触发:
    如下图为ADC 内部使用框图:

    1.2 定时器


    如上图所示是定时器的内部硬件原理框图,在此使用定时器的TIMER3 的TRGO信号作为ADC转换的触发信号,当接收到一次中断信号后,ADC通道进行转换一次.

    3. DMA


    如上图所示,ADC1 使用的是DMA 的stream0 数据流,ADC2使用DMA2 的Stream2数据流.

    二、代码实现

    2.1初始化

    global 数据

    __IO uint16_t g_Adc2ConvertedValues[10][6];//6 个通道每个通道采样10次
    

    2.1.1 PIN initial

    	static void BspGpioConfig(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_0    
                                       | GPIO_Pin_4   
                                       | GPIO_Pin_7;  
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0  
                                     | GPIO_Pin_1;  
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0    
                                     | GPIO_Pin_1 ; 
    
        GPIO_Init(GPIOC, &GPIO_InitStructure);
    
        return;
    }
    
    

    2.2 ADC 初始化 代码

    static void BspAdcConfig(void)
    {
        ADC_CommonInitTypeDef ADC_CommonInitStructure;
        ADC_InitTypeDef       ADC_InitStructure;
    
        ADC_CommonInitStructure.ADC_Mode             = ADC_Mode_Independent;
        ADC_CommonInitStructure.ADC_Prescaler        = ADC_Prescaler_Div8;
        ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_Disabled;
        ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
        ADC_CommonInit(&ADC_CommonInitStructure);
    
        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_TRGO;
        ADC_InitStructure.ADC_DataAlign            = ADC_DataAlign_Right;
        ADC_InitStructure.ADC_NbrOfConversion      = 1;
        ADC_Init(ADC1, &ADC_InitStructure);
    
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_480Cycles);     // PA0_AD0_AC
    
        ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
        ADC_DMACmd(ADC1, ENABLE);
        ADC_Cmd(ADC1, ENABLE);
    
        ADC_InitStructure.ADC_ScanConvMode         = ENABLE;
        ADC_InitStructure.ADC_ExternalTrigConv     = ADC_ExternalTrigConv_T3_TRGO;
        ADC_InitStructure.ADC_NbrOfConversion      = ADC2_NbrofChannel;
        ADC_Init(ADC2, &ADC_InitStructure);
    
    
        ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 1, ADC_SampleTime_480Cycles);     // PA4_AD4_24V_2
        ADC_RegularChannelConfig(ADC2, ADC_Channel_7, 2, ADC_SampleTime_480Cycles);     // PA7_AD7_GNDF
        ADC_RegularChannelConfig(ADC2, ADC_Channel_8, 3, ADC_SampleTime_480Cycles);     // PB0_AD8_24V_OCP_C1
        ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 4, ADC_SampleTime_480Cycles);     // PB1_AD9_24V_OCP_C2
        ADC_RegularChannelConfig(ADC2, ADC_Channel_10,5, ADC_SampleTime_480Cycles);     // PC0_AD10_HOUSING
        ADC_RegularChannelConfig(ADC2, ADC_Channel_11,6, ADC_SampleTime_480Cycles);     // PC1_AD11_24V_1
    
        ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
        ADC_DMACmd(ADC2, ENABLE);
        ADC_Cmd(ADC2, ENABLE);
    
        return;
    }
    

    2.3 DMA 初始化 代码

    
    static void BspDmaConfig(void)
    {
        DMA_InitTypeDef DMA_InitStructure;
    
        DMA_InitStructure.DMA_Channel            = DMA_Channel_0;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
        DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&g_Adc1ConvertedValues;
        DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralToMemory;
        DMA_InitStructure.DMA_BufferSize         = 1024 * 2;
        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_Disable;
        DMA_InitStructure.DMA_FIFOThreshold      = DMA_FIFOThreshold_HalfFull;
        DMA_InitStructure.DMA_MemoryBurst        = DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_PeripheralBurst    = DMA_PeripheralBurst_Single;
        DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    
        DMA_ITConfig(DMA2_Stream0, DMA_IT_HT | DMA_IT_TC, ENABLE);
        DMA_Cmd(DMA2_Stream0, ENABLE);
    
        DMA_InitStructure.DMA_Channel            = DMA_Channel_1;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR;
        DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&g_Adc2ConvertedValues;
        DMA_InitStructure.DMA_BufferSize         = ADC2_NbrofChannel * SamplingNumber;//N*M N: channel number M:sampling number
        DMA_Init(DMA2_Stream2, &DMA_InitStructure);
    
        DMA_Cmd(DMA2_Stream2, ENABLE);
    
        return;
    }
    
    static void BspNvicConfig(void)
    {
        NVIC_InitTypeDef NVIC_InitStructure;
    
        NVIC_InitStructure.NVIC_IRQChannel                   = DMA2_Stream0_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    
        return;
    }
    

    在调用这几个函数之前必须设置RCC时钟如下代码设置RCC时钟:

    static void BspRccConfig(void)
    {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA
                             | RCC_AHB1Periph_GPIOB
                             | RCC_AHB1Periph_GPIOC
                             | RCC_AHB1Periph_DMA2, ENABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2
                             | RCC_APB1Periph_TIM3, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1
                             | RCC_APB2Periph_ADC2, ENABLE);
    
        return;
    }
    

    3.1 定时器初始化

    static void BspTimConfig(void)
    {
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    
        // TIM2设置ADC1  1024Hz
        TIM_TimeBaseStructure.TIM_Prescaler     = 0;
        TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_Period        = 84000000 / 1024 - 1;
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    
        TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
    
        // TIM3设置ADC2 1000Hz
        TIM_TimeBaseStructure.TIM_Prescaler     = 84000000 / 1000000 - 1;
        TIM_TimeBaseStructure.TIM_Period        = 1000000 / 1000 - 1;
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
    
        TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
    
        TIM_Cmd(TIM2, ENABLE);
        TIM_Cmd(TIM3, ENABLE);
    
        return;
    }
    

    3.2 函数调用

    void BspAdcInit(void)
    {
        BspRccConfig();
        BspGpioConfig();
        BspAdcConfig();
        BspDmaConfig();
        BspNvicConfig();
        BspTimConfig();
        return;
    }
    

    在调用BspAdcInit()函数后,就配置完成了ADC+DMA+TIMER的配置.会定时完成采集,且不占用CPU资源.采集的数据将会自动存储在定义的g_Adc2ConvertedValues 全局变量中.

    总结

    以上流程就是使用STM32的ADC+DMA+timer实现自动定时采样模拟电压的配置使用流程,若读者发先任何疑问,妄指出问题…

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32F407定时采样模拟量的ADC DMA定时器配置指南

    发表评论