近期正好开发需要采集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]);
这个保证该通道是我们需要采集的唯一通道,而且每次通道切换我们都会丢弃一次数据,保证数据的稳定性
此次分享仅为个人所经历,希望大家多多指导,谢谢!