The Atmega32 comes with a 10-bit, 8 channel inbuilt Ananlog to Digital Convertor (ADC). We will set it up and read temperature from LM35 and light with a simple (light dependent Resistor)LDR. So let's get started!
Basics
The ACSRA register allows us to enable the adc and set the sampling rate.
ADC Control and Status Register A (ACSRA):
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ADEN | ADSC | ADATE | ADIF | ADIE | ADPS2 | ADPS1 | ADPS0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
We will first initialize the ADC with the following code
- Enable ADC by Setting ADEN bit of ADCSRA and set the sampling frequency to half of oscillator frequency (i.e 8 MHz)
- Select channel zero by default using the ADMUX register shown below.
ADC Multiplexer Select (ADMUX)
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
REFS1 | REFS0 | ADLAR | MUX4 | MUX3 | MUX2 | MUX1 | MUX0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
- void ADC_Init()
- {
- ADCSRA=(1<<ADEN) | (1<<ADPS0); /* Enable ADC , sampling freq=osc_freq/2 */
- ADMUX=0x00; /* Result right justified, select channel zero */
- }
Let us write another function to select the required channel and read the analog data as below :
- Select the required channel passed as input to the function
- Start the ADC conversion by setting ADSC bit in ADCSRA
- Wait till the conversion is over by checking the ADIF bit in ADCSRA
- Read the ADCW register and return the result of conversion
- uint16_t ADC_GetAdcValue(uint8_t v_adcChannel_u8)
- {
- ADMUX = v_adcChannel_u8; /* Select the required channel */
- DELAY_us(10); /* Wait for some time for the channel to get selected */
- util_BitSet(ADCSRA,ADSC); /* Start the ADC conversion by setting ADSC bit */
- while(util_IsBitCleared(ADCSRA,ADIF)); /* Wait till the conversion is over */
- /* ADIF will be set once ADC conversion is complete */
- return(ADCW); /* Return the 10-bit result */
- }
Raw Data
Let's put all of the above together to read raw data from the ADC:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "adc.h" | |
#include "uart.h" | |
int main() | |
{ | |
int adcValue; | |
float volt; | |
ADC_Init(); /* Initialize the ADC module */ | |
UART_Init(9600); /* Initialize UART at 9600 baud rate */ | |
while(1) | |
{ | |
adcValue = ADC_GetAdcValue(0); // Read the ADC value of channel zero | |
volt = (adcValue*5.00)/1023; //10bit resolution, 5vReference | |
UART_Printf("ADC0 Value:%4d Equivalent Voltage:%f\n\r",adcValue,volt); // Send the value on UART | |
} | |
return (0); | |
} |
Temperature
Let's connect the LM35 temperature sensor to channel zero of the ADC and read the temperature.
Hook up LM35
Code to Read Temperature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "adc.h" | |
#include "uart.h" | |
int main() | |
{ | |
int adcValue; | |
int temp; | |
ADC_Init(); /* Initialize the ADC module */ | |
UART_Init(9600); /* Initialize UART at 9600 baud rate */ | |
while(1) | |
{ | |
adcValue = ADC_GetAdcValue(0); // Read the ADC value of channel zero where the temperature sensor(LM35) is connected | |
/* Convert the raw ADC value to equivalent temperature with 5v as ADC reference | |
Step size of AdC= (5v/1023)=4.887mv = 5mv. | |
for every degree celcius the Lm35 provides 10mv voltage change. | |
1 step of ADC=5mv=0.5'c, hence the Raw ADC value can be divided by 2 to get equivalent temp*/ | |
temp = adcValue/2.0; // Divide by 2 to get the temp value. | |
UART_Printf("ADC0 Value:%4d Equivalent Temperature:%dC\n\r",adcValue,temp); // Send the value on UART | |
} | |
return (0); | |
} |