How to Use ADC (Analog to Digital Converter) in AVR – Atmega32

jojo May 19, 2017 1 Comment

Using LM35 Sensor and Atmega32 ADC to measure Temperature

Analog to digital conversion is generally needed whenever we deal with a sensor that produces an analog output (for example: LM35 temperature sensor), which is the case for a wide range of sensors. When dealing with such sensors we have to convert the analog signal coming out of them into digital words of ones and zeros so that our microcontroller can process it and make decisions based on it. In order to do that we need a device called an ADC (Analog to Digital Converter) and fortunately, many controllers now have this device built-in.

In this article, we shall learn about using the ADC of the Atmega32 to convert an analog signal to a digital one. As an example of an analog signal, we shall use the output signal coming out of the LM35 temperature sensor. By the end of this article, we will be able to make a simple fire alarm that triggers a buzzer when the temperature exceeds a certain limit (60 Celsius degrees as an example).

ADC Reference Voltage

The reference voltage is the maximum voltage you are expecting to receive from the sensor on the input channel of the ADC. In Atmega32 you can use one of three sources for the reference voltage:

  1. An internal voltage from within the Atmega32 MCU. This voltage is set to 2.56V and cannot be changed.
  2. The AVCC pin can be your reference voltage, but this pin must be connected to the VCC and in this case, your reference voltage is the VCC
  3. Finally, you can use your own customized reference voltage by connecting a voltage source that has the same value as the reference voltage you want to the pin AREF (pin32).

Choosing between these three sources of reference voltage happens while configuring the ADMUX register as we will explain later in this article. We will use the internal voltage option.

Hardware Requirements:

Before using the ADC of the Atmeg32 there are a few hardware connections required in the circuit so that you can get the best results:

  1. You should make sure that pins (VCC & AVCC) that are pins (10 & 30) are connected. This is because the ADC gets its power supply from the AVCC pin.
  2. If conversion accuracy is critical all the time, it is preferable that you connect a coil between the 2 pins and a capacitor between AVCC and GND. These 2 connections make the supply voltage of the ADC more stable and not easily fluctuated by noise.
  3. Also, it is preferable to connect a capacitor between AREF and GND so that the reference voltage of the ADC is more stable and not affected by noise. (Even if you choose to use the internal voltage or the AVCC)
  4. If you are going to use an external reference voltage, then you should connect it to the AREF pin. In this article, we will use the internal reference voltage so we will not need this step.

Atmega32 ADC Input Channels

ADC of the Atmega32 can accept inputs from up to eight channels. This means that you can connect up to eight analog input signals to the Atmega32 ADC, but at each conversion, only one channel input is converted. So, at each conversion, you should first choose the input channel to convert before starting the conversion. This is also done in the ADMUX register.

The input channels are multiplexed over the pins of port A of the ATmega32. These are the pins (33 to 40)

LM35DZ

LM35D is a temperature sensor of the LM35 temperature sensors family. It has 3 pins assigned as demonstrated in the below diagram. Where Vs is connected to the high voltage (VCC), GND is connected to GND and Vout is connected to the Input channel of the Atmega32 ADC

Important note: The pin-out diagram above (which is the same of the datasheet) is showing the sensor pin-out from the bottom view. So take care not to connect the sensor in reversed pin order.

The LM35 output voltage is linearly proportional to the temperature. It represents each 1 Celsius degree by 10 mV, so that if the temperature is 20 Celsius degrees, then the output voltage of the LM35 will be (20*10mV=200mV).

When the LM35 is connected as explained above it can detect temperatures between 2 and 150 Celsius degrees which means that the maximum output voltage will be (150*10mV=1500mV=1.5V). This means that we should use a reference voltage of 1.5V for best accuracy. However, for simplicity we can use the internal voltage (2.56V) and this is what we shall do in this article.

Temperature Calculation

The Atmega32 ADC has a resolution of 10 bits, which means that the output of the ADC will be a 10 bits binary word. This also means that the maximum output of the ADC will be the binary 1111.1111.11 that corresponds to a value of 1023 in decimal.

Now, as the maximum output of the ADC is 1023 and the maximum input is 2.56 (The Reference Voltage), then we can calculate the corresponding ADC output to an input of 10mV using the below equation:

LM35_Analog_to_Digital_Conversion_Equation

So, each 10mV will cause the ADC to output a value of 4, and as 10mV corresponds to 1 Celsius degree, then each Celsius degree will cause the ADC to output a value of 4. So, if the temperature is 20 Celsius degrees, the output of the ADC will be (20*4=80) and in binary this is (0001.0100.00). We will read this value from the ADCH and ADCL registers as we will explain.
So, as a conclusion in our case, we can calculate the temperature value from the ADC output using this equation:

ADC-equation

Software Requirements

Now, let’s get to the ADC Software configuration on the Atmega32

To enable the Analog to Digital Converter on Atmeg32 we need to do the following steps:

  1. In the ADMUX Register (ADC Multiplexer Selection Register):
    1. Set both bits (REFS1 & REFS0) to one. This tells the Atmega32 to use the internal voltage of 2.56 as a reference voltage.
    2. Clear the ADLAR bit to Zero. This will left adjust the ADC output (will be explained later in reading the ADC output)
    3. Choose the ADC input channel by setting the value of the 5 bits (MUX0…MUX4). In this article, we will clear them all to zero to choose the first input channel. This channel is the first pin in port A which is pin 40 of the Atmega32 IC. If you want to use another channel, check the below table to know the proper value for these bits.
MUX0 … MUX4 ADC input Channel
00000 ADC0
00001 ADC1
00010 ADC2
00011 ADC3
00100 ADC4
00101 ADC5
00110 ADC6
00111 ADC7

 

ADMUX Register
REFS1 REFS0 ADLAR MUX4 MUX3 MUX2 MUX1 MUX0
1 1 0 0 0 0 0 0
  1. In the ADCSRA Register (ADC Status Register A):
    1. Set bit ADEN to1. This enables the ADC.
    2. The ADC module needs a clock to work and it takes this clock from the MCU clock. However, the MCU clock is divided by a factor before it is fed to the ADC. This factor is determined by the bits (ADPS2, ADPS1, ADPS0) in the ADCSRA register. In this article, we will set the three bits to 1 so that the division factor is 128. If you want to use another division factor, check the below table for the proper value of these bits.
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

 

ADCSRA Register
ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0
1 0 0 0 0 1 1 1

 

Starting conversion and reading the ADC output

To start an analog to digital signal conversion, we set the 6th bit in ADCSRA (ADSC bit) to one. The ADC starts reading the analog signal immediately from the input channel (specified in ADMUX as explained above) and converts it to a digital 10-bit word. After finishing the conversion, the ADSC bit is cleared to zero again and the ADC module writes the output of the conversion (10-bits) in two registers named ADCH & ADCL. The bits are organized as demonstrated in the below figures.

Note the difference between ADLAR=0 and ADLAR=1. In this article, we had set ADLAR=0 in the ADMUX register.

If ADLAR=0:

ADC9 ADC8 ADCH
ADC7 ADC6 ADC5 ADC4 ADC3 ADC2 ADC1 ADC0 ADCL

 

If ADLAR=1:

ADC9 ADC8 ADC7 ADC6 ADC5 ADC4 ADC3 ADC2 ADCH
ADC1 ADC0 ADCL

 

When reading the ADC output, we should read ADCL first then read ADCH. This is because reading ADCL, informs the ADC module that a read process is in progress and so no conversions happen until the ADCH is read as well.

In our program, we will convert the output of the LM35 from analog to digital using the first ADC channel, we will turn on a buzzer that is connected to pin5 in port D when the temperature exceeds 60 Celsius degrees.

Below is the schematic, program code, pictures of the circuit and a video for the demonstration.

Circuit Diagram

LM35 to AVR

Circuit Schematic – LM35 to AVR Atmega32

Program/Code

#define get_bit(reg,bitnum) ((reg & (1<<bitnum))>>bitnum)

#include <avr/io.h>


int main(void)

{
       int ADCOut=0;

char Temperature;

       DDRD=0b00010000; // set pin 4 on port D as output to control the buzzer

       DDRA&=~(1<<0);

       ADMUX=0b11000000;

ADCSRA=0b10000111;


       while(1)

       {

        ADCSRA|=(1<<6); //Set bit 6 n ADCSRA to start conversion

              while(get_bit(ADCSRA,6)==1) // poll bit 6 n ADCSRA till it is back to zero again

              {

              }


              ADCOut=ADCL|(ADCH<<8); // Save the ADC reading into an integer variable ADCOut. The ADCL must be read first as written here.

              Temperature=ADCOut/4; // Calculate Temperature


              if (Temperature>=60) // Check if temperature is above 60 Celsius degrees

              {

                     PORTD|=(1<<4); //turn on the buzzer

              }

              else

              {

                     PORTD&=~(1<<4); //turn off the buzzer

              }

    }

}

Output Photograph

LM35_AVR

I implemented this circuit on my AVR development board. If you have any doubts, please feel free to ask in the comments section.

Demonstration Video


I hope you all enjoyed my tutorial!

 

Comments
  • Ogu Reginald
    May 20, 2017

    Good tutorial, which IDE did you use for the coding?

Leave a Reply to Ogu Reginald Cancel reply

Your email address will not be published. Required fields are marked *