One led voltmeter (Part 3)

Part 1, 2, 3, 4

Playing a little bit with regsiters

Let’s proceed step by step to the details of the A/D converter. Firstly, we will pay attention to the ADMUX register.

The four least significant bits: MUX0, MUX1, MUX2 and MUX3 are used for setting the mux channel, which is strictly equivalent to passing the channel parameter to the analogRead(channel) function. Next bit is always empty. Next bit is tricky. The A/D digital value (10 bits) is stored in two registers (8 bits each). If the ADLAR is set to 1, the bits are left aligned. Which means that the 8 upper bits (MSB) from the A/D conversions are stored in bits 7 to 0 from one register (ADCH), while the two lower bits (LSB) are stored in bit 7 and 6 from an other register (ADCL). If the ADLAR is set to 0, the bits are right aligned. Which means that the 2 upper bits (MSB) from the A/D conversions are stored in bits 1 and 0 from ADCH, while the eight lower bits (LSB) are stored in bit 7 to 0 from ADCL. Why? Because, depending upon the required precision, we may save a little measuring time by reading only the 8 most or least significant bits, instead of the 10 bits, which are read in two steps. Believe me, it makes a lot of sense when you start competing with sampling time in DSO applications for exemple, where 8 bits are enough.
And at last, let’s talk about the two upper bits! The type of voltage reference depends on the combination of REFS0 and REFS1 as per the following table:

void loop(){
  // Read voltage value
  int tenthsVolts;
  // Set ADMUX register: REFSO bit = 1 in any case
  ADMUX = (1 << REFS0);
  int DACValue = analogRead(inputVoltagePin);
  if (DACValue < 200) { // Approx. less than 1 V in digital counts
    ADMUX |= (1 << REFS1); // Set REFS1 bit
    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(fracPart, DEC);
  Serial.println(" V");
  // Flash Volts
  toggleLed(integerPart, 500, 500);
  // Pause
  // Flash tenths of Volt
  toggleLed(fracPart, 100, 500);
  // Pause between readings

OK, this one is easy, next one shall be a little bit more tough 😉

Next post on same subject

Leave a Reply

You must be logged in to post a comment.