Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] voltage detect on avr

Status
Not open for further replies.

foxbrain

Full Member level 2
Joined
Feb 1, 2010
Messages
142
Helped
5
Reputation
10
Reaction score
4
Trophy points
1,298
Location
Damas
Activity points
2,322
how can i make an avr device detect the charge of the battery that is working on?
should i add a device to it ?
or i can solve it by programming it in C language?
thanks
 

What type of battery are you using in your design?

As Nandhu915 mentioned the use of the AVR's ADC is a viable option.

However, you may want to offload the battery management responsibilities to another device while still giving the AVR control over the process.

There are numerous battery management devices which will interface with your AVR, like the following:

Atmel Li-Ion Battery Management Devices

**broken link removed**

Analog Devices Battery Management

Many of these devices have standard interfaces such as SPI and I2C which provide simply interfacing with your AVR.

BigDog
 

A simple way to sense it would be to sense the battery voltage. If the battery voltage is greater than 5v, use a voltage divider (potential divider) using 2 resistors (or a resistor and pot) to reduce the battery voltage to less than 5v. If the battery voltage is less than 5v and you are running the AVR off the battery, make sure you select an appropriate ADC reference lower than the least possible battery voltage. You can use the internal 2.56v/1.1v reference (check the datasheet) or you can set an external reference if you needed a lower reference.

Here you can find out how to use the AVR ADC:
DN021 - Using the Built-in ADC in AVR :: AVR Freaks
Programming AVR ADC module with WinAVR | WinAVR AVR-GCC Tutorial
**broken link removed**

Hope this helps.
Tahmid.
 

Another interesting option combines the battery management with an AVR into a single package:

Battery Management AVR

Combining the AVR microcontroller’s performance with leading-edge high-voltage technology and long-term cooperation with top battery manufacturers, Atmel has developed a full range of microcontrollers dedicated to Li-Ion battery management for 1 to 4 cells in series.

Atmel’s one-chip solution minimizes the component count on the PCB, and is available in ultra small packages.

BigDog
 
  • Like
Reactions: FvM

    FvM

    Points: 2
    Helpful Answer Positive Rating
Detect the charge is more than measuring a voltage, it usually implies accumulated current measurement. Battery management systems, e.g. the said Battery Managment AVRs have it.
 
nandhu015 : yr tutorial is nice and clear but this is not what i want
FVM: i want it without using external stuff
Bigdog : i prefer that without using external things
tahmid : this link is exactly what i want :
**broken link removed**
but it didn't work....
i put the Vgb 1.22v and i'm using atmega16A
do u have any idea what may make it don't work?

thanks to u guys....
 

Hi foxbrain.

You don't mention the exact problem. Wrong result? Interrupt not coming? What exactly is the problem? What kind of battery are you using? Also if you have a schematic please post it.
 
Last edited:

i'm using a power supply...
the led is always lighting , i start the voltage from 5v until 1.5v but the led gets down as i'm decreasing the voltage.....
the schematic is simple just supplying the atmega on Vcc,Avcc and Aref and of course grounding and putting a led with a resistor to the port i use....
 

foxbrain said:
i'm using atmega16A

i start the voltage from 5v until 1.5v

ATmega16A operates from 2.7V-5.5V, so don't fall below the minimum operating voltage!

If I understood correctly you are using Tahmid's link tutorial right?
But you should notice that during initialization there is a command:
ADMUX = 0xE;
According to ATmega48 datasheet this results to VBG=1.1V as selected input. But for ATmega16A you need
ADMUX=0x1E;
to have a VBG=1.22V as selected input.

It's all in the dataheet, at the ADMUX register section. Compare ADMUX of ATmega48 and ATmega16A and you will see what I am talking about.
 

ATmega16A operates from 2.7V-5.5V, so don't fall below the minimum operating voltage!
will it get damaged if we pretend that we r using a device with 2 AA battery (1.5v each) the device might fall down under 2.7v but that won't get it damaged , except here is it different?
If I understood correctly you are using Tahmid's link tutorial right?
yes exactly.

i changed the condition to 3.7 volt instead of 3.2v and i changed to port to D5 and of course i changed what needed to be change for that.
but after all i got the same result.....it didn't work correctly:sad:
 

foxbrain said:
will it get damaged if we pretend that we r using a device with 2 AA battery (1.5v each) the device might fall down under 2.7v but that won't get it damaged , except here is it different?
Just stick to the manufacturer's ratings, don't fall below minimum operating voltage!;-)

foxbrain said:
i changed to port to D5 and of course i changed what needed to be change for that.
You do what with D5, led driving?

foxbrain said:
it didn't work correctly
OK, post your code then!
 

You do what with D5, led driving?
it should be cleared if the voltage is over 3.7 v else it will light..
here is the code:
Code:
#include <avr\io.h>
#include <avr\interrupt.h>

// Global variables

float vcc;//variable to hold the value of Vcc

void setup_adc(void)
	{
    	ADMUX = 0x1E; //Set the Band Gap voltage as the ADC input
    	ADCSRA = (1<<ADEN)|(1<<ADATE)|(1<<ADIE)|(1<<ADSC)|5;
	}

ISR(ADC_vect) //ADC End of Conversion interrupt 
	{
		unsigned char adc_data;
		adc_data = ADC>>2; //read 8 bit value
		vcc = 1.22 * 255 / adc_data;
	}

// ***********************************************************
// Main program
// ***********************************************************
int main(void) 
{
   	DDRD = DDRD | (1<<PD5); //set PB0 as output (for the LED).
   	sei(); //Activate interrupts
   	setup_adc(); //setup the ADC

   	while(1) { // Infinite loop
       	if (vcc < 3.7)
        {
            PORTD |= (1<<PD5);
        }
        else
        {
            PORTD &= ~(1<<PD5);
        }
    }
}
 
Last edited:

You should update the adc value every time before comparing..

You had enabled autotrigger mode and did not specified the source of auto trigger mode.

It is better to manually read adc values and compare it.
 

did not specified the source of auto trigger mode.
so should i put it in free running mode or in analog comparator?
 

Although auto triggered is enabled, you have it in free runing mode. Personally I don't use interrupts for the ADC, but remove the "(1<<ADATE)" part from line 2 of setup_adc() and see what happens, you don't need auto trigger anyway.
 

You should update the adc value every time before comparing..
don't worry about this , because i tried it many time every time i power my device with a voltage then i turn it off and put another voltage and turn it on.....
Personally I don't use interrupts for the ADC
do u have another way ? for me it doesn't matter the way what it matters to me the result.
i removed the "(1<<ADATE)" part from line 2 of setup_adc() but i got the same result.....
 

The following code is from an ATmega128 project, compare datasheets and modify if necessary to match involved AVR registers bit values. The example uses ADC1 channel.

Code:
/*Is needed for ReadADCValue()*/
typedef union
{
  uint16 ivalue;

  struct
  {
    uint8 low;
    uint8 high;
  };
} Value16Bit_t;



void InitADC (void)
{
  volatile uint8 dummyH, dummyL;
  ADMUX = 0x41;          //PF1 pin as analog pin (ADC1)
  ADCSRA = (1<<ADPS0);	//Set prescaler: /2
  ADCSRA |= ((1<<ADEN) | (1<<ADSC));	//enable and start ADC
  while(ADCSRA&(1<<ADSC))
    ;	//wait for convertion to complete
		
  dummyL = ADCL;	//Read dummy convertion result
  dummyH = ADCH;
  ADCSRA &= ~(1<<ADEN);	//Disable ADC
}


uint16 ReadADCValue (void)
{
  volatile Value16Bit_t	adcVal;
	
  ADCSRA |= ((1<<ADEN) | (1<<ADSC));	//enable and start ADC
  while(ADCSRA&(1<<ADSC))
    ;	//wait for convertion to complete
	
  adcVal.low = ADCL;
  adcVal.high = ADCH;
	
  ADCSRA &= ~(1<<ADEN);	//Disable ADC
		
  return adcVal.ivalue;
}

You can read ADC value like:
uint16 adcValue=ReadADCValue();

If you use multiple channels you can pass an uint8 as argument:
InitADC(_CHANNEL0);
adcValue=ReadADCValue(_CHANNEL2);


The returned value represent ADC's value and must be proccessed accordingly to give you the voltage analog value on MCU pin.
 
Last edited:

i wrote this code:
Code:
#include <avr\io.h>

// Global variables

float vcc
typedef union
{
  uint16 ivalue;

  struct
  {
    uint8 low;
    uint8 high;
  };
} Value16Bit_t;



void InitADC (void)
{
  volatile uint8 dummyH, dummyL;
  ADMUX = 0x41;          //PF1 pin as analog pin (ADC1)
  ADCSRA = (1<<ADPS0);	//Set prescaler: /2
  ADCSRA |= ((1<<ADEN) | (1<<ADSC));	//enable and start ADC
  while(ADCSRA&(1<<ADSC))
    ;	//wait for convertion to complete
		
  dummyL = ADCL;	//Read dummy convertion result
  dummyH = ADCH;
  ADCSRA &= ~(1<<ADEN);	//Disable ADC
}


uint16 ReadADCValue (void)
{
  volatile Value16Bit_t	adcVal;
	
  ADCSRA |= ((1<<ADEN) | (1<<ADSC));	//enable and start ADC
  while(ADCSRA&(1<<ADSC))
    ;	//wait for convertion to complete
	
  adcVal.low = ADCL;
  adcVal.high = ADCH;
	
  ADCSRA &= ~(1<<ADEN);	//Disable ADC
		
  return adcVal.ivalue;
}
int main(void) 
{
   	DDRD = DDRD | (1<<PD5); //set PB0 as output (for the LED).
	uint16 adc;
	adc=ReadADCValue();
	vcc = 1.22 * 255 / adc;
 //  	sei(); //Activate interrupts
   //	setup_adc(); //setup the ADC

   	while(1) { // Infinite loop
       	if (vcc < 3.7)
        {
            PORTD |= (1<<PD5);
        }
        else
        {
            PORTD &= ~(1<<PD5);
        }
    }
}
and i got 10 errors and 2 warnings!!!
 

There was a semicolon missing in the second line and all the uint8 and uint16 have to be changed to uint8_t and uint16_t

Code:
#include <avr\io.h>

// Global variables

float vcc;
typedef union
{
  uint16_t ivalue;

  struct
  {
    uint8_t low;
    uint8_t high;
  };
} Value16Bit_t;



void InitADC (void)
{
  volatile uint8_t dummyH, dummyL;
  ADMUX = 0x41;          //PF1 pin as analog pin (ADC1)
  ADCSRA = (1<<ADPS0);	//Set prescaler: /2
  ADCSRA |= ((1<<ADEN) | (1<<ADSC));	//enable and start ADC
  while(ADCSRA&(1<<ADSC))
    ;	//wait for convertion to complete
		
  dummyL = ADCL;	//Read dummy convertion result
  dummyH = ADCH;
  ADCSRA &= ~(1<<ADEN);	//Disable ADC
}


uint16_t ReadADCValue (void)
{
  volatile Value16Bit_t	adcVal;
	
  ADCSRA |= ((1<<ADEN) | (1<<ADSC));	//enable and start ADC
  while(ADCSRA&(1<<ADSC))
    ;	//wait for convertion to complete
	
  adcVal.low = ADCL;
  adcVal.high = ADCH;
	
  ADCSRA &= ~(1<<ADEN);	//Disable ADC
		
  return adcVal.ivalue;
}
int main(void) 
{
   	DDRD = DDRD | (1<<PD5); //set PB0 as output (for the LED).
	uint16_t adc;
	adc=ReadADCValue();
	vcc = 1.22 * 255 / adc;
 //  	sei(); //Activate interrupts
   //	setup_adc(); //setup the ADC

   	while(1) { // Infinite loop
       	if (vcc < 3.7)
        {
            PORTD |= (1<<PD5);
        }
        else
        {
            PORTD &= ~(1<<PD5);
        }
    }
}

Alex
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top