• STM32F407ADC多通道+定时器触发+DMA模式设置


    #include "adc.h"
    
    /* 数据定义 */
    u8 UpdataTIM = 0;        //更新TIM2定时器标志
    u16 CurrentFreq = 500;//默认市电频率,单位为0.1hz
    ADBASE_TYPE uAD_Buff_A[ADC_CHANNEL];        //ADC采集缓存A
    ADBASE_TYPE uAD_Buff_B[ADC_CHANNEL];        //ADC采集缓存B
    //考虑到可能出现的数据处理时间较长的问题,临时添加缓存
    //u16 uAD_IN_BUFF[ADC_BUFFSIZE][ADC_CHANNEL];
    ADBASE_TYPE *CurrentBuffPtr = NULL;        //当前缓存指针
    /*
     * Function    : static void ADCInit_GPIO(void)
     * Description : ADCGPIO初始化
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */
    static void ADCInit_GPIO(void)
    {
        GPIO_InitTypeDef  GPIO_InitStructure;
    
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟
    
        //ADC通道初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|  
                                        GPIO_Pin_9|GPIO_Pin_10; //PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10 ADC通道
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;  //模拟输入
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  //不带上下拉
        GPIO_Init(GPIOF, &GPIO_InitStructure);  //初始化     
    }
    /*
     * Function    : static void ADCInit_ADC(void)
     * Description : ADC模式初始化
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */
    static void ADCInit_ADC(void)
    {
        ADC_CommonInitTypeDef ADC_CommonInitStructure;
        ADC_InitTypeDef       ADC_InitStructure;
        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); //使能ADC3时钟
        
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,ENABLE);      //ADC3复位
        RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,DISABLE); //复位结束     
    
        ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
        ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //两个采样阶段之间的延迟5个时钟(三重模式或双重模式下使用)
        ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能(对于多个ADC模式)
        ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
        ADC_CommonInit(&ADC_CommonInitStructure);//初始化
        
        ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
        ADC_InitStructure.ADC_ScanConvMode = ENABLE;//扫描模式(多通道ADC采集要用扫描模式)    
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
    //    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //软件触发
        ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; //上升沿触发
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;  //定时器事件2触发ADC
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐    
        ADC_InitStructure.ADC_NbrOfConversion = ADC_CHANNEL;    //8个转换在规则序列中
        ADC_Init(ADC3, &ADC_InitStructure);//ADC初始化
        
        //连续模式下,通道的配置
        ADC_RegularChannelConfig(ADC3, ADC_Channel_9, 1, ADC_SampleTime_15Cycles);  //PF3,VIN1,通道9,UA,rank=1,表示连续转换中第一个转换的通道,采样时间15个周期(如果数据不稳定可以延时采样时间)
        ADC_RegularChannelConfig(ADC3, ADC_Channel_14, 2, ADC_SampleTime_15Cycles); //PF4,VIN2,通道14,UB
        ADC_RegularChannelConfig(ADC3, ADC_Channel_15, 3, ADC_SampleTime_15Cycles); //PF5,VIN3,通道15,AC220
        ADC_RegularChannelConfig(ADC3, ADC_Channel_4, 4, ADC_SampleTime_15Cycles);     //PF6,VIN4,通道4,I0
        ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 5, ADC_SampleTime_15Cycles);     //PF7,VIN5,通道5,IA
        ADC_RegularChannelConfig(ADC3, ADC_Channel_6, 6, ADC_SampleTime_15Cycles);     //PF8,VIN6,通道6,IB
        ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 7, ADC_SampleTime_15Cycles);     //PF9,VIN7,通道7,IC
        ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 8, ADC_SampleTime_15Cycles);     //PF10,VIN8,通道8,暂时未接入信号
    
        ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); //连续使能DMA
        ADC_DMACmd(ADC3, ENABLE);  //使能ADC_DMA
        ADC_Cmd(ADC3, ENABLE);//开启AD转换器    
    }
    /*
     * Function    : static void ADCInit_DMA(void)
     * Description : ADC使能DMA模式
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */
    static void ADCInit_DMA(void)
    {
        DMA_InitTypeDef  DMA_InitStructure;
        
        //时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
        
        //DMA设置
        DMA_InitStructure.DMA_Channel = DMA_Channel_2; //选择通道号
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC3->DR); //外围设备地址,ADC_DR_DATA规则数据寄存器
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(u16 *)uAD_Buff_A; //DMA存储器地址,自己设置的缓存地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //传输方向,外设->存储器
        DMA_InitStructure.DMA_BufferSize = ADC_BUFFSIZE * ADC_CHANNEL; //DMA缓存大小,数据传输量32*8
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设是否为增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器是否为增量模式
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据长度半个字(16位)
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据长度半字(16位)
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA模式,普通模式、循环模式,还有双缓冲模式,需要特殊设置
        DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA优先级,高优先级
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不使用FIFO
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; //FIFO阈值
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发,单次传输
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发,单次传输
        DMA_Init(DMA2_Stream0, &DMA_InitStructure); //初始化DMA2_Stream0,对应为ADC3
    
        //双缓冲模式设置
        DMA_DoubleBufferModeConfig(DMA2_Stream0,(uint32_t)(u16 *)(uAD_Buff_B),DMA_Memory_0);    //DMA_Memory_0首先被传输
        DMA_DoubleBufferModeCmd(DMA2_Stream0,ENABLE);
        
        //设置DMA中断
        DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC); //清除中断标志   
        DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE); //传输完成中断                                       
        DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA
        
    }
    /*
     * Function    : void ADCInit_Timer(void)
     * Description : ADC触发定时器的设置
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */
    void ADCInit_Timer(void)
    {
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    
        //时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);          
    
        //失能定时器
        TIM_Cmd(TIM2, DISABLE);
        TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); //初始化定时器
        
        //定时器设置,T=(84 * 625) / 84M = 625us = 20ms/32,50Hz信号,每周期采样32个点,采样频率1600
        TIM_TimeBaseStructure.TIM_Prescaler = 84-1; //分频系数,TIM2时钟在分频系数不为1时,时钟是APB1时钟的两倍84M
        TIM_TimeBaseStructure.TIM_Period = 312500/CurrentFreq - 1; //周期值1M/32=31250,CurrentFreq单位为0.1hz,因此需扩大10倍
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频因子
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up ; //向上计数模式
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器2
        
        //使能定时器中断    
        TIM_ARRPreloadConfig(TIM2, ENABLE); //允许TIM2定时重载
        TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);  //选择TIM2的UPDATA事件更新为触发源
    //    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //配置TIM2中断类型
        
        //使能TIM2
        TIM_Cmd(TIM2, ENABLE); 
        DebugLog("Enable TIM2, Set frequency is %d.", CurrentFreq);
    }
    /*
     * Function    : void ADCInit_Nvic(void)
     * Description : 中断初始化
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */
    static void ADCInit_Nvic(void)
    {
        NVIC_InitTypeDef NVIC_InitStructure;
        
        //定时器中断设置
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //定时器TIM2中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  //抢占优先级0
        NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;        //子优先级1
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化NVIC寄存器    
        
        //DMA中断设置
        NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;  //DMA2_Stream0中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;  //抢占优先级1
        NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;        //子优先级1
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);    //根据指定的参数初始化NVIC寄存器    
    }
    /*
     * Function    : void  ADCInit(void)
     * Description : ADC初始化函
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */                                                           
    void ADCInit(void)
    {
        ADCInit_GPIO();
        ADCInit_DMA();
        ADCInit_ADC();
        ADCInit_Nvic();
        DebugLog("ADC Init is finish.");
    }    
    /*
     * Function    : void TIM2_IRQHandler(void) 
     * Description : TIM2中断触发函数
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */
    void TIM2_IRQHandler(void)  
    {
      OSIntEnter(); //进入中断    
        
        if(TIM_GetITStatus(TIM2, TIM_IT_Update))  //判断发生update事件中断  
        {         
            TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除update事件中断标志
    //    ADC_SoftwareStartConv(ADC1);      
        }
        
        OSIntExit();  //退出中断  
    }
    /*
     * Function    : void DMA2_Stream0_IRQHandler(void) 
     * Description : DMA2_Stream0中断
     * Arguments   : 无
     * Returns     : 无
     * Other       :
     */
    void DMA2_Stream0_IRQHandler(void)  
    {
        u16 period = 0;
        
      OSIntEnter(); //进入中断 
        if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))  //判断DMA传输完成中断  
        {
             DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
    //         DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA,连续模式下不需要该使能
             //数据转移程序
             if(DMA_GetCurrentMemoryTarget(DMA2_Stream0) == DMA_Memory_0)
             {
                 CurrentBuffPtr = uAD_Buff_A;
             }
             else
             {
                 CurrentBuffPtr = uAD_Buff_B;
             }
             //遥测任务等待该信号量
             OSSemPost(SemAD);
             
             //判断是否更新TIM2
             if(UpdataTIM)
             {
                 period = 312500/CurrentFreq - 1;        //计算采样频率1M/32=31250;32为采样点数,31250/freq=采样周期
                 TIM_ARRPreloadConfig(TIM2, DISABLE); //关闭TIM2定时重载
                 TIM2->ARR = period ;        //更新定时器周期
                 TIM_ARRPreloadConfig(TIM2, ENABLE);     //打开TIM2定时重载
             }
        }
        OSIntExit();  //退出中断  
    }

    另外还是双缓存机制,代码已经注释的很清楚了,以后有问题了可以再回过头来看看。

  • 相关阅读:
    TCP/IP的基本概念知识
    Mysql查询今天、昨天、7天、近30天、本月、上一月数据
    PHP OOP面向对象部分方法归总(代码实例子)
    PHP 变量
    PHP超级全局变量、魔术变量和魔术函数
    PHP编程效率的20个要点
    MemCache超详细解读
    CodeForces 652E Pursuit For Artifacts 边双连通分量
    HDU 2460 Network 边双连通分量 缩点
    HDU 3594 Cactus 有向仙人掌图判定
  • 原文地址:https://www.cnblogs.com/longbiao831/p/6688006.html
Copyright © 2020-2023  润新知