// Calculates the internal bandgap voltage value of an specific Arduino Nano/Uno/Mega board.
// The user must measure the voltage between Vcc and Ground with accuracy and precision (i.e.: using a DMM).
// 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
long externally_measured_Vcc = 5000L; // In mV. This value must be measured by the user.
long InternalReferenceVoltage; // In mV. This value will be calculated by this program.
constexpr byte numChars = 64;
char readCstring[numChars];
boolean finished_reading_serial = false;
void setup(void)
{
Serial.begin(9600);
Serial.println("Welcome to the internal bandgap measurement tool.");
Serial.println("Measure the Vcc voltage with a DMM.");
Serial.println("End input with EOL");
Serial.println( "\r\n" );
Serial.print("What is the measured voltage at Vcc? (in mV): ");
Serial.println();
delay(100);
}
void loop(void)
{
check_and_read_1_char_serial();
if (finished_reading_serial == true) {
externally_measured_Vcc = atol(readCstring);
Serial.print("Recieved: ");
Serial.println(externally_measured_Vcc);
InternalReferenceVoltage = getBandgap(externally_measured_Vcc);
Serial.print("The bandgap voltage is (in mV) = ");
Serial.println(InternalReferenceVoltage);
Serial.println();
delay(1000);
Serial.print("What is the measured voltage at Vcc? (in mV): ");
Serial.println();
finished_reading_serial = false;
}
}
int getBandgap(long externally_measured_Vcc)
// Returns the bandgap value (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 ) );
long result = (externally_measured_Vcc * ADC) / 1024L; // calculates for straight line value
return result;
}
void check_and_read_1_char_serial()
// Respeta lo que dice:
// https://forum.arduino.cc/t/serial-input-basics-updated/382007/2
// Made by Juan 02/2025.
{
static byte i = 0;
char endMarker = '\n';
char recievedChar;
while (Serial.available() > 0 && finished_reading_serial == false) {
recievedChar = Serial.read();
if (recievedChar != endMarker) {
readCstring[i] = recievedChar;
i++;
if (i >= numChars) {
i = numChars - 1;
Serial.println("Error, buffer overflow.");
}
}
else {
readCstring[i] = '\0'; // terminate the string
i = 0;
finished_reading_serial = true;
}
}
}