定时器+ADC+DMA DMA传输ADC的数据一直为0

2019-07-20 21:51发布

#include "sys.h"
#include "adc.h"
#include "delay.h"

   
#define     ADC1_DR_Address     ((uint32_t)ADC1_BASE+0x4c)
__IO uint16_t ADC1OscConver[10]={0};

void DMA2_Init(void)
{
      DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef        NVIC_InitStructure;
    //打开DMA2的时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
        //初始化个寄存器的配置
    DMA_DeInit(DMA2_Stream0);
    DMA_StructInit( &DMA_InitStructure);
     //选取DMA通道0,数据流0
    DMA_InitStructure.DMA_Channel=DMA_Channel_0;
        //设置外设的基地址
    DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)ADC1_DR_Address;
    //设置内存的地址
    DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t)&ADC1OscConver;
    //设置数据从外设传到内存
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;
        //设置每次传送的数据量1000
    DMA_InitStructure.DMA_BufferSize=10;
        //外设地址不变
    DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
        //内存地址每次加1
    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;
        //这里不用FIFO模式
    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;
        
        //将以上应用于数据流0和通道0
    DMA_Init(DMA2_Stream0,&DMA_InitStructure);
        
        
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        //选择DMA2数据流0通道0
        NVIC_InitStructure.NVIC_IRQChannel=DMA2_Stream0_IRQn;
        //抢占式优先级
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
        //响应式优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=4;
        //通道使能
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
        //将以上配置应用于NVIC
        NVIC_Init(&NVIC_InitStructure);
        //使能DMA传输中断
        DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);
        
        //使能DMA
    DMA_Cmd(DMA2_Stream0, ENABLE);
}

//time2定时器的配置
void Tim2Config(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    //打开time2的时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
   
    TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStruct.TIM_Prescaler=42-1;
    TIM_TimeBaseInitStruct.TIM_Period=44;
    TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
   
    //使用更新事件作为触发
    TIM_SelectOutputTrigger(TIM2,TIM_TRGOSource_Update);
   
   
    TIM_Cmd(TIM2,ENABLE); //使能定时器
}

//初始化ADC
//初始化规则通道

void Adc_Init(void)
{
    //先配置IO口 使用ADC1 通道5
    GPIO_InitTypeDef GPIO_InitStruct;
    ADC_CommonInitTypeDef ADC_CommonInitStruct;
    ADC_InitTypeDef ADC_InitStruct;
   
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);  //使能ADC1的时钟
   
    //先初始化ADC1通道5的IO
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;  //PA5 ADC1 通道5
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AN; //模拟输入
    GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL; //不带上下拉
    GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化
   
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE); //ADC1复位
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);//复位结束
   
    //初始化ADC的通用设置
   
    //设置ADC为独立模式
    ADC_CommonInitStruct.ADC_Mode=ADC_Mode_Independent;
    //两个采样阶段之间延时5个时钟
    ADC_CommonInitStruct.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;
    //DMA失能
    ADC_CommonInitStruct.ADC_DMAAccessMode=ADC_DMAAccessMode_1;
    //设置ADC预分频为4分频
  //这里分频以后要小于36MHZ,而4分频后频率为21MHZ   
    ADC_CommonInitStruct.ADC_Prescaler=ADC_Prescaler_Div4;
    ADC_CommonInit(&ADC_CommonInitStruct);//初始化
  
    //初始化ADC1相关参数
    ADC_InitStruct.ADC_Resolution=ADC_Resolution_12b;//12位模式
    //非扫描模式
    ADC_InitStruct.ADC_ScanConvMode=DISABLE;
    //关闭连续转换
    ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;
   
    //触发检测
    ADC_InitStruct.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising;
   
    //使用外部触发来启动AD转换  这里使用定时器2的TRGO触发
    ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T2_TRGO;

    ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//右对齐
    ADC_InitStruct.ADC_NbrOfConversion=1;//一个转换在规则序列中
    ADC_Init(ADC1,&ADC_InitStruct);
   
//    //使能ADC在DMA模式下的连续转换
    ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);
    //使能ADC的DMA模式
    ADC_DMACmd(ADC1,ENABLE);
    //开启ADC转换
    ADC_Cmd(ADC1,ENABLE);
}

//获得ADC值
//ch:通道值0~15
//返回值:转换结果
u16 Get_Adc(u8 ch)
{
   
    //设置指定ADC的规则通道,一个序列,采样时间
    ADC_RegularChannelConfig(ADC1,ch,1,ADC_SampleTime_3Cycles); //第三个参数为规则组采样第一个
   
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));//等待转换结束
   
    return ADC_GetConversionValue(ADC1); //返回一次转换结果
   
}

//获取通道ch的转换值,取times后然后平均
//ch为通道编号 times为获取次数
//返回值 ch的times次转换的平均结果
u16 Get_Adc_Average(u8 ch,u8 times)
{
    u32 temp_val=0;
    u8 t;
    for(t=0;t<times;t++)
    {
        temp_val+=Get_Adc(ch);
        delay_ms(5);
    }
    return temp_val/times;
}




现在不使用DMA的时候可以采集到数据,而且使用DMA可以进到中断服务函数,请大虾帮忙看一下问题!
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。