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:
-
I don't get the question. The idea is not to measure the 3.3v or 5v using the internal reference voltage as a reference, but the other way around. You measure the internal reference voltage in relation to Vcc.Gerben– Gerben04/24/2016 18:26:15Commented Apr 24, 2016 at 18:26
-
Thanks. Do you know how I should change the code or the measurements then? I thought measuring Vcc using the internal reference would allow me to calculate how my particular internal reference varies from 1.1V.Paul Grime– Paul Grime04/24/2016 18:47:04Commented Apr 24, 2016 at 18:47
-
After reading your question one more time, I finally get it. Forget what I said, as it's not related.Gerben– Gerben04/25/2016 14:56:07Commented Apr 25, 2016 at 14:56
1 Answer 1
The internal reference won't change much. That's why it's a reference.
Running this code on my Atmega328P:
void setup ()
{
ADMUX = bit (REFS0) | bit (REFS1); // Internal 1.1V reference
}
void loop () { }
That outputs the reference voltage on Aref. I measured it as follows with different values for Vcc:
Vcc Aref
------------
5.00 1.085
4.00 1.081
3.30 1.080
3.00 1.079
So you can see that it retains, more or less, the same voltage regardless of Vcc. In any case, there is no way of measuring Aref, unless you have another reference voltage around to compare it to.
-
Thanks. So do I measure the voltage on the AREF pin with a multimeter to calibrate an individual chip? I'm sure I read somewhere that the internal voltage reference was never made physically available externally. I'm still not clear on how to fine tune an individual chip to get more accurate voltage readings of the battery powering the chip.Paul Grime– Paul Grime04/25/2016 06:34:56Commented Apr 25, 2016 at 6:34
-
What I posted above was done by measuring with a multimeter after running that code which puts the internal voltage reference onto the Aref pin. And yes, it varies from chip to chip. As you can see, mine is slightly under 1.1V.04/25/2016 09:29:57Commented Apr 25, 2016 at 9:29
-
Thanks. I measure 1.078V on AREF (using multimeter) following your sketch, but when I use that value as the InternalReferenceVoltage value (from your "Internal Voltage Sensor" code - gammon.com.au/adc) I get 4.35V printed, when my voltage is 5.16V. I measure Vcc continuously in the loop. Confused.Paul Grime– Paul Grime04/25/2016 16:30:04Commented Apr 25, 2016 at 16:30
-
What raw ADC reading do you get? Mine reads low (4.95V - raw reading: 226) but not that low. See this thread on AVR Freaks - it appears that there are some inconsistencies between theory and practice.04/25/2016 23:14:53Commented Apr 25, 2016 at 23:14
-
The difference between 4.95V and 5V (that I got) is only 1%, so that is probably acceptable for checking input voltage. Your results of 4.35V sounds like some sort of error. I tried a different approach using an external reference voltage (TL431 chip) and got better results. I can amend my answer if you want to see that. However that may have other drawbacks (depending on whether you are using the analog inputs for other purposes as well).04/26/2016 00:48:01Commented Apr 26, 2016 at 0:48