Reattach interrupt doesn't working

I'm currently trying to use 2 external interrupts to drive a counter. The counter starts after first interrupt occurs and it stops after the second interrupt occurs.

void loop()
{
  attachInterrupt(0, count_start, FALLING);
  while(time_start == 0)
  {}
  detachInterrupt(0);
  attachInterrupt(1, count_stop, FALLING);
  while(time_stop == 0)
  {
    count = count + 1;
  }
  detachInterrupt(1);

  calculation();
  delay(5000);
}
void count_start() 
{
  time_start = 1;
}
void count_stop()
{
  time_stop = 1;
}

When the program enter into the loop at the first time the counter increase properly. But when the second time, program enter into the loop, the counter doesn't increase. the reason might be ISR is not clearing the EIFR flags. But i cant find any answer to this... :~

Please post your code.

Where do you reset "time_start"?

void loop()
{
  attachInterrupt(0, count_start, FALLING);
  while(time_start == 0)
  {}
  detachInterrupt(0);
  
  attachInterrupt(1, count_stop, FALLING);
  while(time_stop == 0)
  {
    count = count + 1;
  }
  detachInterrupt(1);

  calculation();

  all_clear();
  
  delay(5000);
}

void count_start()
{
  time_start = 1;
}

void count_stop()
{
  time_stop = 1;
}

void calculation()
{
  new_count = float(count - float(count/Dmax));
  
  time = float(new_count/1000000);
  
  angle = (time*18000);
  
  angle_rad = ((angle * 3.14159)/180);
  
  power_factor = cos(angle_rad);

  lcd.clear();
  lcd.print("Angle: ");
  lcd.print(angle, 6);
  
  lcd.setCursor(0, 1);
  lcd.print("P Fact: ");
  lcd.print(power_factor, 5);
}

void all_clear()
{
  new_count = 0;
  time = 0;
  angle = 0;
  angle_rad = 0;
  power_factor = 0;

  count = 0;
  time_stop = 0;
  time_start = 0;
}

I used a function to clear the all variables. Then I used the Serial monitor and also a LCD module to see the variables and they also cleared properly. There is nothing wrong with that variables. :drooling_face:

I'd really like you to post your code.

You need to post all of your code so we can see, for example that time_start and time_stop are properly declared volatile.

#include <LiquidCrystal.h>
LiquidCrystal lcd(31, 30, 27, 26, 25, 24);

//For Interrupt operation
  volatile int time_start = 0;
  volatile int time_stop = 0;
  long count = 0;

//For calculation part
  float Dmax = 5.49857;
  float new_count = 0;
  float time = 0;
  float angle = 0;
  float angle_rad = 0;
  float power_factor = 0;
  
void setup()
{
  lcd.begin(16, 2);
}

void loop()
{
  attachInterrupt(0, count_start, FALLING); //pin 2
  while(time_start == 0)
  {}
  detachInterrupt(0);
  
  attachInterrupt(1, count_stop, FALLING); //pin 3
  while(time_stop == 0)
  {
    count = count + 1;
  }
  detachInterrupt(1);

  calculation();

  all_clear();
  
  delay(5000);
}

void count_start()
{
  time_start = 1;
}

void count_stop()
{
  time_stop = 1;
}

void calculation()
{
  new_count = float(count - float(count/Dmax));
  
  time = float(new_count/1000000);
  
  angle = (time*18000);
  
  angle_rad = ((angle * 3.14159)/180);
  
  power_factor = cos(angle_rad);

  lcd.clear();
  lcd.print("Angle: ");
  lcd.print(angle, 6);
  
  lcd.setCursor(0, 1);
  lcd.print("P Fact: ");
  lcd.print(power_factor, 5);
}

void all_clear()
{
  new_count = 0;
  time = 0;
  angle = 0;
  angle_rad = 0;
  power_factor = 0;

  count = 0;
  time_stop = 0;
  time_start = 0;
}

Do you still have a problem after adding all_clear() to your code?

If so add Serial.print()'s to your code to find out whats is going on. There is nothing wrong with the arduino's interrupts. Any problem has to do with you.

Mark

hasantha848: the reason might be ISR is not clearing the EIFR flags. But i cant find any answer to this... :~

http://www.gammon.com.au/interrupts

You aren't clearing EIFR the first time.

Why not use micros() instead of this convoluted way of attaching and detaching interrupts?

I used Serial.print() but still I have the problem. I cant use micros because I have to measure the time between two FALLING edges. Can anyone please tell me how do I clear the EIFR (External Interrupt Flag Register) bits.

hasantha848: I cant use micros because I have to measure the time between two FALLING edges.

You'll have to explain that one a bit more - I can't follow your reasoning.

In my code I have to measure the delay between 2 square waves. So Im detect one falling edge of a square wave and increment a counter until detect the falling edge of the other square wave.

I'm still not reading anything I recognise as preventing the use of simple polling and "micros()"

Are there any need of clearing the EIFR flags before attach any interrupt?

Did you read my page at all?

http://www.gammon.com.au/interrupts

If the EIFR flag is not cleared then an interrupt may fire immediately, so it is wise to clear it before attaching an interrupt. And since you are doing a lot of attaching you should clear it every time.

I cant use micros because I have to measure the time between two FALLING edges

You can’t use micros() to measure time. Right.

So instead you are adding one to a counter, which will be very inaccurate (because of timer interrupts).

You aren’t making any sense, sorry.

I suggest something like this:

#include <LiquidCrystal.h>

LiquidCrystal lcd(31, 30, 27, 26, 25, 24);

//For Interrupt operation
  volatile unsigned long time_start = 0;
  volatile unsigned long time_stop = 0;
  volatile bool triggered = false;

//For calculation part
  float Dmax = 5.49857;
  float new_count = 0;
  float time = 0;
  float angle = 0;
  float angle_rad = 0;
  float power_factor = 0;
  
void setup()
{
  lcd.begin(16, 2);
  EIFR = 0;
  attachInterrupt(0, count_start, FALLING); //pin 2
  attachInterrupt(1, count_stop, FALLING); //pin 3
}

void loop()
{

  // ready yet?
  if (!triggered)
    return;
    
  // save difference
  long interval = time_stop - time_start;
  
  // negative time interval, ignore
  if (interval <= 0)
    {
    triggered = false;
    return;
    }

  calculation (interval);
  triggered = false;
  
  delay(5000);
}

void count_start()
{
  if (!triggered)
    time_start = micros ();
}

void count_stop()
{
  if (!triggered)
    {
    time_stop = micros ();
    triggered = true;
    }
}

void calculation(long interval)
{
  // whatever
}

hasantha848: In my code I have to measure the delay between 2 square waves. So Im detect one falling edge of a square wave and increment a counter until detect the falling edge of the other square wave.

Instead of that complication, why don't you just read the current time whenever a falling edge occurs, and subtract that from the previous time to calculate the interval between those two events? Who knows, you might even be able to use pulseIn().

I'll try your code! All the time that I tried to clear the EIFR flags not worked. I want to know is this really working?

EIFR = bit (INTF0);

Anyway thanks all of you for helping me.

I got it wrong. It should be:

  EIFR = bit (INTF0) | bit (INTF1);

That should work, yes.

Thanks all of you for helping me! Finally I solved the problem. But it was totally unbelievable when I realized the error of my code. Here is the modified code...

void loop(){

  time_start = 0;
  bitSet(EIFR, INTF1);
  attachInterrupt(3, count_start, FALLING);
  while(time_start == 0){}
  detachInterrupt(3);

  time_stop = 0;
  bitSet(EIFR, INTF0);
  attachInterrupt(2, count_stop, FALLING);
  while(time_stop == 0){}
  detachInterrupt(2);

  calculation();
  all_clear();
  delay(3000);
}
void count_start(){
  time_start = 1;
  first_edge = micros();
}
void count_stop(){
  time_stop = 1;
  second_edge = micros();
}

Im using Interrupt 3 and 2 in ATmega 2560 arduino board. You can clearly see here, before attaching the interrupt I'm clearing the flags of INT0 and INT1. But it should be INT2 and INT3. But when I cleared the INT0 and INT1 flags in my code, interrupt fired as soon as it is attached. But in this manner the code is working properly... Anyway thanks all of you!

Excellent, Nick, so far you’re the ONE and ONLY guy I’ve seen who made a “correct” accounting of how Mega mucked up the INTx mapping, in your final note
http://www.gammon.com.au/forum/?id=11488

Reply #8 on Sat 27 Jul 2013 12:41 AM (UTC)
Interrupt names to pin mappings

My first thought with seeing this thread was … is OP using a Mega board?

You still might add a note to your page, Nick, indicating that the “official” info on the Mega page [schematics and pinout diagrams] are contrary.