If you supply your Arduino or ATmega/ATtiny using a battery you might want to be warned, when the battery is almost empty so you can replace it. To do this you can monitor the supply voltage. If it drops below a defined threshold you can for example turn on a LED to be warned.
Monitoring the voltage can be done without any additional hardware by using the microcontrollers analog digital converter. As you might know, the value of the ADC is calculated using the following formula:
VALUE_ADC = V_INPUT * 1023/V_REF
Now you could think: "I'll just take my supply voltage as input voltage for the ADC" but that won't work since the supply voltage is also used as reference voltage. The value of the ADC would always be 1023.
But there is a trick: every microcontroller generates an internal reference voltage, the so called "bandgap voltage" V_BG. At the ATmega328 which is used in die Arduino Uno, the bandgap voltage is 1.1V. You can use this voltage as input für your ADC.
With V_INPUT = V_BG and V_REF = V_CC you get:
VALUE_ADC = V_BG * 1023/V_CC
or:
V_CC = V_BG * 1023/VALUE_ADC
With V_BG = 1100 (in mV) you get:
V_CC = 1100 * 1023/VALUE_ADC
Where V_CC is the value of your supply voltage in mV.
The code for the Arduino Uni is:
int led = 13; //pin of the LED int adc_low, adc_high; //buffer for the results of the ADC long adc_result; //10bit result of measurement of ADC long vcc; //supply voltage void setup() { pinMode(led, OUTPUT); ADMUX |= (1<<REFS0); //VCC as reference for ADC ADMUX |= (1<<MUX3) | (1<<MUX2) | (1<<MUX1); //1.1V bandgap voltage as input of ADC delay(10); //wait until reference voltage is set ADCSRA |= (1<<ADEN); //enable ADC } // the loop routine runs over and over again forever: void loop() { ADCSRA |= (1<<ADSC); //start measurement while (bitRead(ADCSRA, ADSC)); //wait until measurement is completed //buffer results. Important: read ADCL first! adc_low = ADCL; adc_high = ADCH; adc_result = (adc_high<<8) | adc_low; //10bit result vcc = 1125300L / adc_result; //calculate supply voltage in mV (1100mV * 1023 = 1125300) //if supply voltage is lower then 5V if (vcc < 5000) { digitalWrite(led, HIGH); //turn on LED } else { digitalWrite(led, LOW); //turn of LED } delay(500); }
In setup()-function the ADC is configured to use the supply voltage V_CC als referenz and the bandgap voltage V_BG as input. Then the ADC is enabled.
In loop() the measurement is started by setting the bit ADSC. When it's finished (bit ADSC is cleared) the result of the conversion is read from the registers ADCL (lower 8 bits) and ADCH (upper 2 bits) and merged to a 10-bit-result. Using this result, the supply voltage is calculated. If it is uner 5V, the LED is turned on.
This method works with every ATmega oder ATtiny. Depending on the µC you might have to set different bits in the registers of the ADC. Check the datasheet of your microcontroller.