1

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:

asked Apr 24, 2016 at 15:02
3
  • 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. Commented 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. Commented 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. Commented Apr 25, 2016 at 14:56

1 Answer 1

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.

answered Apr 25, 2016 at 5:30
7
  • 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. Commented 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. Commented 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. Commented 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. Commented 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). Commented Apr 26, 2016 at 0:48

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.