这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【换取手持数字示波器】关于STM32F030ADC采集的巨坑,请注意避让!!!

共7条 1/1 1 跳转至

【换取手持数字示波器】关于STM32F030ADC采集的巨坑,请注意避让!!!

院士
2024-05-23 12:04:43   被打赏 45 分(兑奖)     打赏

近期正好开发需要采集ADC相关数据的项目,使用的芯片是STM32F030RCT6,目前采用独立库的方式开发


第一个注意点STM32F030RC使用的一些中断向量与常用的STM32F030有些差异,主要在于串口3的相关终端配置


言归正传回到我们ADC相关的开发,本来觉得这个简单的功能只要一下就可以调试出来的,但是这个整整花了我半天的时间,或者说是我水平有限吧,让大家见笑了,但是我还是要把这个过程给大家分享出来。


我这边的需求是采集交流电的数据做转换,得到有效值


对于STM32F030的ADC其实只有1组,理论上按照库里面Demo那样设计基本没有问题

先看下原厂的Demo


初始化

static void ADC_Config(void)
{
  ADC_InitTypeDef     ADC_InitStructure;
  GPIO_InitTypeDef    GPIO_InitStructure;
  
  /* GPIOC Periph clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
  
  /* ADC1 Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  /* Configure ADC Channel11 as analog input */
#ifdef USE_STM320518_EVAL
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 ;
#else
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
#endif /* USE_STM320518_EVAL */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
  
  /* ADCs DeInit */  
  ADC_DeInit(ADC1);
  
  /* Initialize ADC structure */
  ADC_StructInit(&ADC_InitStructure);
  
  /* Configure the ADC1 in continuous mode with a resolution equal to 12 bits  */
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
  ADC_Init(ADC1, &ADC_InitStructure); 
  
  /* Convert the ADC1 Channel 11 with 239.5 Cycles as sampling time */ 
#ifdef USE_STM320518_EVAL
  ADC_ChannelConfig(ADC1, ADC_Channel_11 , ADC_SampleTime_239_5Cycles);
#else
  ADC_ChannelConfig(ADC1, ADC_Channel_10 , ADC_SampleTime_239_5Cycles);
#endif /* USE_STM320518_EVAL */

  /* ADC Calibration */
  ADC_GetCalibrationFactor(ADC1);
  
  /* Enable the ADC peripheral */
  ADC_Cmd(ADC1, ENABLE);     
  
  /* Wait the ADRDY flag */
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 
  
  /* ADC1 regular Software Start Conv */ 
  ADC_StartOfConversion(ADC1);
  
}


数据采集

{
/* Test EOC flag */
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    
    /* Get ADC1 converted data */
    ADC1ConvertedValue =ADC_GetConversionValue(ADC1);
    
    /* Compute the voltage */
    ADC1ConvertedVoltage = (ADC1ConvertedValue *3300)/0xFFF;
}


原厂代码只是针对一路的,一路的持续测试基本没有问题,就是前面的数据可能会不准确,因为电压还未稳定


一下为个人修改的代码

初始化

void ADC_ModeConfig()
{
	ADC_InitTypeDef     ADC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	/* ADCs DeInit */  
//    ADC_DeInit(ADC1);

    /* Initialize ADC structure */
    ADC_StructInit(&ADC_InitStructure);

    /* Configure the ADC1 in continuous mode with a resolution equal to 12 bits  */
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
    
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
    ADC_Init(ADC1, &ADC_InitStructure); 

	/* ADC Calibration */
    ADC_GetCalibrationFactor(ADC1);

    /* Enable the ADC peripheral */
    ADC_Cmd(ADC1, ENABLE);     

    /* Wait the ADRDY flag */
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); 

    /* ADC1 regular Software Start Conv */ 
    ADC_StartOfConversion(ADC1);
}


采集接口

void ADC_Collection(uint8 NUM )
{
    uint16 i=0,j;


    for(i=0;i<NUM;i++){
    
        ADC_ChannelConfig(ADC1, (ADC_Channel_0 << Channel[i]) , ADC_SampleTime_71_5Cycles);
        
        while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY) == RESET);
        ADC_StartOfConversion(ADC1); 
        ADC_ClearFlag(ADC1,ADC_FLAG_EOC);    //采集两次抛弃第一次的值
        while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
        

        ADC_StartOfConversion(ADC1); 
        ADC_ClearFlag(ADC1,ADC_FLAG_EOC);    //采集两次抛弃第一次的值
        while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
        ADC_VAL[count][i]=ADC_GetConversionValue(ADC1);
        ADC_StopOfConversion(ADC1);
    
    }
    count++;
}


初始化主要修改的是

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

这个是连续扫描,因为我们采集的多通道的,连续扫描会影响其他通道的数据采集所以这个扫描要关闭掉


采集这个才是大坑的所在,这边加了一句

ADC1->CHSELR =(ADC_Channel_0 << Channel[i]);


这个语句其实在以下库函数中是用或的方式添加通道

ADC_ChannelConfig(ADC1, (ADC_Channel_0 << Channel[i]) , ADC_SampleTime_71_5Cycles);


void ADC_ChannelConfig(ADC_TypeDef* ADCx, uint32_t ADC_Channel, uint32_t ADC_SampleTime)
{
  uint32_t tmpreg = 0;

  /* Check the parameters */
  assert_param(IS_ADC_ALL_PERIPH(ADCx));
  assert_param(IS_ADC_CHANNEL(ADC_Channel));
  assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime));

  /* Configure the ADC Channel */
  ADCx->CHSELR |= (uint32_t)ADC_Channel;

  /* Clear the Sampling time Selection bits */
  tmpreg &= ~ADC_SMPR1_SMPR;

  /* Set the ADC Sampling Time register */
  tmpreg |= (uint32_t)ADC_SampleTime;

  /* Configure the ADC Sample time register */
  ADCx->SMPR = tmpreg ;
}


为了保证通道的唯一性,添加

ADC1->CHSELR =(ADC_Channel_0 << Channel[i]);

这个保证该通道是我们需要采集的唯一通道,而且每次通道切换我们都会丢弃一次数据,保证数据的稳定性


此次分享仅为个人所经历,希望大家多多指导,谢谢!




关键词: STM32F030     ADC    

高工
2024-05-23 13:27:39     打赏
2楼

谢谢分享


高工
2024-05-23 16:40:16     打赏
3楼

这款芯片现在还可以买到吗?


院士
2024-05-24 09:30:36     打赏
4楼

STM32的连续扫描时也会影响到其它通道的采样结果呀!


工程师
2024-05-24 09:33:29     打赏
5楼

666


院士
2024-05-30 21:26:54     打赏
6楼

现在终于明白为什么有的MCU有两个ADC,但外设引脚是共用的了。

谢谢了


菜鸟
2024-06-01 19:56:44     打赏
7楼

谢谢分享


共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]