Implementation of ADC in AVR
Welcome readers, in this blog, we will learn ADC and how to implement it.
Let’s start with the first word, What exactly is AVR?
First of all, AVR is a family of microcontrollers developed by Atmel corporation beginning in 1996. The original meaning of “AVR” letters is not defined officially yet, sometimes Atmel says it means nothing in particular, and sometimes Atmel has said it means "AdVanced Risc" or "Advanced Virtual Risc", but if you dig deeper:
AVR = "Alf (Egil Bogen) and Vegard (Wollan) 's Risc processor", huh? Maybe
The AVR is basically a modified Harvard architecture machine, where programs and data are stored in separate physical memory systems (i.e they appear in different address spaces) but it has the ability to read data items from program memory using special instructions.
In the AVR family, it has a lot of members based on their program memory, pin packages and other features. tinyAVR/ATTiny series, megaAVR/ATmega series, XMEGA, FPSLIC and many more. Flash, EEPROM, and SRAM are all integrated into one single chip, that’s why you don't need external memory in most applications. Some devices have a parallel external bus option to allow adding additional data memory or memory-mapped devices.
Now the second one ADC basically means Analog to digital conversion. In electronics, an analogue-to-digital converter (ADC, A/D, or A-to-D) is a system that converts an analogue signal, such as a sound picked up by a microphone or light entering a digital camera, into a digital signal. An ADC is used in electronic devices that convert an input analogue voltage or current to a digital number that represents the magnitude of the voltage or current. An ADC converts a continuous-time and continuous-amplitude analogue signal to a discrete-time and discrete-amplitude digital signal. The conversion involves quantization of the input, as a result, it introduces a small amount of error or noise. Moreover, instead of continuously performing the conversion, an ADC does the conversion periodically, sampling the input, limiting the allowable bandwidth of the input signal. Now as you got some basic idea of ADC you have to be aware of some terms before we reach the coding part.
An analogue signal is continuous and it is necessary to convert this to a flow of digital values. It is therefore required to define the rate at which new digital values are sampled from the analogue signal. The rate at which new values are created from that analog continuous signal is called the SAMPLING RATE of the ADC. The converted digital signal can also be altered to its initial analogue form by using DAC(Digital to Analog Converter)
RESOLUTION of ADC :
The resolution of the converter indicates the number of different(i.e discrete)values it can produce over the allowed range of analogue input values. Let me take you through an example-
Let’s say the resolution of your ADC is 8-bits and the sensor you are using gives you an output of 0-5 volt. So in 8-bit binary value, the highest value we can get is ‘11111111’(i.e - 255 in decimal) and the lowest is ‘00000000’(i.e - 0 in decimal). Now you must have guessed that when your sensor gives an output of 5 volts, ADC converts it into ‘11111111’ and in case of zero volts ADC converts it into ‘00000000’ and any number between 0-5 gets converted into the corresponding 8-bit digital number. Thus ADC gives you the precision of 5/255 volts = 0.01961 volts (i.e difference between two consecutive 8-bit binary numbers). Now it must make sense that more the resolution( i.e. no of bits in converted digital number ) more the accuracy, less quantization error.
Read More about Implementing UART Using AVR
IMPLEMENTATION OF ADC IN AVR(ATMEGA328P)
Now that you are familiar with the basic terms used in ADC, now it’s time that we look at how to implement ADC.
First, let's clear our basics about registers needed for the implementation of ADC.
The first register we are gonna talk about is ADMUX (ADC Multiplexer Selection Register)
In order to convert an analogue voltage to a digital value on any ADC, the converter has to be provided with a range of voltages. The lower limit is always GND on the Arduino (i.e. 0V) but you can select one of three sources to serve as the high reference:
- AREF - This is a separate pin on the microcontroller that can be used to provide any high reference voltage you wish to use as long as it’s in the range of 1.0V to VCC.
- AVCC - This pin on the microcontroller provides power to the ADC circuitry on the chip. On the Uno, it is connected to VCC. This is the simplest option to use provided AVCC is connected to VCC.
- 1.1V - The microcontroller has an internal 1.1V reference voltage that can be used
For example, if u want to use the internal Vcc(5 V) for the conversion u have to put just the bit on “ REFS0 ” as 1 → ADMUX|=(1<<REFS0);
We will learn about the ADLAR bit in a while, so continue reading
The next register we are gonna talk about is the ADCSRA-ADC Control and Status Register A(we have another register ADCSRB but for basics of ADC, it's not needed):-
Bit 7 - The ADEN bit enables the ADC . so it must be set to 1 for doing any ADC operation.
Bit 6 - Setting the ADSC bit to a 1 initiates a single conversion. This bit will remain a 1 until the conversion is complete. It returns to 0 when conversion is complete
Bits 2:0(meaning 2 to 0) - The ADPS2, ADPS1 and ADPS0 bits select the pre-scaler divisor value. Those available are:
The ADC circuitry needs to have a clock signal provided to it in the range of 50kHz to 200kHz. The ATmega328P clock is too fast (16MHz on the Uno) so the chip includes an adjustable pre-scaler to divide the processor clock down to something usable. The processor clock speed is divided by the prescaler value to give an ADC clock speed. Using a lower pre-scaler will make the conversion faster but at the cost of accuracy(ex for resolution less than 10 bits).
For ex, if prescaler is 128(ADCSRA |=1<<ADPS2|1<<ADPS1|1<<ADPS0) then the clock frequency is (16/128=125 Khz on the Uno).
Last but not the least, ADCL and ADCH – The ADC Data Registers
U remember right, where we left about that ADLAR bit in ADMUX.
If you want to use ADLAR=0, you have to read the ADCL register first and then ADCH left-shifted 8 times.
If you want precision up to 8 bits u can just put ADLAR=1 and read just ADCH left-shifted 2 times
*When using the 10-bit results (ADLAR=0), the results can be read into your program with:
int value = ADC; *
Note:- For any further information u can always refer to the datasheet of ATMEGA328P.
Now let's use the knowledge we gained from above and code a simple program where we read the analogue input and store it in a variable:-
ADCSRA |= (1 << ADSC);//Starting conversion
while(ADCSRA & (1 << ADSC))
//Wait for the ADC conversion to complete
int value= ADC;//giving the value after ADC conversion in a variable
Here if you print the value of “value” variable you will get any value from 0 to 1023 depending on the voltage at A0 pin to be 0 to 5 respectively.
This blog has been submitted by KRSSG under the Robocraze Club Outreach Program
Author:- Samanway Ray & Pritam Das