Go Down

Topic: Problems using interrupts  (Read 526 times) previous topic - next topic

wbanz

Oct 12, 2018, 02:06 am Last Edit: Oct 12, 2018, 10:40 am by wbanz Reason: Attached wrong code
I am using two vibration sensors to trigger interrupts. Both sensors will react when a shock is received on a board but one will trigger before the other. The objective is to calculate the time difference between the sensors triggering and determine which sensor triggered first.
I am using an Arduino UNO and interrupts 0 and 1.
Because the vibrators may (will) result in more than one pulse per shock, after receiving the first pulse I disconnect the interrupt. Each interrupt captures micros() and after both interrupts have been processed I calculate the difference with a plus or minus result depending on which interrupt was processed first. Before  re-attaching the interrupts I use code I borrowed from Nick Gammons interrupts tutorial.
My problem is that I still get extra interrupts triggering after the interrupt processors are re-attached.
Any advice will be gratefully received.
Code: [Select]

int vibPin1 = 2;
int vibPin2 = 3;
int ledPin = 13;
int CR = 13;
volatile long timeone = 0;
volatile long timetwo = 0;
volatile long timedelay = 0;
volatile int(sequence);

void setup() {
  Serial.begin(9699);
  pinMode(vibPin1,INPUT);
  pinMode(vibPin2,INPUT);
  pinMode(ledPin,OUTPUT);
  attachInterrupt(0, pin1_ISR, CHANGE);
  attachInterrupt(1, pin2_ISR, CHANGE);

}

void loop() {
  if (timeone * timetwo != 0) {
    digitalWrite(ledPin, HIGH);
    timedelay = timeone - timetwo;
    Serial.print(sequence); Serial.print("\n");
    Serial.print(timeone);Serial.print(" ");  Serial.print(timetwo);Serial.print(" ");Serial.print(timedelay);Serial.print(" delay\n");   
    timetwo = 0;
    timeone = 0;
    delay(5000);
    digitalWrite(ledPin, LOW);
    sequence = 0;
    EIFR = bit (INTF0);
    EIFR = bit (INTF1);
    attachInterrupt(0, pin1_ISR, CHANGE);
    attachInterrupt(1, pin2_ISR, CHANGE);

  }
}
void pin1_ISR(){
  detachInterrupt(0);
  if (timeone == 0)timeone = micros();
  sequence = 1;

}

void pin2_ISR(){
    detachInterrupt(1);
  if (timetwo == 0)timetwo = micros();
  sequence = 2;

}

gfvalvo

Your code is short enough to post in-line using code tags.
It's all described in Item #6 here:  Read this before posting a programming question ...

You did read that, didn't you?

DKWatson

Why go to all that bother? After you post your code, why not use a single character variable cleared to NULL. The first interrupt to trigger checks this variable and if NULL, knows that it is first so sets the variable to say A. After that, you can have as many interrupts as you want, but the first was still A. When you're ready, reset the variable to NULL and start all over again. Unless of course you actually need the time difference between the two in which case you use another pair to hold the timestamps.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

johnwasser

Are you saying that you are getting vibrations detected even five seconds after the initial shock?  Maybe you have to wait longer for these "vibration detectors" to settle down.  Have you tried using an oscilloscope to see what kind of signal you are getting from your sensors?

It is recommended that you use the "digitalPinToInterrupt()" macro to get the interrupt number for a pin.  That will take care of the case of switching between an UNO and a Leonardo where the interrupts on Pin 2 and Pin 3 are swapped: 
UNO Pin 2 -> Int 0, Pin 3 -> Int 1
Leonardo Pin 2 -> Int 2, Pin 3 -> Int 0

Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

holmes4

You also need to provide a link to the sensors you are using!

and a diagram to  the way they are wired.

Mark

wbanz

Your code is short enough to post in-line using code tags.
It's all described in Item #6 here:  Read this before posting a programming question ...

You did read that, didn't you?
Yes, I did read that. I just chose the option to attach rather than include.
I have gone back and included the code.

wbanz

Are you saying that you are getting vibrations detected even five seconds after the initial shock?  Maybe you have to wait longer for these "vibration detectors" to settle down.  Have you tried using an oscilloscope to see what kind of signal you are getting from your sensors?
No, the five seconds delay is purely there to allow the physical environment to settle.
Yes, I have scoped it and the 5 seconds is more than ample.
The issue is that because I am using a vibration sensor I am getting multiple pulses. The code responds to the first pulse from a sensor then detaches that interrupt, then waits for a pulse from the second sensor and detaches that interrupt. However it seems that if a second pulse (or possibly more) from the vibrator sensor is detected before the interrupt is detached, then one of these interrupts is stacked. When the interrupt is attached again, even after 5 seconds, this stacked interrupt is processed. I understand all of this to be expected.
So, to prevent the stacked interrupt from being actioned, I use Nick Gammons suggested code
    EIFR = bit (INTF0);
    EIFR = bit (INTF1);
to reset the stored interrupts.
However, this does not seem to work.

Quote
It is recommended that you use the "digitalPinToInterrupt()" macro to get the interrupt number for a pin.  That will take care of the case of switching between an UNO and a Leonardo where the interrupts on Pin 2 and Pin 3 are swapped:
UNO Pin 2 -> Int 0, Pin 3 -> Int 1
Leonardo Pin 2 -> Int 2, Pin 3 -> Int 0

Valid point, this point is noted for final code, thanks.

DKWatson

A) I don't see anywhere that you have engaged or disabled interrupts.

B) I don't see any interrupts being called.

C) I don't see any interrupt service routines.

D) If you are timing, and supposedly using micros, in each of your startTimer functions you have a print statement that, at 9600 baud, will take at least 14ms to complete. Not a very good delay in a timing loop.

Am I looking at the correct code?
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

wbanz

#8
Oct 12, 2018, 10:45 am Last Edit: Oct 12, 2018, 10:47 am by wbanz Reason: Cant type!
A) I don't see anywhere that you have engaged or disabled interrupts.

B) I don't see any interrupts being called.

C) I don't see any interrupt service routines.

D) If you are timing, and supposedly using micros, in each of your startTimer functions you have a print statement that, at 9600 baud, will take at least 14ms to complete. Not a very good delay in a timing loop.

Am I looking at the correct code?
No, sorry, not sure how I did it but i uploaded the wrong code. I have corrected that.

DKWatson

FYI there is no need to detach interrupts when you enter ISR as they are disabled automatically by the hardware, enabled on exit.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

wbanz

#10
Oct 12, 2018, 10:58 am Last Edit: Oct 12, 2018, 11:02 am by wbanz
FYI there is no need to detach interrupts when you enter ISR as they are disabled automatically by the hardware, enabled on exit.
I detach them in the ISR so that after I leave the ISR they are detached until I am ready to process  more input from that sensor.

DKWatson

#11
Oct 12, 2018, 11:09 am Last Edit: Oct 12, 2018, 11:11 am by DKWatson
I detach them in the ISR so that after I leave the ISR they are detached until I am ready to proceed more input from that sensor.
Doesn't work that way. The hardware will enable the interrupts on exit (I feel like I'm repeating myself). Read the datasheet.
Quote
When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The
user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then
interrupt the current interrupt routine. The I-bit is automatically set when a Return from Interrupt
instruction - RETI - is executed.
11.7 in the datasheet.
Live as if you were to die tomorrow. Learn as if you were to live forever. - Mahatma Gandhi

GolamMostafa

#12
Oct 12, 2018, 11:23 am Last Edit: Oct 12, 2018, 11:50 am by GolamMostafa
All enabled interrupts can then interrupt the current interrupt routine.
Which enabled interrupt can interrupt the current on-going interrupt? The interrupt that has higher priority than the current on-going interrupt. For example: ISRINT0 is an on-going ISR. Interrupt request due to INT1 will not interrupt the ISRINT0 process as the INT0 has the higher priority than INT1 interrupt. The MCU will finish the ISRINT0 routine, and then it will begin the ISRINT1 process. Interrupt with lower vector value has the higher priority.

sterretje

Which enabled interrupt can interrupt the current on-going interrupt? The interrupt that has higher priority than the current on-going interrupt. For example: ISRINT0 is an on-going ISR. Interrupt request due to INT1 will not interrupt the ISRINT0 process as the INT0 has the higher priority than INT1 interrupt. The MCU will finish the ISRINT0 routine, and then it will begin the ISRINT1 process.
Priority is only used when the processor has to decide which interrupt to handle. Once an ISR is in progress, the specific interrupt flag is cleared and the MCU has no idea which one it is handling and hence you can interrupt even the highest priority interrupt with a low priority interrupt.

This obviously requires enabling interrupts again as DKWatson indicated.
If you understand an example, use it.
If you don't understand an example, don't use it.

Electronics engineer by trade, software engineer by profession. Trying to get back into electronics after 15 years absence.

GolamMostafa

#14
Oct 12, 2018, 12:08 pm Last Edit: Oct 12, 2018, 01:01 pm by GolamMostafa
Priority is only used when the processor has to decide which interrupt to handle. Once an ISR is in progress, the specific interrupt flag is cleared and the MCU has no idea which one it is handling and hence you can interrupt even the highest priority interrupt with a low priority interrupt.

This obviously requires enabling interrupts again as DKWatson indicated.
No, the specific interrupt flag ( Local interrupt enable bit) is not cleared. It remains enabled. The global interrupt enable bit (I-bit of SREG Register) is cleared to prevent the MCU from responding to all kinds of further interrupts. If the user has an impending interrupt of higher priority than the on-going ISR to which the MCU should respond, then he must activate the global interrupt enable bit (putting LH at the I-bit) by executing interrupts() instruction just after arriving at the ISR. Edit: In view of Post#15.

The MCU has interrupt priority logic inside its interrupt module to resolve the priority issue based on the following vector table. Interrupt with lower vector value has the higher priority. This is a hard-cored rule like the 8086 which when receives an interrupt vector, the vector is multiplied by 4 to get the beginning address of the interrupt vector table which holds the 20-bit (SEG:OFF format) physical address of the corresponding ISR.


Go Up