## One led voltmeter (Part 2)

Part 1, 2, 3, 4

Auto ranging

This improvement is quite easy, and it may be useful in some circumstances. Arduino contains in fact one A/D converter which is connected to an 8 ports multiplexer: 6 of them are available from the 28 DIL PDIP package, the one which is used on Arduinos.

Before getting too far with A/D converter, we will mention that this function uses a reference voltage which is the scale for measuring input voltages. This scale ranges from 0 to 1023 (2^n-bits -1, with n-bits=10 on ATMEAG 168 series), resulting in 1023 steps. But! For the ease of use, Vref is converted to 1024.
In all cases, the low end of the scale is ground, resulting in a “0” digital value. In the high end of the scale, well, we have the choice! By default, it is equal to 5V, Vcc, and it results in a “1024” digital value. This means that the resolution is 5/1024, approximately 5 mV. Fair enough for most hobbies oriented applications. Note that it would have been so nice to have an internally built voltage reference set to 4.096 V…, 4 mV resolution…, 4, such a nice multiple, easily divided using 2 shifts…

Anyway, 5 Volts full range is fine for many applications. However, we have a few bits left for the measurement of sub volts values. Except if we use the Selectable 1.1V ADC Reference Voltage! Now that the upper range of the scale is 1.1 V, the resolution is approximately 1 mV. Switching from one mode to the other is very easy: use the analogReference(parameter) function. The parameters for this function can be :
– DEFAULT: the default analog reference of 5 volts
– INTERNAL: an built-in reference, equal to 1.1 volts on the ATmega168 or ATmega328
– EXTERNAL: the voltage applied to the AREF pin is used as the reference.

Oh, I see that we can use an external reference! Yes you can. Under these conditions, the internal reference voltage is disconnected from the Vref line. Keep in mind that this source of voltage must be as stable as possible and noise free: consider filtering properly this line. There are thousands of references available, among which high reputation chips from Maxim Dallas . And again, if you kindly ask samples, they will send a couple of them for free.

```/*
One led voltmeter or 'the voltmeter of the poor'
Reads analog port 0 from a bare Arduino board
Count long lasting flashes for volts and short lasting flashes for tenths of volts
Special features:
- Auto-ranging
The routine will also print value on serial comm port

No warranty, no claims, just fun
Didier Longueville invenit et fecit May 2010
*/
int inputVoltagePin = 0;

void setup(){
DDRB  |=  (1 << PINB5); // Led pin
PORTB &= ~(1 << PINB5); // Turn led off
toggleLed(5, 200, 200);
Serial.begin(115200);
}

void toggleLed(int cycles,int onTime, int offTime) {
for(int i=0; i < cycles; i++){
PORTB |=  (1 << PINB5); // Turn led on
delay(onTime);
PORTB &= ~(1 << PINB5); // Turn led off
delay(offTime);
}
}

void loop(){
int tenthsVolts;
analogReference(DEFAULT);
if (DACValue < 200) { // Approx. less than 1 V in digital counts
analogReference(INTERNAL);
tenthsVolts = (DACValue * 11L) >> 10;
Serial.print("Internal ref.: ");
}
else {
tenthsVolts = (DACValue * 50L) >> 10;
Serial.print(" Default ref.: ");
}
// Compute integer and fractional parts
int integerPart = (tenthsVolts / 10);
int fracPart = (tenthsVolts % 10);
// Send formated value to serial comm port
Serial.print(integerPart, DEC);
Serial.print(".");
Serial.print(fracPart, DEC);
Serial.println(" V");
delay(1000);
// Flash Volts
toggleLed(integerPart, 500, 500);
// Pause
delay(1000);
// Flash tenths of Volt
toggleLed(fracPart, 100, 500);