Regardless of whatever voltage at A0, the software is always returning high (1023)

volatile unsigned char* ADmux = (unsigned char*) 0x7C;
volatile unsigned char* ADCSRa = (unsigned char*) 0x7A;
volatile unsigned char* ADCSRb = (unsigned char*) 0x7B;
volatile unsigned char* ADCh = (unsigned char*) 0x79;
volatile unsigned char* ADCl = (unsigned char*) 0x78;
int Voltage;

void adc_init()
  *ADmux = 0x00; // setting entire register to 0's notably setting Refs1 and refs0 to 0's meaning reference voltage is AREF
  *ADCSRa = 0b10000111; //Sets most significant bit to 1, which is the ADC enable bit, and the 3 least signifcant bits are the prescalar, which is 128


unsigned int adc_read( unsigned char adc_channel)
  *ADmux = *ADmux | 0b00000000;// set mux bits to 0 to test A0 regardless of whatever adc_channel is
  *ADCSRa = *ADCSRa | 0b01000000; // set ADSC bit high to start conversion

  while(*ADCSRa & 0b01000000);//wait until ADSC goes low, indicated conversion is complete

  return ADC; //return bits in the adc registers

void setup() {
   // put your setup code here, to run once:
   adc_init(); // initializes the adc

void loop() {
  // put your main code here, to run repeatedly:

  Voltage = adc_read(0b00000); // calls on adc_read

  Serial.print(Voltage); // prints voltage reading


And here is a schematic of the circuit:


simulate this circuit – Schematic created using CircuitLab

I have combed over chapter 26 of the atmega2560 document and the descriptions of each register, but I am at a loss. Why is the contents of the adc registers always filled with 1's regardless of the voltage at a0?

  • what do you read if you remove R1? – jsotola Nov 15 '19 at 5:39
  • @jsotola it still reads 1023 – ClockwerkSC Nov 15 '19 at 5:41
  • What IDE do you use, if any? Make sure MUX5, at ADCSRB:3 is set to 0, as well as ADTS2:0 at ADCSRB 2:0 to enable free running mode. – towe Nov 15 '19 at 7:20
  • I got the program to work by setting refs0 to 1. So this means that the reference voltage switched from AREF to AVCC. Does anyone know why this small change makes it work? Isn't AREF 5V by default? – ClockwerkSC Nov 15 '19 at 7:30
  • @towe I'm using the default Arduino IDE. – ClockwerkSC Nov 15 '19 at 7:31

First, let me give a couple of suggestions on the programming style. There is no point in defining your own variables for accessing the hardware registers: the avr-libc does that for you, you just have to #include <avr/io.h>. Actually, you don't have to #include anything: the Arduino IDE automatically #includes Arduino.h, which in turn #includes avr/io.h.

Next, the same avr-libc also defines macros for the bit names, so you don't have to explicitly write binary numbers in your own code (which is error-prone). And a couple of utility macros that you can use to make the code a little bit more readable. For example:

void adc_init()
    ADMUX  = _BV(REFS0);  // ADC reference = AVCC
    ADCSRA = _BV(ADEN)    // enable the ADC
           | _BV(ADPS2)   // set prescaler to 128
           | _BV(ADPS1)   // ditto
           | _BV(ADPS0);  // ditto

unsigned int adc_read(unsigned char adc_channel)
    ADMUX   = _BV(REFS0) | (adc_channel & 7);  // select channel
    ADCSRA |= _BV(ADSC);  // start conversion

    // Conversion is complete when ADSC goes low.
    loop_until_bit_is_clear(ADCSRA, ADSC);

    return ADC;  // return the adc data register

Now, let's answer your actual question. When you set both REFS0 and REFS1 to 0, the voltage reference is stated to be “AREF, internal V REF turned off”. The implication is that you are supposed to bring your own voltage reference and connect it to the AREF pin. Otherwise AREF is left as a floating input. This is illustrated in the schematic of the ADC. Here is the relevant part:


As you see here, REFS0 is used to connect AREF to one of the other possible references: either AVCC or the internal bandgap. If REFS0 is zero, the transistor depicted above is off, and AREF is left floating.


What are the resistance values for R1 and LDR1? Their ratio will determine the voltage at A0. If the ratio of their resistances is too high (for example, 100:1) then any light measured by LDR1 would only result in a small change in the voltage being measured. If the difference is extreme enough, the voltage could also appear to be constantly low or high. If you have a multimeter available, checking the voltage of that divider circuit could help determine what's going on.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.