Я использую плату STM3240G-EVAL для считывания значений с АЦП. Я печатаю значения с АЦП на ЖК-дисплей на моей плате, используя функцию печати ниже. Я физически подключил датчик температуры к 3,3 В, ADC3 и GND на плате eval. Возвращаемые значения слишком велики. Разрешение АЦП должно быть 12 бит, поэтому 4096 должно быть максимальным значением, выводимым функцией ADC_GetConversionValue. Я получаю 5000+ значений при комнатной температуре! У кого-нибудь есть интуиция относительно того, почему значения АЦП могут масштабироваться?
////// stm324xg_eval.c
// to configure the ADC
void STM_EVAL_TEMPInit(Temp_TypeDef Temp)
{
RCC_PCLK2Config(RCC_HCLK_Div8);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
/* Enable the GPIO_TEMP Clock */
RCC_AHB1PeriphClockCmd(GPIO_TEMP_CLK[Temp], ENABLE);
/* Configure the GPIO_TEMP pin */
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_TEMP_PIN[Temp];
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_TEMP_PORT[Temp], &GPIO_InitStructure);/* Enable ADC3 Clock */
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_Init(ADC3, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC3, ADC_Channel_4, 1, ADC_SampleTime_144Cycles);
ADC_Cmd(ADC3, ENABLE);
}////// main.cpp
// to print to lcd
ADC_SoftwareStartConv(ADC3);
temp_value = ADC_GetConversionValue(ADC3);
uint8_t mymsg[20];
sprintf((char *)mymsg, "ADC = %d",(int)temp_value);
LCD_DisplayStringLine(Line6, mymsg);////// stm32f4xx_adc.c
// ADC_GetConversionValue function
/**
* @brief Returns the last ADCx conversion result data for regular channel.
* @param ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
* @retval The Data conversion value.
*/
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)
{
/* Check the parameters */
assert_param(IS_ADC_ALL_PERIPH(ADCx));
/* Return the selected ADC conversion value */
return (uint16_t) ADCx->DR;
}
Вам нужно дождаться завершения конвертации:
ADC_SoftwareStartConv(ADC3);
while( ADC_GetFlagStatus( ADC3, ADC_FLAG_EOC ) == RESET )
{
// do nothing (or something useful perhaps)
}
temp_value = ADC_GetConversionValue(ADC3);
Мне не хватало конфигурации АЦП;
ADC_InitStructure.ADC_NbrOfConversion = 1;
Убедитесь, что при использовании АЦП вы используете все конфигурации и не пропускаете их. После включения этого я смог получить то же напряжение с помощью мультиметра, что и значения АЦП, считанные датчиком.
Вы измеряли напряжение на датчике температуры и напряжение на входе ACD и напряжение VCC на вашем устройстве? Лучше включать их значения времени выполнения в тот момент, когда вы берете этот вывод 5000+.
Вы пытались подать заранее известное напряжение (скажем, 3,3 В) на тот же вход АЦП и сравнивать измеренные / полученные значения? Потому что кажется, что измеряемое вами напряжение 5000+ похоже на 4 + В.
Что касается кода, вероятно, лучше маскировать возвращаемое значение, чтобы учитывать только 12 бит:
return (uint16_t) ((ADCx->DR) & 0xFFF)
Следующий код работал для меня:
#define HW_DIVIDE 2
#define VREF_IN_mV 2500
#define MAX_RESOLUTION 255
static void _setup_rcc()
{
// Enable the ADC interface clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
// Enable the clock for the ADC GPIOs
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA, ENABLE);
}
static void _setup_gpio()
{
GPIO_InitTypeDef GPIO_InitStructure;
// Configure source 1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Configure source 2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Configure source 3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// Configure source 4
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
static void _setup_adc()
{
ADC_InitTypeDef ADC_InitStructure;
ADC_DeInit();
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 16;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_Init(ADC1, &ADC_InitStructure);
// Enable ADC
ADC_Cmd(ADC1, ENABLE);
}
void drv_adc_init()
{
_setup_rcc();
_setup_gpio();
_setup_adc();
}
uint16_t drv_adc_get_voltage(ADC_CHANNEL_IN type)
{
uint16_t val;
switch (type)
{
case ADC_3V3:
ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1,ADC_SampleTime_15Cycles);
break;
case ADC_1V2:
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_15Cycles);
break;
case ADC_3VA:
ADC_RegularChannelConfig(ADC1,ADC_Channel_6,1,ADC_SampleTime_15Cycles);
break;
case VIB_CUR:
ADC_RegularChannelConfig(ADC1,ADC_Channel_7,1,ADC_SampleTime_15Cycles);
break;
}
do
{
// Start the conversion
ADC_SoftwareStartConv(ADC1);
// Processing the conversion
if (ADC_GetFlagStatus(ADC1, ADC_FLAG_OVR))
{
ADC1->SR &= ~ADC_FLAG_OVR;
}
}
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
// Calculate the converted data
val = ADC_GetConversionValue(ADC1);
// Return voltage in millivolts
return HW_DIVIDE * VREF_IN_mV * val / MAX_RESOLUTION;
}