Hello,
I'm trying to use the "bandgap" method for measuring VCC (the battery voltage) of a battery powered Arduino. In all of these examples, they seem to suggest that I don't need to wire up the VCC to an analog pin. How are they doing that?
I understand that they're using the internal 1.1V reference and measuring it against VCC...but don't they need to use one of the analog pins and connect VCC to it? Or is there a magical command that lets you read VCC as an analog input between 0-1023? Is there really no extra wires I have to add to any pin?
There are two popular links that people use as reference:
http://jeelabs.org/2012/05/04/measuring-vcc-via-the-bandgap/#comments
http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/
I don' t know what some of the code does - for example, the Jeelab code
-
What does the ADMUX and bitSetwaiting do?
-
returns (55U * 1023U) / (ADC + 1) - 50;...what's the U mean? It's not a variable that's been declared?
In general, I'd like to translate some of the confusing lines of code.
Jeelab's example code:
#include <JeeLib.h>
#include <avr/sleep.h>
volatile bool adcDone;
ISR(WDT_vect) { Sleepy::watchdogEvent(); }
ISR(ADC_vect) { adcDone = true; }
static byte vccRead (byte count =4) {
set_sleep_mode(SLEEP_MODE_ADC);
ADMUX = bit(REFS0) | 14; // use VCC and internal bandgap
bitSet(ADCSRA, ADIE);
while (count-- > 0) {
adcDone = false;
while (!adcDone)
sleep_mode();
}
bitClear(ADCSRA, ADIE);
// convert ADC readings to fit in one byte, i.e. 20 mV steps:
// 1.0V = 0, 1.8V = 40, 3.3V = 115, 5.0V = 200, 6.0V = 250
return (55U * 1023U) / (ADC + 1) - 50;
}
void setup() {
rf12_initialize(17, RF12_868MHZ, 5);
}
void loop() {
byte x = vccRead();
Sleepy::loseSomeTime(16);
rf12_sleep(RF12_WAKEUP);
rf12_sendNow(0, &x, sizeof x);
rf12_sendWait(2);
rf12_sleep(RF12_SLEEP);
Sleepy::loseSomeTime(1024);
}
provideyourown.com's example code
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);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#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
}