采用STM32F030单片机采集两路AD数据,单独采集多路AD时,使用单次转换模式,程序配置如下:
void ADC1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_ADCCLKConfig(RCC_ADCCLK_HSI14);//14mhz
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0|GPIO_Pin_5|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉 (浮空)
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉 (浮空)
GPIO_Init(GPIOB, &GPIO_InitStructure);
ADC_DeInit(ADC1);//ADC恢复默认设置
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位精度
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //不用外不触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据对其为右对齐
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Backward; //ADC的扫描方向
ADC_Init(ADC1, &ADC_InitStructure);
ADC_GetCalibrationFactor(ADC1); /* 先校准ADC 要按顺序执行,*/
ADC_Cmd(ADC1, ENABLE); /*使能ADC */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY)); /* Wait the ADCEN falg */
ADC_StartOfConversion(ADC1); /* ADC1 regular Software Start Conv */
}
多通道AD采集如下:
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
if(ch==0)
{
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); //设置指定ADC
的规则组通道,设置它们的转化顺序和采样时间
}
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY) == RESET);
ADC_StartOfConversion(ADC1);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}
经测试,AD采集的值与实际测量相对应符合实际值。另外单独测试第7通道也是符合实际值的。但是当主程序循环测量第0通道和第7通道时,发现测量值不能对应起来。找网上找到一篇博客说是库文件底层出问题了,控制AD通道的寄存器赋值有问题,不应该用“或”的方式赋值,这样的话就相当于只是在读取被赋值的最大通道有效,有问题的底层库如下:
当然这个问题可以这样来做处理:
//设置指定ADC的规则组通道,一个序列,采样时间
if(ch==0)
{
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
ADC1->CHSELR =ADC_Channel_0;
}
else if(ch==5)
{
ADC_ChannelConfig(ADC1, ADC_Channel_5 , ADC_SampleTime_239_5Cycles); //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
ADC1->CHSELR =ADC_Channel_5;
}
else if(ch==7)
{
ADC_ChannelConfig(ADC1, ADC_Channel_7 , ADC_SampleTime_239_5Cycles); //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
ADC1->CHSELR =ADC_Channel_7;
}
就是在选择通道函数之后,加一条赋值指令,这样即可解决底层库赋值问题。
但是奇怪的问题是,当解决以上问题后,通过观察串口打印输出的AD各通道数据发现,采集第7通道时,输出的AD数据恰好是符合第0通道的AD值的,而第0通道的输出AD值恰好是符合第7通道的AD值。从这里可以看到AD通道的值错位了,仔细检查选择通道函数,发现在切换通道之后,就是等待数据转换完成标志,那么这个转换完成的标志其实就是未转换前通道已经转换完成的标志,这样的话就相当于将上一个通道的AD值给读取来了。那么解决的方法也很简单,就是在转换通道之前我们将转换完成标志先清除掉,这样就可以完全解决这个通道数据错位问题了,经测试完全解决了问题。修改完成后的代码如下:
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
ADC_StopOfConversion(ADC1);//停止转换
ADC_ClearFlag(ADC1, ADC_FLAG_EOC); //此处至关重要,一定要清除完成转换标志
//设置指定ADC的规则组通道,一个序列,采样时间
if(ch==0)
{
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_239_5Cycles); //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
ADC1->CHSELR =ADC_Channel_0;
}
else if(ch==5)
{
ADC_ChannelConfig(ADC1, ADC_Channel_5 , ADC_SampleTime_239_5Cycles); //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
ADC1->CHSELR =ADC_Channel_5;
}
else if(ch==7)
{
ADC_ChannelConfig(ADC1, ADC_Channel_7 , ADC_SampleTime_239_5Cycles); //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间
ADC1->CHSELR =ADC_Channel_7;
}
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY) == RESET);
ADC_StartOfConversion(ADC1);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}