最近使用stm32f103c8t6自带的ADC,遇到如下问题:while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET );
程序执行到这里跳不出循环
uint16_t myADC_GetValue(void)
{
uint16_t value_ADC = 0;
uint8_t i = 0;
for(i=0;i<10;i++)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发ADC转换,这样ADC就可以进行转换了 conversion
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET );//规则组转换完成标志位,//12MHZ, (1/12M)*(55.5+12.5)=5.6us,该循环大概等待5.6us
value_ADC += ADC_GetConversionValue(ADC1);
}
delay_ms(10);
return value_ADC / 10;//获取ADC的转换值
}
详情:规则组ADC转换一直没完成。
我逛论坛发现2个解决方案:
(1)不使用标志位判断,用delay来假装转换结束。
原理:
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//把通道0写入在规则组菜单列表的第一个位置,采样时间是55.5个ADCCLK周期
//12MHZ, (1/12M)*(55.5+12.5)=5.6us
配置好参数后,采样时间大约是5.6us。那么用delay来延时一下,不管有没有把电压值转换完成,都继续执行,强制认为转换已经完成。
代码如下:
#include "ADC.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_adc.h"
#include "oled.h"
#include "delay.h"
void MyAdcTest_Config(void)//ADC初始化
{
GPIO_InitTypeDef myGPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);//打开ADC1的时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC的时钟由主时钟6分频而来,即72/6=12MHZ
myGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
myGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入,电压是模拟量(AIN模式是ADC的专属模式)
myGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &myGPIO_InitStructure ); //初始化GPIOD3,6
//ADC_DeInit(ADC1);
//ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigInjecConv_None;//触发源:软件触发
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//非连续转换
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描
ADC_InitStructure.ADC_NbrOfChannel = 1;//通道数目,在非扫描模式下,通道数目可以不写
ADC_Init(ADC1,&ADC_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//把通道0写入在规则组菜单列表的第一个位置,采样时间是55.5个ADCCLK周期
//12MHZ, (1/12M)*(55.5+12.5)=5.6us
ADC_Cmd(ADC1,ENABLE);//电源
ADC_ResetCalibration(ADC1);//复位校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);//返回复位校准的状态
ADC_StartCalibration(ADC1);//开始校准
while(ADC_GetCalibrationStatus(ADC1)==SET);//等待校准完成
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发ADC转换,这样ADC就可以进行转换了 conversion
}
uint16_t myADC_GetValue(void)
{
uint16_t value_ADC = 0;
uint8_t i = 0;
for(i=0;i<10;i++)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发ADC转换,这样ADC就可以进行转换了 conversion
delay_us(6);
value_ADC += ADC_GetConversionValue(ADC1);
}
delay_ms(10);
return value_ADC / 10;//获取ADC的转换值
}
(2)在初始化ADC时,ADC_Cmd(ADC1,DISABLE);
在获取ADC转换值的函数中ADC_Cmd(ADC1,ENABLE);
这里使用EOC标志位。原理我还没搞清楚。
代码如下:
#include "ADC.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_adc.h"
#include "oled.h"
#include "delay.h"
void MyAdcTest_Config(void)//ADC初始化
{
GPIO_InitTypeDef myGPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);//打开ADC1的时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC的时钟由主时钟6分频而来,即72/6=12MHZ
myGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
myGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入,电压是模拟量(AIN模式是ADC的专属模式)
myGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
GPIO_Init(GPIOA, &myGPIO_InitStructure ); //初始化GPIOD3,6
//ADC_DeInit(ADC1);
//ADC_StructInit(&ADC_InitStructure);
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigInjecConv_None;//触发源:软件触发
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//非连续转换
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描
ADC_InitStructure.ADC_NbrOfChannel = 1;//通道数目,在非扫描模式下,通道数目可以不写
ADC_Init(ADC1,&ADC_InitStructure);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//把通道0写入在规则组菜单列表的第一个位置,采样时间是55.5个ADCCLK周期
//12MHZ, (1/12M)*(55.5+12.5)=5.6us
ADC_Cmd(ADC1,DISBLE);//电源
ADC_ResetCalibration(ADC1);//复位校准
while(ADC_GetResetCalibrationStatus(ADC1) == SET);//返回复位校准的状态
ADC_StartCalibration(ADC1);//开始校准
while(ADC_GetCalibrationStatus(ADC1)==SET);//等待校准完成
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发ADC转换,这样ADC就可以进行转换了 conversion
}
uint16_t myADC_GetValue(void)
{
uint16_t value_ADC = 0;
uint8_t i = 0;
for(i=0;i<10;i++)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发ADC转换,这样ADC就可以进行转换了 conversion
ADC_Cmd(ADC1, ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET );//规则组转换完成标志位,//12MHZ, (1/12M)*(55.5+12.5)=5.6us,该循环大概等待5.6us
value_ADC += ADC_GetConversionValue(ADC1);
}
delay_ms(10);
return value_ADC / 10;//获取ADC的转换值
}