One led voltmeter (Part 3)
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("."); 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); }
OK, this one is easy, next one shall be a little bit more tough 😉