Playing with Arduino

A page to record my playing with Arduino



The analogRead() reads the value from analog pin using analog-digital(AD) converter.

The Arduino Uno has 6 10-bit AD converters. The analgoRead() uses 4 registers named ADMUX, ADCSRA, ADCL and ADCH.


The ADMUX(ADC Multiplexer Selection Register) controls the reference voltage, the presentation of the ADC conversion(left adjust or right adjust) and analog channel selection.

bit 7 6 5 4 3 2 1 0

The REFS0 and REFS1 set the reference voltage. The meanings of the combination of these bits are shown in the next table.

REFS1 REFS0 Meanings Argument of analogReference()
0 0 Voltage applied to AREF pin. EXTERNAL(0)
0 1 Default referece voltage(5V in case of Arduino Uno). DEFAULT(1)
1 0 Reserved. -
1 1 Internal reference voltage(1.1V in case of Arduino Uno) INTERNAL(3)

The ADLAR detemins the presentation of the ADC conversion result. If it is 1, the ADC conversion result is left adjusted. If 0, right adjusted. It is set to 0, right adjusted, by the Arduino software.

MUX0 to MUX3 selects the analog pin.

If MUX3...MUX0 is 1000, it reads the value from an internal temperature sensor. But the ability to read internal temperature sensor is dsiabled in Arduino software.

MUX3 MUX2 MUX1 MUX0 Analog Pin
0 0 0 0 0
0 0 0 1 1
0 0 1 0 2
0 0 1 1 3
0 1 0 0 4
0 1 0 1 5


The ADCSRA(ADC Control and Status Register A) is a register to control AD conversion.

bit 7 6 5 4 3 2 1 0

Setting the ADEN to 1 enables the AD conversion. The init() which is called from the main() sets the bit.

Setting theADSC(ADC Start Conversion) to 1, the chip begins AD conversion. While AD conversion is executed, this bit is 1. After the conversion, it becomes 0.

The ADATE(ADC Auto Trigger Enable) controls automatic trigger of AD conversion. The bit is not used by the Arduino software.

The ADIF(ADC Interrupt Flag) and ADIE(ADC Interrupt Enable) controls the interruption. The bits are not used by the Arduino software.

The ADPS are the bits to determine the division factor between the system clock frequency and the input clock to the AD converter.

ADPS2 ADPS1 ADPS0 Division Factor
0 0 0 2
0 0 1 2
0 1 0 4
0 1 1 8
1 0 0 16
1 0 1 32
1 1 0 64
1 1 1 128

To get 10bit precision, from 50kHz to 200kHz clock must be supplied. If you need less precision, you can supply higher clock. The Arduino software sets the ADPS to 0b011, that is, the division factor is 128. As Arduino Uno uses 16Mhz system clock, the clock to the AD convert is 125kHz(=16MHz/128). It requires 13 clock for conversion, it takes 0.000104(=1/125kHz*13) seconds or 104 micro seconds to execute AD cnversion.


The ADCH and ADCL are the registers to store the result of the AD conversion. The ADLAR bit of the ADMUX register controls how the result is stored. The Arduino software sets the ADLAR to 0, the first 2 bits of the conversion result is stored in ADXH and the remaining 8 bits are stored in the ADXL.

Source Code

The analogRead() is defined in hardware/arduino/cores/arduino/wiring_analog.c as below. Only the souce code for Arduino UNO is quoted. The original source code supports many tips using #if's.

int analogRead(uint8_t pin)
        uint8_t low, high;

        if (pin >= 14) pin -= 14; // allow for channel or pin numbers

        // set the analog reference (high two bits of ADMUX) and select the
        // channel (low 4 bits).  this also sets ADLAR (left-adjust result)
        // to 0 (the default).
        ADMUX = (analog_reference << 6) | (pin & 0x07);

        // start the conversion
        sbi(ADCSRA, ADSC);

        // ADSC is cleared when the conversion finishes
        while (bit_is_set(ADCSRA, ADSC));

        // we have to read ADCL first; doing so locks both ADCL
        // and ADCH until ADCH is read.  reading ADCL second would
        // cause the results of each conversion to be discarded,
        // as ADCL and ADCH would be locked when it completed.
        low  = ADCL;
        high = ADCH;

        // combine the two bytes
        return (high << 8) | low;

The input argument is pin and its type is uint8_t. It returns int, the result of the AD conversion which is 10 bits.

First, pin number is converted.

        if (pin >= 14) pin -= 14; // allow for channel or pin numbers

The analog pin is represented by number, for example 0, or symbol, for example A0. In Arduino Uno the A0 is defined as 14, A1 is 15 and so on. See hardware/arduino/variants/standard/pins_arduino.h. So if the pin is higher than 14, the function consider the user used the symbol. Analog pins can be used as digital pins, the A0 is defined as 14.

Next ADMUX register is set.

        ADMUX = (analog_reference << 6) | (pin & 0x07);

The analog_reference, which is set by analogReference(), is set to REFS1 and REFS0 of the ADMUX. The logical OR of analog_reference <<6 and logical AND of pin and 0x07 is set to ADMUX. The ADLAR is not set explisitly, it is 0.

This is why we can not use internal temperature sensor by Arduino Uno. To use the internal temperature sensor, we need to set the MUX3...MUX0 to 0b1000, but this calculation forces the MUX3 to 0.

Now AD conversion is started.

        sbi(ADCSRA, ADSC);

The sbi() is a macro to set the bit(the second argument) of the address(the first argument) to 1. Setting the ADSC bit of ADCSRA to 1 begins the AD conversion.

Wait for the conversion to finish.

        while (bit_is_set(ADCSRA, ADSC));

The bit_is_set is a macro that checks if the second argument bit of the first argument is 1. If the conversion finishes, the ADSC of ADCSRA becomes 0.

Reading ADCL and ADCH where the result of the conversion is stored, and connect them to make 16bit value.

        low  = ADCL;
        high = ADCH;
        return (high << 8) | low;

Once the ADCL is read, the value of the ADCH would not be changed unless the ADCH is read. So the ADCL must be read before reading the ADCH.


Arduino 1.0.5

Turn on JavaScript to display a menu.

Playing with Arduino
Copyright © 2012 garretlab all rights reserved.
inserted by FC2 system