// Code that reads with presition the voltage in PIN 0 (because Vcc is usually not simply 5.000 V).
// The user must measure the internal bandgap reference (InternalReferenceVoltage)
// using my function: Determine_internal_bandgap_voltage.
// Refurbished by Juan 02/2025.
// Original idea:
// 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"
constexpr byte READ_PIN_V = 0; // Analog pin form where you read the voltage.
int Vcc_measured; // 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)
{
Vcc_measured = getVcc(); //Determins what actual Vcc is, (in mV), based on known bandgap voltage
Serial.print("Vcc volts = ");
Serial.println(Vcc_measured);
Serial.print("Analog pin voltage = ");
Serial.println(map(analogRead(READ_PIN_V), 0, 1023, 0, Vcc_measured));
Serial.println();
delay(1000);
}
int getVcc(void)
// Returns the Vcc voltage (in mV).
{
#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; // calculates for straight line value
return results;
}