Arduino – Calculate VCC
A little known feature of many AVR chips is the ability to measure the internal analog voltage reference. This trick can be used in all sorts of ways such as:
- Monitoring battery voltage to your Arduino
- Checking to see if A/C power is running
- Improve accuracy of analogRead() in many situations
The way to perform these feats is use the internal reference to actually measure Vcc. In the code following, we will actually measure the internal voltage reference, and then use this value to calculate our actually Vcc. Here is the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
long readVcc() { // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0) ; #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Start conversion while (bit_is_set(ADCSRA,ADSC)); // measuring uint8_t low = ADCL; // must read ADCL first - it then locks ADCH uint8_t high = ADCH; // unlocks both long result = (high<<8) | low; result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 return result; // Vcc in millivolts } |
There are some limitations in accuracy due to tolerances on the internal voltage reference. You can however, calibrate the scale factor for greater accuracy. This code runs on all Arduino variants as well as the ATtinyx4 series chips.
Bron: https://www.instructables.com/Secret-Arduino-Voltmeter/
Other example
Another option which does not require a voltage divider is to use Vcc as a reference to measure both the analog input and the internal 1.1 V “bandgap“ reference. Measuring the 1.1 V against Vcc is an indirect way to measure Vcc. This is not supported by the Arduino core library, but you can do it by programming directly the control registers of the ADC:
1 2 3 4 5 6 7 8 9 10 |
// Return the supply voltage in volts. float read_vcc() { const float V_BAND_GAP = 1.1; // typical ADMUX = _BV(REFS0) // ref = Vcc | 14; // channel 14 is the bandgap reference ADCSRA |= _BV(ADSC); // start conversion loop_until_bit_is_clear(ADCSRA, ADSC); // wait until complete return V_BAND_GAP * 1024 / ADC; } |
Beware that the very first reading after boot may be bogus.
Source: https://newbedev.com/does-adc-conversion-to-a-voltage-rely-on-the-actual-value-of-the-5-v-pin