Issue when looping through an ADC interrupt

Hello, this is my first time using this forum so if there is any issue, just let me know.

My Arduino is connected to a potentiometer that is going to read 25 inputs and convert them using the ADC/Interrupts. The code works outside of the first conversion. It appears to not do it at all after a board reset. If I execute the code more than once before the board resets, it prints the first iteration, but it prints the digital value as "000" with a time of "0us". I'm not sure what would be causing this to happen.

//Screenshot of the output

// Below is the "main" code that I am trying to execute

#include <avr/wdt.h>  
unsigned long stopTime = 0;
unsigned long startTime = 0;
unsigned long totalTime = 0;
unsigned long averageTime = 0;
const byte adc_pin = A0; // = 14 (pins_arduino.h)
volatile int adc_value;
volatile bool adc_done;
volatile bool adc_busy;


void setup() {

    Serial.begin(9600);
    pinMode(A0,INPUT);
    ADCSRA = bit(ADEN) // Turn ADC on
           | bit(ADIE) // Enable interrupt
           | bit(ADPS0) | bit(ADPS1) | bit(ADPS2); // Prescaler of 128
     ADMUX  = bit(REFS0) // AVCC
           | ((adc_pin - 14) & 0x07); // Arduino Uno to ADC pin
    

    Serial.println("Board was reset"); // prints the sentence on the serial monitor

}
// ADC complete ISR
ISR(ADC_vect) {
  adc_value = ADC;
  totalTime = micros() - startTime;
  adc_done = true;
  adc_busy = false;
  
  
}


void loop() {
    
     mainfunction();       // loop runs main function, allows me to control code easier

}


void mainfunction() {    //acts as main
   
    static String userInput;
    static int AR_analogIN = 0;
    static int P_analogIn = 0;
    
    Serial.println("Select a type of conversion to perform (‘a’ for lab #4; ‘b’ for lab #5; 'c' for lab #6) > ");
    wdt_enable(WDTO_4S);                    //set watchdog to have 4S timer
    while(!Serial.available()) {}           
    userInput = Serial.readString();

    if (userInput == "a")             {
     wdt_disable();           //disables WDT
     Serial.println("Starting a set of conversions using AnalogRead: ");
     
for(int i = 1; i<=25 ; i++) {    //Loops through for 25 conversions

    String readdump = Serial.readString();   // reads each value sent to serial
    
    startTime = micros();
    AR_analogIN = analogRead(A0);
    totalTime = micros() - startTime;

    
    Serial.print("#");
    Serial.print(i);
    Serial.print(":     digital value = ");

    String HexString = String(AR_analogIN,HEX);

    while (HexString.length() != 3) {
      HexString = String("0" + HexString);
    }
    Serial.print(HexString);   //prints the analogIN in hex
    
    
    Serial.print("     Time = ");
    Serial.print(totalTime);
    Serial.print(" usecs");
    
    averageTime = averageTime + totalTime;
    Serial.println();
}

    Serial.print("avg conversion time = ");
    Serial.print(averageTime / 25);         //formula for average time of conversion
    Serial.println(" usecs");

    averageTime = 0;
    totalTime = 0;
    startTime = 0;
  
}

else if (userInput == "b") {
  ACD_init();
  wdt_disable();
  Serial.println("Starting a set of conversions using polling and port manipulation: ");

  for(int i = 1; i<=25 ; i++) {    //Loops through for 25 conversions

    int readdump = Serial.parseInt();   // reads each value sent to serial
    
    P_analogIn = adc_read(A0);
   
    
    Serial.print("#");
    Serial.print(i);
    Serial.print(":     digital value = ");
    
    String HexString = String(P_analogIn,HEX);

    while (HexString.length() != 3) {
      HexString = String("0" + HexString);
    }
    Serial.print(HexString);   //prints the analogIN in hex
    
    Serial.print("     Time = ");
    Serial.print(totalTime);
    Serial.print(" usecs");
    
    averageTime = averageTime + totalTime;
    Serial.println();
}

    Serial.print("avg conversion time = ");
    Serial.print(averageTime / 25);         //formula for average time of conversion
    Serial.println(" usecs");

    averageTime = 0;
    startTime = 0;
    totalTime = 0;

 }

 else if (userInput == "c")             {
     wdt_disable();           //disables WDT
     Serial.println("Starting a set of conversions using interrupts: ");
     
     
     for(int i = 1; i<=25 ; i++) {    //Loops through for 25 conversions

    int readdump = Serial.parseInt();
  
  if (adc_done) {
    
    Serial.print("#");
    Serial.print(i);
    Serial.print(":     digital value = ");
    
    String HexString = String(adc_value,HEX);

    while (HexString.length() != 3) {
      HexString = String("0" + HexString);
    }
    
    Serial.print(HexString);
    
    Serial.print("     Time = ");
    Serial.print(totalTime);
    Serial.println(" usecs");

    averageTime = averageTime + totalTime;
    
    adc_done = false;

 
  }

  // Start new conversion
   if (!adc_busy) {
    adc_busy = true;
    // start the conversion
    startTime = micros();
    bitSet(ADCSRA, ADSC);
    
    
  }
  }

    Serial.print("avg conversion time = ");
    Serial.print(averageTime / 25);         //formula for average time of conversion
    Serial.println(" usecs");

    averageTime = 0;
    startTime = 0;
    totalTime = 0;
}


 else {      //if the user input is not a or b or c

     Serial.println("Error: invalid input - the only valid input is 'a' or 'b' or 'c'");    //error
     wdt_reset();             // resets the WDT
     mainfunction();         // resets and calls main function from scratch again

}
}

void ACD_init()    {     // function to initialize the ADC

     ADMUX = (1 << REFS0); //default Ch-0; Vref = 5V
     ADCSRA |= (1 << ADEN) | (0 << ADSC) | (0 << ADATE); //auto-trigger OFF
     ADCSRB = 0x00;
}

uint16_t adc_read(uint8_t ch)  {    // Function to read value of ADC

      
     ADCSRA |= (1 << ADSC);     //starts single conversion and writes a '1' to ADSC
     startTime = micros();
     
    
     while (ADCSRA & (1 << ADSC));      //waits for the conversion to complete, poll until ADSC becomes '0' again

     
     ADC = (ADCL | (ADCH << 8));
     totalTime = micros() - startTime;
     return (ADC);                      //return conversion value
     
}


//check why timings are inconsistent
//INTERRUPT for loop starts at 2... 1st doesn't work for some reason
//tidy up code

// This is the ISR

ISR(ADC_vect) {
  adc_value = ADC;
  totalTime = micros() - startTime;
  adc_done = true;
  adc_busy = false;
  }

//This is the Setup for the ADC/Interrupt

ADCSRA = bit(ADEN) // Turn ADC on
          | bit(ADIE) // Enable interrupt
          | bit(ADPS0) | bit(ADPS1) | bit(ADPS2); // Prescaler of 128
   ADMUX  = bit(REFS0) // AVCC
          | ((adc_pin - 14) & 0x07); // Arduino Uno to ADC pin

As a first step avoid using the String type on Uno or similarly small controllers.

2 Likes

Below is the "main" code

Post all the code.

Something like old-school sprintf is fun:

  char buff[128];
  sprintf(buff,"#%d:     digital value = %03x     Time = %3d 
 usecs\n",i,adc_value, totalTime);
 Serial.print(buff);

Updated the post with all the code.

It looks like you didn't clear the interrupt flag (ADIF) before you enabled the interrupt (ADIE) so you got an immediate interrupt.

I see. Would you be able to show me the proper way to do that? I'm still pretty new at working with the Arduino.

"ADIF is cleared by writing a logical one to the flag."

so:

   ADCSRA |= _BV(ADIF); // clear interrupt flag

So, I tried implementing that, and the loop did not run at all.

I think you put it in the wrong place. It goes in setup(), just before you enable the interrupt.

This is the change I implemented, and the output it produced. Not entirely sure if I did it correctly, but the output did not change

Serial.begin(9600);
    pinMode(A0,INPUT);
    ADCSRA = bit(ADEN); // Turn ADC on
    ADCSRA |= _BV(ADIF)
           | bit(ADIE) // Enable interrupt
           | bit(ADPS0) | bit(ADPS1) | bit(ADPS2); // Prescaler of 128
    
     ADMUX  = bit(REFS0) // AVCC
           | ((adc_pin - 14) & 0x07); // Arduino Uno to ADC pin

issue again

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.