0

This sketch always reports 0 for the ADC reading.

I think this is going to turn out to be something silly, but I cannot find the source. I've reviewed the sketch ADC lines carefully and they seem right, so maybe the problem with the physical connections or how I'm trying to report the ADC output or the order in which tasks are executed. The capture_FID() etc functions are based on the example in Section 9.2.4 of Norman Dunbar's book, Arduino Software Internals. The only difference is the position of ADCSRA |= (1 << ADEN); which I moved to right after the power up based on this answer. That did not make a difference.


void init();
void setup() {
  Serial.begin(115200);
  capture_FID();
}
void loop() {
}

void capture_FID() {

  volatile uint16_t ADC_output = 0;  // max value 65536

  config_ADC();
  start_ADC();
  for (int i = 1; i <= 5; i++) {
    Serial.print("\ti = ");
    Serial.print(i);
    Serial.print(" value = ");
    Serial.println(ADC_output);
  }
  stop_ADC();
}

// ADC Configuration
void config_ADC() {
  Serial.println("Configuring the ADC...");
  PRR &= ~(1 << PRADC);                                            // power up the ADC
  ADCSRA |= (1 << ADEN);                                           // enable ADC
  ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);             // slow the clock
  ADMUX = (0 << REFS1) | (1 << REFS0);                             // use 5 V internal reference
  ADMUX &= ~(1 << ADLAR);                                          // right-align the 10 bit output in 2 byte/16 bit space
  ADMUX |= (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0);  // multiplexer input; use A0
  DIDR0 |= (1 << ADC0D);                                           // disable digital input to pin A0
  ADCSRA |= (1 << ADIE);                                           // set interupt to notify data is available for further use
  ADCSRA |= (1 << ADATE);                                          // auto-trigger on
  ADCSRB = 0;                                                      // free-running mode
  delay(20);                                                       // wait for voltage to settle
}

// Start the ADC = start acquiring data
void start_ADC() {
  Serial.println("Starting the ADC...");
  ADCSRA |= (1 << ADSC);
}

// Stop the ADC = stop acquiring data
void stop_ADC() {
  Serial.println("Stopping the ADC...");
  ADCSRA |= (0 << ADSC);
}

ISR(ADC_vect) {
  volatile uint16_t ADC_output;  // max value 32767
  ADC_output = ADCW;
}

Hardware:

  • Arduino R3
  • 0.1 uF cap across GND and AREF
  • PicoScope function generator is supplying a 500 Hz, 500 mV, 1 V offset signal; the negative output is wired to GND on the Arduino, the positive output is wired to A0.
  • A sketch that doesn't involve free-running and auto-triggering that I found on Nick Gammon's site works fine, so the board appears to be fine. This also implies the hardware connections and scope settings are fine.

1 Answer 1

3

You have two different variables named ADC_output:

  • one which is local to capture_FID(), and is always zero (it is never assigned another value)
  • one local to ISR(ADC_vect), which is set but never used.

You should use only one such variable.

There are also a handful more problems in this code:

  • capture_FID() prints multiple times the same result, without checking that new data has arrived
  • access to ADC_output outside the ISR is not protected in a critical section
  • the ADC register is called ADC, not ADCW.
  • ADCSRA |= (0 << ADSC) is a no-op
  • there is no point in declaring init()
  • probably more, I did not read it thoroughly…
1
  • Ah, so my limited experience with C is the problem. Let me poke around a bit. Thank you. Commented Jan 7 at 2:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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