ADC neglects input voltage (ATMega32)

adcatmegaavravr-gccc

In the following AVR code, why do I always see the same voltage for all pins of port A?

I am using ATMega32.

BTW, when I am grounding some pins of port A I do not see any change in the output. It seems AVR neglects what ever I give to port A of it.

#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include "lib/hd44780.h"

void InitADC()
{
    ADMUX=(1<<REFS0);                         // For Aref=AVcc;
    ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Rrescalar div factor =128
}

uint16_t ReadADC(uint8_t ch)
{
    //Select ADC Channel ch must be 0-7
    ch=ch&0b00000111;
    ADMUX|=ch;

    //Start Single conversion
    ADCSRA|=(1<<ADSC);

    //Wait for conversion to complete
    while(!(ADCSRA & (1<<ADIF)));

    //Clear ADIF by writing one to it
    //Note you may be wondering why we have write one to clear it
    //This is standard way of clearing bits in io as said in datasheets.
    //The code writes '1' but it result in setting bit to '0' !!!

    ADCSRA|=(1<<ADIF);

    return(ADC);
}

void convert_text(double voltage,char *text)
{
    int voltage_n, voltage_f;
    voltage_n=(int)trunc(voltage);
    voltage_f=(int)trunc((voltage-voltage_n)*100);
    sprintf(text,"%d.%02d",voltage_n,voltage_f);
}

void convert_voltage_text(double voltage,int battery,char *text)
{
    char stext[20];
    convert_text(voltage,stext);
    sprintf(text,"V%d=%s",battery,stext);
}

void main ()
{

    char vtext1[20];
    char vtext2[20];
    char vtext3[20];
    char vtext4[20];
    char line1[20];
    char line2[20];
    uint16_t v_val1, v_val2, v_val3, v_val4;
    double voltage1, voltage2, voltage3, voltage4;

    InitADC();
    lcd_init();
    // DDRA=0;
    // PORTA=0;

    while(1)
    {
    _delay_ms(10);
        v_val1=ReadADC(1);           // Read Analog value from channel-0
    _delay_ms(10);
        v_val2=ReadADC(2);           // Read Analog value from channel-2
    _delay_ms(10);
        v_val3=ReadADC(3);           // Read Analog value from channel-3
    _delay_ms(10);
        v_val4=ReadADC(4);           // Read Analog value from channel-4

        voltage1=((double)v_val1)/1023*5;
        voltage2=((double)v_val2)/1023*5;
        voltage3=((double)v_val3)/1023*5;
        voltage4=((double)v_val4)/1023*5;

        convert_voltage_text(voltage1,1,vtext1);
        convert_voltage_text(voltage2,2,vtext2);
        convert_voltage_text(voltage3,3,vtext3);
        convert_voltage_text(voltage4,4,vtext4);

        sprintf(line1,"%-10s %s",vtext1,vtext2);
        sprintf(line2,"%-10s %s",vtext3,vtext4);

        lcd_clrscr();
        lcd_goto(LCD_LINE1_POS);
        lcd_puts("");
        lcd_puts(line1);
        lcd_goto(LCD_LINE2_POS);
        lcd_puts("");
        lcd_puts(line2);

        _delay_ms(100);             
    }

    return(0);
}

Best Answer

I think previous poster is right about not clearing the channel bits in ADMUX. Here's my well tested code:

unsigned short read_proc_ad(byte adchan){
  //start a new conversion, wait for a result, and return it
  //unsigned short retval;
  ADMUX &= ~0X1F;
  ADMUX |= adchan;
  ADCSRA |= _BV(ADSC);
  while(bit_is_set(ADCSRA,ADSC))wdt_reset();
  return ADC;
}

Note also I don't look for ADIF to rise, instead I look for ADSC to fall. Also you might want to clear the ADIF flag just before the conversion rather than after.