Measure different Vcc using 1.1V bandgap
When I power my ATmega328P chip from 5.16V and 3.3V, there doesn't seem to be a single bandgap voltage compensation figure that works for both.
I'm using the following sketch, and I need the following InternalReferenceVoltage
values to read the correct voltage from A0
:
1255L
to correctly output 5.16V.1358L
to correctly output 3.3V.
I have a couple of questions:
- Should I be able to use a single
InternalReferenceVoltage
compensation value whe powering the ATmega328P from different voltages? - Aren't both of these values outside the specced 1.0 to 1.2 range?
The code is from, http://forum.arduino.cc/index.php?topic=56750.msg407897#msg407897, retolefty post @ Mar 28, 2011, 02:27 pm.
#include <SPI.h>
void setup()
{
delay(5000);
Serial.begin(115200);
}
void loop(void)
{
// Determines what actual Vcc is, (X 100), based on known bandgap voltage
int battVolts = readVcc1();
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);
}
// Returns actual value of Vcc (x 100)
int readVcc1()
{
uint8_t oldADMUX = ADMUX;
const long InternalReferenceVoltage = 1255L; // Adjust this value to your boards specific internal BG voltage x1000
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// For mega boards
// 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
// 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
ADMUX = oldADMUX;
return results;
}
I have read these other references to try and find a solution: