// 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;
}