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
  // Blink status led
  toggleLed(5, 200, 200);
  Serial.begin(115200);
  Serial.println("Ready");
}

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(){
  // Read voltage value
  int tenthsVolts;
  analogReference(DEFAULT);
  int DACValue = analogRead(inputVoltagePin);
  if (DACValue < 200) { // Approx. less than 1 V in digital counts
    analogReference(INTERNAL);
    DACValue = analogRead(inputVoltagePin);
    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);
  // Pause between readings
  delay(1000);                  
}

Important: Please note that the other way around does not work. I mean, evaluating the input voltage using the internal reference, and switching to DEFAULT if the digital value exceeds the limit does not work and leads to un predictable results! Probably due to the principle of operation of the A/D converter which includes the loading of a capacitor.

Next post on same subject

Leave a Reply

You must be logged in to post a comment.