请问STM32F030 ADC切换通道后采集到的数据不对可能是什么原因?

2019-12-10 18:08发布

   假设通道2 的ad值是200左右,如果不改变通道那么测的值一直都在200左右。 当采集完通道2 -->切换到通道1-->采集完通道1-->切换到通道2    。。。  这样切换时 通道1的值就变为600多了。 通道1是一个1.6V左右的直流电平。
搞了两天了没有找到原因,贴上代码:
volatile uint8_t  TimerTrgAdcOkFlag=0;
//------------------------------------   DMA 初始化 ----------------------------------------------------------------
void DmaInit(void)
{
        DMA_InitTypeDef    DMA_InitStructure;
        NVIC_InitTypeDef   NVIC_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);                           //使能DMA时钟
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;         //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)&AdResults;                   //DMA内存基地址*/
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                            //方向:外设为源地址 即外设-》内存
        DMA_InitStructure.DMA_BufferSize = ADC_SAMP_CNT;                              //搬运数量
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;              //DMA外设地址不自加
        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_Mode = DMA_Mode_Normal;                                 //搬运完DMA_BufferSize 后不再搬运
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;                      // 配置DMA中断源
        NVIC_InitStructure.NVIC_IRQChannelPriority = 1;                    
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        DMA_ClearITPendingBit(DMA_IT_TC);                                             //清除一次DMA中断标志
        DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);                               //使能DMA传输完成中断
        DMA_ClearITPendingBit(DMA_IT_TC);                                             //清除一次DMA中断标志
        DMA_Cmd(DMA1_Channel1, ENABLE);                                               //使能DMA1
}


//配置ADC触发  = 定时器TIM15,用更新事件触发
void TimTrgInit(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
     //(1)选择TIM15 Update事件作为触发源(计数器溢出)
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, ENABLE);
        TIM_DeInit(TIM15);                                                            //配置基础
        TIM_TimeBaseStructure.TIM_ClockDivision=0;                                    //48M
        TIM_TimeBaseStructure.TIM_Prescaler=48-1;//48000;                               //48k 1Tick=1ms
        TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
        TIM_TimeBaseStructure.TIM_Period=20-1;//1000*1;                                //50K
        TIM_TimeBaseStructure.TIM_Period=25-1;//1000*1;                                //40K
        TIM_TimeBaseStructure.TIM_Period=50-1;//1000*1;                                //20K
        TIM_TimeBaseStructure.TIM_Period=FS_PRE-1;
        TIM_TimeBaseStructure.TIM_RepetitionCounter=0;                                //发生RepetitionCounter+1次溢出事件后中断
        TIM_TimeBaseInit(TIM15,&TIM_TimeBaseStructure);
        TIM_SelectOutputTrigger(TIM15,TIM_TRGOSource_Update);                         //TIM15的Update事件作为外部TRGO
        TIM_ClearFlag(TIM15,TIM_FLAG_Update);                                         //防止一上电进入中断 貌似可以不用??
        TIM_Cmd(TIM15,ENABLE);                                                        //使能TIM15
        ADC_StartOfConversion(ADC1);                                                  //如果是软件触发将立即开始转换,
                                                                                      //如果是定时器触发则等待定时触发信号来到启动。
        NVIC_InitStructure.NVIC_IRQChannel = TIM15_IRQn;                              // 配置DMA中断源
        NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        TIM_ITConfig(TIM15,TIM_IT_Update,ENABLE);                   //使能中断用来调试,
}

//-----------配置ADC为TIM15触发--------------
void AdcConfig(void)
{
    GPIO_InitTypeDef        GPIO_InitStructure;
    ADC_InitTypeDef         ADC_InitStructure;
    //DMA_InitTypeDef         DMA_InitStructure;
    //TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    //NVIC_InitTypeDef NVIC_InitStructure;
    //----gpio----
        RCC_APB2PeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_5;                        //Configure PA.0 PA.1  as analog input
    //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;                        //Configure PA.0 PA.1  as analog input
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        //-----adc-----
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
        RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4);        //ADC时钟不能大于14M
        ADC_DeInit(ADC1);
        ADC_StructInit(&ADC_InitStructure);
        ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;                          //右对齐
        ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising;   //上升沿触发
        ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T15_TRGO;         //TIM15触发
        // ADC_InitStructure.ADC_ExternalTrigConv =  ADC_ExternalTrigConv_T1_CC4;//选择TIM1 Compare&Capture4 作为触发源
        ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;                        //12位精度
        ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;                             //连续模式禁止 要由定时器触发
        ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;               //CH0-18
        ADC_Init(ADC1, &ADC_InitStructure);
        ADC_OverrunModeCmd(ADC1,ENABLE);                                              //数据覆盖方式,只保留最新的转换数据
        //ADC_ChannelConfig(ADC1,ADC_Channel_0|ADC_Channel_1,ADC_SampleTime_1_5Cycles);
        ADC_ChannelConfig(ADC1,ADC_Channel_1,ADC_SampleTime_1_5Cycles);
        ADC_GetCalibrationFactor(ADC1);                                               // 开始ADC校准
        ADC_Cmd(ADC1,ENABLE);
        while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN)==RESET);                         //等待ADC准备好
        ADC_DMACmd(ADC1,ENABLE);                                                      //使能ADC
        ADC_DMARequestModeConfig(ADC1,ADC_DMAMode_Circular);                          //ADC模式
        //ADC_DMARequestModeConfig(ADC1,ADC_DMAMode_OneShot);                          //DMA循环模式
        //------dma-----------
        DmaInit();
        //-------trg timer------
        TimTrgInit();
}


//传输完512个数据后,进入中断。在中断中我关闭触发定时器 并TimerTrgAdcOkFlag=1 声明采集传送完毕。
void DMA1_Channel1_IRQHandler()  
{  
    //DMA_InitTypeDef         DMA_InitStructure;
        if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)                                     //判断DMA传输完成中断                       
        {
                TimerTrgAdcOkFlag = 1;
                //toggle(GPIOC,GPIO_Pin_13);
                TIM_Cmd(TIM15,DISABLE);                                                   //关闭触发用的定时器
                DMA_ClearITPendingBit(DMA1_IT_TC1);                                           //清除DMA中断标志位  
        }       
}  

//-----------------------至此某个通道的一组数据就已经成功搬运存储完毕, 然后我有个timer3 是不停的在跑的并开启了溢出中断。在中断检测 当 TimerTrgAdcOkFlag  为0时就会再次初始化DMA和触发定时器。  这样就会继续采集搬运了

void TIM3_IRQHandler()
{
    //static uint8_t cnt=0;
    if(TIM_GetITStatus(TIM3, TIM_IT_Update)!= RESET)            //判断发生update事件中断  
    {  
        tick++;
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);     //清除update事件中断标志  
            //toggle(GPIOC,GPIO_Pin_13);
            if(TimerTrgAdcOkFlag==0)                                                //上次数据处理完毕
            {
                 if(!(TIM15->CR1 & TIM_CR1_CEN))                                    //且TIM15定时器 在关闭状态
                 {
                      DmaInit();
                     TimTrgInit();                                     //开启下一笔数据采集
                 }
            }
    }
   
}

//-----------------------  当我要切换通道时调用下面这个函数-----------------------------
void SetAdcChannel(uint32_t ADC_Channel)
{
    while(0==TimerTrgAdcOkFlag);              //等待上一次数据采集完成
        ADC1->CR &= (uint32_t)(~ADC_CR_ADSTART);  //设置START=0 才可以修改通道
        ADC_ChannelConfig(ADC1,ADC_Channel,ADC_SampleTime_1_5Cycles);
        ADC1->CHSELR = (uint32_t)ADC_Channel;     //修改通道
        while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)){};
        DelayMs(5);
        TimerTrgAdcOkFlag=0;                      //申明上一次数据处理完毕 , timer3中断里如果判断为0 就开始下次采集
              //ADC1->CR |= (uint32_t)ADC_CR_ADSTART;     //使能触发转换
        //while(0==TimerTrgAdcOkFlag);              //等待上一次数据采集完成
        //TimerTrgAdcOkFlag=0;   
}

SetAdcChannel(ADC_Channel_2);  等待TimerTrgAdcOkFlag=1 ----》查看结果  ---》SetAdcChannel(ADC_Channel_2);  等待TimerTrgAdcOkFlag=1 ----》查看结果 。。。  这样ADC_Channel_2数据是对的
SetAdcChannel(ADC_Channel_2);  等待TimerTrgAdcOkFlag=1 ----》查看结果  ---》SetAdcChannel(ADC_Channel_1);  等待TimerTrgAdcOkFlag=1 ----》查看结果   .。。   这样ADC_Channel_2数据是错的
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
6条回答
chendy6868
1楼-- · 2019-12-10 23:10
 精彩回答 2  元偷偷看……
bailangcn
2楼-- · 2019-12-11 04:48

TIM截图20191021170500.png (23.35 KB, 下载次数: 0)

下载附件

2019-10-21 17:05 上传




先清掉通道清掉,你懂的   


这个坑,应该不少人掉进过的
wuha
3楼-- · 2019-12-11 10:22
楼上说的对,库函数里设置通道,没有把之前的通道清除
GZZXB
4楼-- · 2019-12-11 13:15
bailangcn 发表于 2019-10-21 17:05
先清掉通道清掉,你懂的   

   ADC1->CHSELR = (uint32_t)ADC_Channel;     //修改通道
我这是直接赋值啊,不是或操作
GZZXB
5楼-- · 2019-12-11 15:45
wuha 发表于 2019-10-21 17:10
楼上说的对,库函数里设置通道,没有把之前的通道清除

    知道库函数是保留了上次的结果,我是直接赋值了。相当于清空通道-》更改通道了
GZZXB
6楼-- · 2019-12-11 19:21
 精彩回答 2  元偷偷看……

一周热门 更多>