Go Down

Topic: Interrupt timing issue (Read 519 times) previous topic - next topic

Hey all! I'm new to the forum as well as the arduino - but an experienced programmer.

I've built a circuit to measure the frequency of a 120v/60hz AC phase through zero point detection. On the Arduino side I have:

Code: [Select]

volatile unsigned long lastInterrupt = 0;
volatile unsigned long previousInterrupt = 0;

void setup() {
  // some setup code ....
  attachInterrupt(0, zero_cross_int, RISING);
  // ... end setup code
}


void zero_cross_int() {
  previousInterrupt = lastInterrupt();
  lastInterrupt = micros();

  // the code below seems to mess up the timing calculation which normally detects 60Hz, but by adding this it detects 68Hz!!
  delayMicroseconds(65 * 128);
  digitalWrite(PIN_AC_LOAD, HIGH);
  delayMicroseconds(8);
  digitalWrite(PIN_AC_LOAD, LOW);
  // end output code
}

void loop(){
  long elapsed = lastInterrupt - previousInterrupt();
  long lastSignalDistance = micros() - lastInterrupt;
  float rate = ((1000.0 * 1000.0) / elapsed) / 2.0;
  Serial.print(rate, 2);
  Serial.println("Hz");
}



In the interrupt method I am keeping track of the time elapsed between two interrupts and using that to calculate the frequency of the interrupts. That works fine and detects the 60Hz AC frequency, but as soon as I add additional code with some delays the rate gets detected as 68Hz or so. I can't quite explain why, it's as if either the interrupts are running over-top of each other, or the lastInterrupt variable isn't being set until the end of the interrupt method. Can anyone explain this behavior or suggest how to better implement it?

(If anyone is wondering why I'm bothering to calculate the phase, since I could just fire off my code in the interrupt at the rate it is triggered - I have my reasons! I would like to detect the actual phase frequency to more accurately adjust the delays needed for triac firing)

Thanks guys!  8)
Beginner Enthusiast

Grumpy_Mike

Simply you can not use a delay inside an ISR.

Not being able to delay inside the ISR sounds like a challenging problem. I need to ensure that I'm pulsing my triac at the exact zero point that the ISR is triggered, and if I am doing that in the main message loop so far I haven't been able to reliably sync.
Beginner Enthusiast

KJMM

check the good BlinkWithOutDelay

Nick Gammon

You can calculate the time interval, no worries. Just save the start time from the first interrupt, and when you get the second one, subtract one from the other.

You can also kick off another timer if you want to time up to some interval and set that other timer to cause an interrupt when it fires.

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

http://www.gammon.com.au/forum/?id=11504
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Thanks guys.. I was able to rewrite the entire app without using delays. Instead of the interrupt doing any manipulation of outputs, I am using a simple boolean to flag when the interrupt is fired and measuring the distance in between each event. Works fantastic :)

Beginner Enthusiast

Go Up