This tutorial shows how to implement the Analogue to Digital Converter (ADC) function on ATMega32 using C code. It consists of code examples, and the meaning of some nomenclature such as sampling rate, and resolution. However before we get to the code, let us start from the beginning. The ATMega32 has a built-in 10-bit ADC. The input to this ADC has a multiplexer to provide eight single-ended channels, where each channel can have a dedicated sensor such as an LDR or a Thermistor to provide an input voltage. These channels share the GPIO pins 33 to 40 on Port A. The output from the multiplexer feeds the non-inverting input of an operational amplifier with programmable gain. The gain is available in the following steps, 0 dB (1×), 20 dB (10×), and 46 dB (200×).
There is also an option to have three differential inputs by way of ADC5, ADC6, and ADC7, which feeds a second multiplexer connecting to the inverting input side of the op-amp.
From a hardware consideration, the AVCC pin provides voltage to the ADC circuitry and Port A also. This pin requires connection to the Vcc voltage supply, even when the ADC is not used. However when using the ADC, you should also include a filter capacitor as the ADC requires an extremely clean power supply.
The ADC also has a dedicated clock circuit, which allows the programmer to shut-off all the other clocks to reduce noise and therefore increase the precision of the ADC.
ADMUX Register
7 | 6 | 5 | 4 | 3 | 2 | 1 | |
REFS1 | REFS0 | ADLAR | MUX4 | MUX3 | MUX2 | MUX1 | MUX0 |
REFS1 | REFS0 | Methods for selecting Voltage Reference |
AREF, Internal Vref turned OFF | ||
1 | AVCC with external capacitor at AREF pin | |
1 | Reserved | |
1 | 1 | Internal 2.56 V Voltage Reference with external capacitor at AREF pin |
The ADC requires a reference voltage to determine the conversion range. The analogue signal for sampling must be between ground and Vref for capture.
For most applications, Vcc is sufficient by setting bit REFS0 to binary 1. Vcc is prone to noise so as a result an external decoupling capacitor helps filter this noise.
ADMUX |= _BV (REFS0);
Analog Channel and Gain Selection Bits
In the ADMUX register, the first four “MUX bits” organise as follows. The first seven numbers select single-ended input configuration. From eight onwards you can select a combination of differential inputs with different gain factors. The gain factor is available only for differential inputs.
MUX 4,3,2,1,0 |
Single Ended | +Differential Input |
-Differential Input |
Gain factor |
00000 | ADC0 | NOT AVAILABLE |
||
00001 | ADC1 | |||
00010 | ADC2 | |||
00011 | ADC3 | |||
00100 | ADC4 | |||
00101 | ADC5 | |||
00110 | ADC6 | |||
00111 | ADC7 | |||
01000 | N/A | ADC0 | ADC0 | 10× |
01001 | ADC1 | ADC0 | ||
01010 | ADC0 | ADC0 | 200× | |
01011 | ADC1 | ADC0 | ||
01100 | ADC2 | ADC2 | 10× | |
01101 | ADC3 | ADC2 | ||
01110 | ADC2 | ADC2 | 200× | |
01111 | ADC3 | ADC2 | ||
10000 | ADC0 | ADC1 | 1× | |
10001 | ADC1 | ADC1 | 1× | |
10010 | ADC2 | ADC1 | 1× | |
10011 | ADC3 | ADC1 | 1× | |
10100 | ADC4 | ADC1 | 1× | |
10101 | ADC5 | ADC1 | 1× | |
10110 | ADC6 | ADC1 | 1× | |
10111 | ADC7 | ADC1 | 1× | |
11000 | ADC0 | ADC2 | 1× | |
11001 | ADC1 | ADC2 | 1× | |
11010 | ADC2 | ADC2 | 1× | |
11011 | ADC3 | ADC2 | 1× | |
11100 | ADC4 | ADC2 | 1× | |
11101 | ADC5 | ADC2 | 1× | |
11110 | 1.22V (VBG) | N/A | ||
11111 | 0V (GND) |
In a simple case, we can use a single-ended input. Any port from ADC0 to ADC7 will work. The ADC port can be any number from 0 to 7 and passed through the following functions.
- ReadADC(uint8_t ADCport);
- ADCport=ADCport & 0b00000111;
- ADMUX|=ADCport;
ADCSRA – Control and Status Register
7 | 6 | 5 | 4 | 3 | 2 | 1 | |
ADEN | ADSC | ADATE | ADIF | ADIE | ADPS2 | ADPS1 | ADPS0 |
ADCSRA |= _BV (ADEN);
Bit 7 – ADEN: Set this to binary 1 to enable the microcontroller ADC circuits, whilst binary 0 will switch it OFF.
ADCSRA |= _BV (ADSC);
Bit 6 – ADSC: Setting ADSC bit to binary 1 starts the conversion process. This bit clears automatically when the conversion process completes. Therefore, this bit provides an indication that the conversion has completed.
While (ADCSRA & _BV (ADSC));
This while loop waits for the ADSC bit to become binary 0 again.
ADPS2, ADPS1, ADPS0
These bits determine the division factor between the XTAL frequency and the ADC input clock.
Converting an analogue signal to digital requires a clock frequency for the approximation circuitry. This principle is similar to the strips under a curve in maths class. The more strips the better the approximation of the analogue signal. A frequency between 50 kHz and 200 kHz is typical for maximum resolution.
The prescaler frequency is a fraction of the crystal frequency, usually achieved by using a division factor. The bits ADPS2, ADPS1, ADPS0, determine the division factor.
ADPS2 | ADPS1 | ADPS0 | Division Factor |
2 | |||
1 | 2 | ||
1 | 4 | ||
1 | 1 | 8 | |
1 | 16 | ||
1 | 1 | 32 | |
1 | 1 | 64 | |
1 | 1 | 1 | 128 |
16000000 / 128 = 125 kHz
This ATMega32 development board has a 16 MHz crystal; therefore, a division of 128 provides 125 kHz for the prescaler frequency.
ADCSRA |= _BV (ADPS2) | _BV (ADPS1) | _BV (ADPS0);
This value is within the maximum resolution range so we choose a prescaler division factor of 128 by setting bits ADPS2, ADPS1, ADPS0 to binary 1.
ADC Example C Code
This program displays the sampled ADC value on HyperTerminal, so you will need a working UART circuit. Make sure you have a working MAX232 interfacing circuit connected to the UART. Make sure you have tested the UART communications with HyperTerminal using uart.h and uart.c include files as shown in the following section. ATMega32 UART PC Interface – Testing