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