// Calculates the VCC voltage in an Arduino Nano/Uno/Mega board using the internal bandgap reference.
// The user must measure the internal bandgap reference (InternalReferenceVoltage)
// using my function: Determine_internal_bandgap_voltage.
// Useful if using a battery to power the Arduino from pin 5V so we can measure the battery voltage.
// Also useful if a correct value of Vcc is needed for internal calculations.
// Works for 168/328 and mega boards.
// Made by Juan 02/2025.
// Based in a "retrolefty" original code.
// https://forum.arduino.cc/t/measurement-of-bandgap-voltage/38215/17
void setup()
{
  Serial.begin(9600);
  Serial.println("Welcome to the internal Vcc measurement tool.");
  Serial.println("Measure the bandgap voltage with my other program.");
  Serial.println();
  delay(100);
}
    
void loop()
{
  int Vcc = getVcc();
  
  // Ver si es necesario promediar estos valores o dan más o menos lo mismo.
  
  Serial.print("The Vcc voltage is (in mV) = ");
  Serial.println(Vcc);
  delay(1000);
}
int getVcc()
// Returns the Vcc voltage (in mV).
{
  constexpr long InternalReferenceVoltage = 1056L;  // Adjust this value to your boards specific internal BG voltage in mV.
  #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 ) );
  int result = ((InternalReferenceVoltage * 1024L) / ADC) + 5L; // calculates for straight line value.
  return result;
}