The analogRead() reads the value from an analog pin using analog-digital(AD) converter.
The Arduino Uno has 6 10-bit AD converters. The analogRead() 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.
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||1||Internal reference voltage(1.1V in case of Arduino Uno)||INTERNAL(3)|
The ADLAR determines 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 disabled in Arduino software.
The ADCSRA(ADC Control and Status Register A) is a register to control AD conversion.
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 finishing 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) control 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.
To get 10bit precision, clock from 50kHz to 200kHz must be supplied. If you need less precision, you can supply higher clock. The Arduino software sets the ADPS to 0b111, 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 conversion.
ADCH and ADCL
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.
The analogRead() is defined in hardware/arduino/avr/cores/arduino/wiring_analog.c as below. Only the source code for Arduino UNO is quoted. The original source code supports many tips using #if’s.
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.
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 considers the user used the symbol. Analog pins can be used as digital pins, the A0 is defined as 14.
Next ADMUX register is set.
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 explicitly, it is 0.
This is why we can not use internal temperature sensor with 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.
Wait for the conversion to finish.
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 bit of ADCSRA register becomes 0.
Reading ADCL and ADCH, where the result of the conversion is stored, and connect them to make 16bit value.
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 AVR core 1.8.3
May 15, 2021