Pages: [1]   Go Down
Author Topic: Measuring it's own voltage from batteries 4,5 volts  (Read 515 times)
0 Members and 1 Guest are viewing this topic.
Norway
Offline Offline
Jr. Member
**
Karma: 0
Posts: 79
<3 Arduino
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, I'm working on a small robot, and I need a way to measure the voltage on the batteries. So far I've just hooked + up to the analog0, and gets a value. But it seems like the analog reference gets lowered to the voltage the arduino is getting fed with.

Are there a way around this?
Logged

I'm from Norway!

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 361
Posts: 17261
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Are there a way around this?

As you have found out the default A/D reference used by the arduino analogRead() command uses whatever voltage that is being supplied to the Vcc and Avcc pins to represent 100% or range (or 1023 counts). As the battery voltage lowers in use you won't be able to determine it's absolute value because of that. There are several methods of working around this. Using an external regulated voltage source wired to the AREF pin (must be lower then the lowest possible battery voltage) and using a voltage divider wired to the battery output is one method. Enabling the internal 1.1vdc voltage reference and again using a voltage divider wired to the battery is another. Both have limitations in that they effect the range measurement for all the analog input pins.

Coding Badly and I worked on a simple sketch that used some cleaver programming method where a sketch can actually measure the battery voltage and therefore come up with an method where one can have a on-the-run calibration value to compensate for falling battery voltage but still be able to measure analog input pins accuratly. The only limitiation is an electrical one of the AVR controller chip in that the voltage on a analog input pin (or even a digital input pin) must never exceed the voltage on the Vcc and Avcc pins.

It's just a demonstration sketch and you would have to work at intergrating it into your larger sketch:

Code:
// Function created to obtain chip's actual Vcc voltage value, using internal bandgap reference
// This demonstrates ability to read processors Vcc voltage and the ability to maintain A/D calibration with changing Vcc
// Now works for 168/328 and mega boards.
// Thanks to "Coding Badly" for direct register control for A/D mux
// 1/9/10 "retrolefty"

int battVolts;   // made global for wider avaliblity throughout a sketch if needed, example a low voltage alarm, etc

void setup(void)
    {
     Serial.begin(38400);
     Serial.print("volts X 100");
     Serial.println( "\r\n\r\n" );
     delay(100);
    }
   
void loop(void)
    {
     battVolts=getBandgap();  //Determins what actual Vcc is, (X 100), based on known bandgap voltage
     Serial.print("Battery Vcc volts =  ");
     Serial.println(battVolts);
     Serial.print("Analog pin 0 voltage = ");
     Serial.println(map(analogRead(0), 0, 1023, 0, battVolts));
     Serial.println();   
     delay(1000);
    }

int getBandgap(void) // Returns actual value of Vcc (x 100)
    {
       
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
     // For mega boards
     const long InternalReferenceVoltage = 1115L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc reference
        // MUX4 MUX3 MUX2 MUX1 MUX0  --> 11110 1.1V (VBG)         -Selects channel 30, bandgap voltage, to measure
     ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
 
#else
     // For 168/328 boards
     const long InternalReferenceVoltage = 1056L;  // Adjust this value to your boards specific internal BG voltage x1000
        // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
        // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
     ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
       
#endif
     delay(50);  // Let mux settle a little to get a more stable A/D conversion
        // Start a conversion 
     ADCSRA |= _BV( ADSC );
        // Wait for it to complete
     while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
        // Scale the value
     int results = (((InternalReferenceVoltage * 1023L) / ADC) + 5L) / 10L; // calculates for straight line value
     return results;
 
    }




Lefty
Logged

Pages: [1]   Go Up
Jump to: