Go Down

Topic: Arduino Uno get's stuck when doing analogRead (Read 535 times) previous topic - next topic

sascha_held

Dear all,

I'm writing a program that uses the Arduino as an A/D-Datagrabber, we try to measure some voltages of capacitors and that measurement should happen right after a falling pin-voltage. For this i wrote a function with a for-loop that writes the AnalodRead-values of the Pins A0-A3 into an array and then gives out the values of this array via Serial. If i put this code into the void loop(), it works, but then the Ardunio is not doing the measurement i want when the interrupt is triggerd. If i put the same code into a function and try to call it via Interrupt, the Uno-board get's stuck and does nothing anymore until i reset it.

This is the code:
(sorry that some is still german, i'm too lazy to translate all the variables  :~)

Code: [Select]


double Vcc;                     //Value of reference voltage
unsigned long Anfang;      //Timeflag for time measurement
double Werte[] = {0,0,0,0}; //Array for measurement values
int Pins[] = {A0,A1,A2,A3}; //Array that gives the pins that are to measure


/* Code for generating the reference voltage

Code von http://code.google.com/p/tinkerit/wiki/SecretVoltmeter */

long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1125300L / result; // Back-calculate AVcc in mV
  return result;
}

void setup() {
  Serial.begin(9600);   
  attachInterrupt(0,measure,FALLING); //Interrupt 0 (=Pin 2) calls measure() if Voltage is dropping
}



void loop() {
  //empty, all functions are implemented in measure()
}



void measure()

//Get start-timestamp
  Anfang = micros();

//measure reference voltage
  Vcc = readVcc()/1000.0;

  //A/D-Grabbing
 
  for (int i=0;i<4;i++) {
    Werte[i]=analogRead(Pins[i]);
  }
  Serial.print("\tDauer der Messschleife: ");
  Serial.print(micros()-Anfang);   
  Serial.println("mikrosek");
 
//Get start-timestamp
  Anfang = micros();
 
  //Print out measured values
  for (int i=0;i<4;i++) {
    Serial.print("Analog-Eingang = " );                       
    Serial.print(Pins[i]);       
    Serial.print(" Wert = " );                       
    Serial.print(Werte[i]);     
    Serial.print("\tEntspricht der Spannung = ");     
    Serial.println(Werte[i] / 1023 * Vcc);
  }
  //Print out time needed for process
  Serial.print("\tDauer der Ausgabeschleife: ");
  Serial.print(micros()-Anfang);
  Serial.println("mikrosek");
}


Again: If i use this code as it is, the Arduino stops working as soon as the Interrupt is called. I checked this by putting a small "serial.print "watining" - delay 1sec" into the main loop. The Arduino freezes as soon as the trigger comes.

If i put the exactly same code into the main loop, it works and reads the for pins, gives their values and the time needed for the measurement. But i need to have this done with the interrupt. I also tried to block another Interrupt call by putting (no)Interrupts() into measurement(), but this wont help.

Is there something in the measurement-function that is not working with interrupt-calls or do i miss something else?

Any suggestion is welcome.

Thanks,
Sascha

AWOL

#1
Feb 12, 2013, 02:23 pm Last Edit: Feb 12, 2013, 02:25 pm by AWOL Reason: 1
Serial output and delays in an interrupt?
Well, that certainly ticks the boxes for a freeze.

A single analogRead takes around 100us.
Even that is far too long to be doing in an interrupt.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

UKHeliBob

Serial.print in an interrupt routine.  Naughty !
Multiple Serial.prints in an interrupt routine.  A capital offence !!
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

sascha_held

Ok, then. Looks like a no-brainer for experienced guys ;-)

As i said, it's not helpful if the programm spams the measured values in a loop, but maybe i can swap the serial-printout part out of the measure() function into another one that is NOT called by an interrupt. It's not mandatory that the printout comes right after the measurement.


Thanks so far!

AWOL

It may be that you don't need an interrupt at all, just a fast polling loop.
If you do find that an interrupt is necessary, because the trigger signal is short and could be missed by a polling loop, then have the service routine simply set a flag that is then examined (and eventually reset) by the main loop.
Don't forget to declare the flag "volatile".
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

sascha_held

#5
Feb 12, 2013, 02:45 pm Last Edit: Feb 12, 2013, 02:54 pm by sascha_held Reason: 1
Ok, if you say that even one AnalogRead is too long for the Interrupt, then i should go for a signal-polling, since the later full-scale version of this shall measure 16 Analog-Ins on an Arduino Mega.

Thanks for the hints guys!

dc42

Alternatively, just kick off the conversion in the interrupt service routine, and read the value when you get the conversion complete interrupt.
Formal verification of safety-critical software, software development, and electronic design and prototyping. See http://www.eschertech.com. Please do not ask for unpaid help via PM, use the forum.

sascha_held

Hi, just a small thank you: Yesterday i had the time to try the new code (the interrupt only changes a "trigger" boolean while the main loop checks if this bool is set and then starts the AD-converter code.
It finally worked, now i can try out the prototype that we build.

Thanks for the support!

Go Up