Arduino MEGA Reading Input Voltage

As many of you are probably aware it is possible to read the input voltage of an AVR against its internal bandgap reference using some funky register tricks. However I have only seen it done on Arduinos based on the 168/328/32u4 platform… So I set about trying some hackery to make it work on the Arduino MEGA with the 2560/1280 processors.

It took a little while but i think i’ve cracked it, although it may still require further tweaks which your more than welcome to add :slight_smile:

Henceforth the code for doing it is shown below. Use it, abuse it, tweak it, change it and report back if you find a better solution. Just don’t come whining to me if it doesn’t work on your system.

The function returns the value of the V+ rail in MILLIVOLTS (mV) as a long variable. And uses the MEGAs internal reference similar to the solution posted here as it is based off it. No plagiarism intended, just thought it might help some others like me looking for a MEGA solution.

long readVCC() {
long result;
// Read 1.1V reference against AVcc
ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(10); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Convert
while (bit_is_set(ADCSRA, ADSC));
result = ADCL;
result |= ADCH << 9;
result = 8500000L / result; // Back-calculate AVcc in mV
return result;

Please also be aware the delay time is required as the registers are a bit wobbly after being set… Not sure why, they just are… :stuck_out_tongue:

Have a nice day everyone :smiley:

Did you make that from scratch ? I think that code already exists, I'm using it already for a while.

You shift ADCH with 9 bits, but it should be 8 bits. You don't even have to use ADCL and ADCH, use 'ADCW' and the compiler will read both. I also clear register ADCSRB.

I think the calculation with a fixed 8500000L is not okay, since every ATmega2560 has a different voltage for the 1.1V. My ATmega2560 has 1.079V (only 2% inaccurate, but it makes a big difference).

I do reading the own Vcc for number of ATmega chips, and the ATmega2560 gives me the most trouble. The analog reading after this is inaccurate. So I have added delays and a few dummy ADC conversions, trying to get back to the normal situation.