Go Down

Topic: Voltage divider problem (Read 6 times) previous topic - next topic

oric_dan

From dhenry's comments, I don't understand what his "specific" objections are.

In general, straightforward ADC readings using a microcontroller like Arduino will have
probably 2-5% error, at best. For 5V, that's as much as 0.25V.

First off, the v.reg voltages are not spot-on 5V, but will have up to 5% error, depending
upon the specific v.regs being used. Secondly, whenever you use a voltage divider, the
resistors also have their own tolerances, ranging from below 1% for high-precision parts
[and who uses these] to 5% for most discrete parts. Therefore, any ADC measurements
will be off from the get-go. You can use a precision voltage-reference, but still must
use precision resistors in the voltage dividers for best results.

It seems to me that the majenko page has some good info to help deal with the first
problem, of v.reg tolerance, so I don't see d-h's trouble.

retrolefty

#21
Jan 02, 2013, 08:56 pm Last Edit: Jan 02, 2013, 08:58 pm by retrolefty Reason: 1

From dhenry's comments, I don't understand what his "specific" objections are.

In general, straightforward ADC readings using a microcontroller like Arduino will have
probably 2-5% error, at best. For 5V, that's as much as 0.25V.

First off, the v.reg voltages are not spot-on 5V, but will have up to 5% error, depending
upon the specific v.regs being used. Secondly, whenever you use a voltage divider, the
resistors also have their own tolerances, ranging from below 1% for high-precision parts
[and who uses these] to 5% for most discrete parts. Therefore, any ADC measurements
will be off from the get-go. You can use a precision voltage-reference, but still must
use precision resistors in the voltage dividers for best results.

It seems to me that the majenko page has some good info to help deal with the first
problem, of v.reg tolerance, so I don't see d-h's trouble.



Well there are pretty simple methods to deal with both the 'problems' you addressed. First it's possible with proper coding to have an arduino measure it's own exact Vcc voltage to gain the proper value to convert counts to voltage readings. The second problem is easily deal with by using a 10 turn pot (say 5K ohms) for the voltage divider and set it for the division ratio you desire using a DMM to verify that it's accurately set.

Now if either or both those are really needed or even desired depends on the application and it's accuracy requirements or assumptions.

Lefty

Code: [Select]

// 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 * 1024L) / ADC) + 5L) / 10L; // calculates for straight line value
     return results;

    }


Boopidoo

Thanks, that code looks very interesting.

Also a question regarding resistor tolerances. These are manufacturing tolerances right? The resistors themselves does not "change" their resistance over time, right? If so then this problem should be overcome by just measuring them and using that exact value in my code. The projects I make is for myself and will not be mass produced hence it's ok for me to measure each resistor manually.

Also I have some 1% and some 5% resistors, the former is much closer to their specified value, of course, but is there any other benefits to use these over the ones with lower tolerances? As I said I do measure them prior to installation.

oric_dan

Resistors will change their values with temperature changes.

Quote
measure it's own exact Vcc voltage

What you mean by "exact"? I've seen nothing "exact" in this analog world. Also, on
further looking, the bandgap reference in the ATmega 328P datasheet is only specified
to within 10% <-- gakk!


Boopidoo

Using that code I got the following when powered over the USB:

USB
Battery Vcc volts =  5.03 (serial printer)
Analog pin 0 voltage = 1.09 (serial printer)
Analog pin 0 voltage = 1.11 (using my meter)

3S external power
Battery Vcc volts =  4.94 (serial printer)
Analog pin 0 voltage = 2.84 (serial printer)
Analog pin 0 voltage = 2.89 (using my meter)

That's pretty good, next I'll try to use these values and update my code to see what I'll get. If I get a consistent difference <2% I guess I can live with that.

Go Up