cancel
Showing results for 
Search instead for 
Did you mean: 

ADC configurations for measuring battery voltage

pm_brk_pm
Associate II
Posted on December 16, 2016 at 10:07

Hello Everyone.

I would like to infrom you that I am trying to measure battery voltage which is connected to ADC12_IN4 pin of stm32f103c8t6 microcontroller with ADC.

I wrote proper code for configurations and reading battery voltage.But Unfortunately it only shows ''0'' as battery voltage in integer.I obtain this data and analyze using web server, in this case I am able to see what is the value of battery voltage.

My question is; Is there anything wrong in my code?

I would like to show you my circuit design,datasheet and part of code for clear understanding

Datasheet, pin connection

0690X00000605tFQAQ.png

Part of my circuit design with microcontroller

0690X00000605tKQAQ.png

My codes for ADC configurations

&sharpinclude ''ADCTIMER.h''

&sharpinclude ''stdio.h''

&sharpinclude ''string.h''

&sharpinclude ''stm32f10x.h''

&sharpinclude ''stm32f10x_flash.h''

&sharpinclude ''stm32f10x_gpio.h''

&sharpinclude ''stm32f10x_adc.h''

&sharpinclude ''stm32f10x_rcc.h''

//ADC GPIO CONFIGURATIONS

void ADC::ADC_GPIO_INIT(void){

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin= GPIO_Pin_4;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

GPIO_Init(GPIOA,&GPIO_InitStructure);

}

//ADC CONFIGURATIONS

void ADC::ADC_Battery_Voltage (void) {

ADC_InitTypeDef ADC_InitStructure;

//PCLK2 is the APB2 clock

//ADCCLK = PCLK26 = 726 = 12MHz

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

//Put everything back to power-on defaults

ADC_DeInit(ADC1);

ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;

ADC_InitStructure.ADC_ScanConvMode=DISABLE;

ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

ADC_InitStructure.ADC_NbrOfChannel = 1 ;

ADC_Init(ADC1,&ADC_InitStructure);

ADC_Cmd(ADC1,ENABLE);

ADC_ResetCalibration(ADC1);

while(ADC_GetResetCalibrationStatus(ADC1));

ADC_StartCalibration(ADC1);

while(ADC_GetCalibrationStatus(ADC1));

}

//NVIC INTERRUPT METHODE FOR ADC

void ADC::NVIC_Interrupt_ADC(){

NVIC_InitTypeDef NVIC_InitStructure;

ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1,ADC_SampleTime_13Cycles5);

NVIC_InitStructure.NVIC_IRQChannel=ADC1_2_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_Init(&NVIC_InitStructure);

}

//Read adc value methode

int ADC::ADC1_Read_Value(){

int ADC_value;

ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1,ADC_SampleTime_1Cycles5);

ADC_SoftwareStartConvCmd(ADC1,ENABLE);

while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

ADC_value = ADC_GetConversionValue(ADC1);

ADC_ClearFlag(ADC1, ADC_FLAG_EOC);

check_adc_value = activate;

return ADC_value;

}

My main NVIC Interrupt handler code

////----------------------------------------ADC APPLICATION NVIC INTERRUPT CONTROLLER--------------------------------int ADC_Value_battery;

extern ''C''{

void ADC1_2_IRQHandler(void){

if(ADC_GetITStatus(ADC1,ADC_IT_EOC != RESET)){

if(adc.check_adc_value){

ADC_Value_battery = adc.ADC1_Read_Value();

}

ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);

}

}

}

My main code(for example, shortened)

int main(void){

adc.ADC_GPIO_INIT();

adc.ADC_Battery_Voltage();

adc.NVIC_Interrupt_ADC();

while(1)

{

gsm.sendGPSData(gpsData,trailer,ADC_Value_battery);

}

}

Here what I see in my server (ALL ZERO ''0'')

0690X00000605tPQAQ.png

Any help highly apreciated.

#interrupt #nvic #c++ #stm32-adc #interrupt-handler
3 REPLIES 3
Posted on December 16, 2016 at 18:37

Your code doesn't have any sensible flow or logic to it. You don't enable the interrupt on the ADC, nor do you create the conditions for the EOC interrupt to occur.

I'm assuming here the IRQ handler never gets called, something you could perhaps confirm with some debugging. Consequently the variable never changes from zero.

When you get an EOC interrupt the data is already available, you read it and start the *next* conversion. More sensibly you use a TIM to pace the conversions are some reasonable frequency, a value you write at 1Hz doesn't need to sample thousands of times per second.

Move all the initialization stuff into one spot, put the channel selection and start conversion stuff .

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on December 16, 2016 at 19:01

A less muddled approach using your code as a basis

#include 'ADCTIMER.h'
#include 'stdio.h'
#include 'string.h'
#include 'stm32f10x.h'
#include 'stm32f10x_flash.h'
#include 'stm32f10x_gpio.h'
#include 'stm32f10x_adc.h'
#include 'stm32f10x_rcc.h'
 
//ADC GPIO CONFIGURATIONS
void ADC::ADC_GPIO_INIT(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;
 GPIO_InitStructure.GPIO_Pin= GPIO_Pin_4;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
 GPIO_Init(GPIOA,&GPIO_InitStructure);
}
//ADC CONFIGURATIONS
void ADC::ADC_Battery_Voltage (void)
{
 ADC_InitTypeDef ADC_InitStructure; 
 //PCLK2 is the APB2 clock 
 //ADCCLK = PCLK26 = 726 = 12MHz
 RCC_ADCCLKConfig(RCC_PCLK2_Div6);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
 //Put everything back to power-on defaults 
 ADC_DeInit(ADC1);
 ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
 ADC_InitStructure.ADC_ScanConvMode=DISABLE;
 ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
 ADC_InitStructure.ADC_NbrOfChannel = 1; 
 ADC_Init(ADC1,&ADC_InitStructure);
 /* Configure the channel(s) */
 ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1,ADC_SampleTime_13Cycles5);
 
 ADC_Cmd(ADC1,ENABLE);
 ADC_ResetCalibration(ADC1);
 
 while(ADC_GetResetCalibrationStatus(ADC1));
 ADC_StartCalibration(ADC1);
 while(ADC_GetCalibrationStatus(ADC1));
}
//NVIC INTERRUPT METHODE FOR ADC
void ADC::NVIC_Interrupt_ADC()
{
 NVIC_InitTypeDef NVIC_InitStructure;
 NVIC_InitStructure.NVIC_IRQChannel=ADC1_2_IRQn;
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
 NVIC_Init(&NVIC_InitStructure);
 /* Enable EOC interrupt */
 ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
 /* Start first conversion */
 ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
 
////----------------------------------------ADC APPLICATION NVIC INTERRUPT CONTROLLER--------------------------------int ADC_Value_battery;
extern 'C' void ADC1_2_IRQHandler(void)
{
 if (ADC_GetITStatus(ADC1, ADC_IT_EOC != RESET))
 {
 ADC_Value_battery = ADC_GetConversionValue(ADC1);
 ADC_SoftwareStartConvCmd(ADC1,ENABLE); // Start Next
// Reading ADC Should clear this
// ADC_ClearITPendingBit(ADC1,ADC_IT_EOC);
 }
}
int main(void)
{
 adc.ADC_GPIO_INIT();
 adc.ADC_Battery_Voltage();
 adc.NVIC_Interrupt_ADC();
 
 while(1)
 {
 gsm.sendGPSData(gpsData,trailer, ADC_Value_battery); // make sure variable is volatile
 // Consider starting next conversion here
 }
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on December 19, 2016 at 07:16

Thank you Clive,

I will try to configure as you mentioned above.This is first time I tried ADC pins for arm and I am still learning new things on it.