arduinoembeddedavrattinywinavr

why adc always reads 1023 irrespective of input


I am trying to read a analogue voltage using the ADC in attiny85. But the ADC register always read 1023 irrespective of what input is given.

Moreover when the ADC pin is measured with a multimeter it shows nearly 3.1V. I aasumed that it is pulled up but the fact is, when i connect the pin to its analog input , the voltage at the pin disturbs the input voltage circuit. I dont know why this happens. the same code worked well before 6 months but now it is not. reason unknown. could anyone explain me what I'm actually doing wrong? I am using USBasp as my programmer and attiny85 as my target microcontroller, arduino as my compiler. Also i tried compiling using WinAVR but still the analogue input pin is at a voltage near 3.1V. thanks in advance:)

#define F_CPU 16000000UL
#define myTx PB1 //PB1
#define myRx PB0 //PB0
#define ADC_CH_2 PB4
#define ADC_CH_3 PB3

#include <SoftwareSerial.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
float ADCval;
int i = 0, p;

SoftwareSerial myPort(myRx, myTx); //rx,tx

ISR(ADC_vect) {

  p = ADCW;
  ADCval = (float)p * 5.00f / 1024.0f;


  //logging the data
  myPort.print(i++);
  myPort.print(" ADC: ");
  myPort.print(p);

  myPort.print(" voltage: ");
  myPort.println(ADCval);

}

int main(void) {
myPort.begin(9600);
MCUCR &= ~(1 << PUD); //disabling Pull Up Disable i.e, enabling pullups

//I/O configuration
DDRB &= ~(1 << ADC_CH_2) & ~(1 << ADC_CH_3); //configuring as input
PORTB |= (1 << ADC_CH_2) | (1 << ADC_CH_3); //  writing 1 to an input pin activates pullup-resistor
DIDR0 |= (1 << ADC_CH_2) | (1 << ADC_CH_3); // disable digital buffer
myPort.print("DDRB: ");
myPort.println(DDRB);

myPort.print("PORTB: ");
myPort.println(PORTB);

//ADC configuration

ADCSRA |= (1 << ADEN); //enable ADC
ADCSRA |= (1 << ADIE); //enable conversion complete interrupt
ADCSRA |= (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2); // prescaler 128 - 16000000/128=125khz;
myPort.print("ADCSRA: ");
myPort.println(ADCSRA);

ADMUX &= ~(1 << ADLAR); // right most shift in ADCH and ADCL i.e, ADCH has two MSB bits and ADCL has 8 LSB bits



ADMUX |= (1 << REFS1) | (1 << REFS2); ADMUX &= ~(1 << REFS0); //Vref as 2.56V
ADMUX |= (1 << MUX1) | (1 << MUX0) ; ADMUX &= ~(1 << MUX2) & ~(1 << MUX3); //adc3

sei(); // enable all interrupts
myPort.print("ADMUX: ");
myPort.println(ADMUX);

while (1)
{
_delay_ms(1000);
ADCSRA |= 1 << ADSC;
myPort.print("DDRB: ");
myPort.println(DDRB);
myPort.print("ADMUX: ");
myPort.println(ADMUX);
myPort.print("ADCSRA: ");
myPort.println(ADCSRA);
myPort.print("PORTB: ");
myPort.println(PORTB);

}




return 0;
}

Update

the following image describes my output of different ADC channels for the same input voltage.

output of ADC channel 2

output of ADC channel 3


Solution

  • When the ADC configured with 2.56V as a reference voltage then all voltages at level 2.56 and above will be read as ADC's maximum value, i.e. 1023. The same goes for 3.1 V.

    Probably the issue is in the enabled internal pull-up:

    PORTB |= (1 << ADC_CH_2) | (1 << ADC_CH_3); //  writing 1 to an input pin activates pullup-resistor
    

    Enabled pull-up will source additional current and change the voltage at the input. You should never use internal pull-ups with ADC since the pull-up's value is different from part to part in range 20k...50k, and it is hard to predict exact value.

    You should disable it:

    PORTB &= ~(1 << ADC_CH_2) & ~(1 << ADC_CH_3); //  disable pull-ups
    

    Use external pull-up of the known value, if needed.