AttachInterrupt() help..

New to Arduino..not really sure what Im doing wrong..maybe you guys can help me out? =)

This is my first time trying to use an External Interrupt..

As I understand it.. these are 'listeners' that check for a state of a 'pin', WITHOUT having to be CODE dependent? ie: not having your code keep 'polling/checking' for a pin status.

Question 1: I know the Arduino Due only says it has 2 external interrupt pins.. Is there any way to get more than these two? (I thought I read something about a pin change?..but it was a bit over my head then..since I didnt even have my Arduino yet)

What Im trying to do is (I thought) fairly simple..

I have a 'sensor'.. wich is nothing more than a spring/nail type sensor

any time this sensor completes the circuit/connects.. it should trigger an event. (whatver function noted in the parameter of the attachInterrupt() function.)

however.. I can NOT seem to get consistent results..

it should ONLY make a noice (play tone) or light the LED when the connection happens..then pause 500 ms.. then turn off again..waiting for the interrupt to fire again..

int pin = 13;
volatile int state = LOW;

void setup()
{
  // initialize the serial communications:
  Serial.begin(9600);
  //set pim mode
  pinMode(pin, OUTPUT);
  //attach interrupt 'listener' to pin2 on Arduino
  attachInterrupt(0, blink, HIGH);
}

void loop()
{
  if(state == HIGH){
    digitalWrite(pin, state);
    delay(500);
    state = LOW;
  }
}

void blink()
{
  Serial.println("--EVENT TRIGGERED--");
  //tone(8, 350, 250);
  state = HIGH;  
}

Question 2: After the interrupt IS triggered.. should I remove it? until AFTER the code/routine has executed..then re-enable/re-attach the interrupt?

Think of this 'sensor' as an IMPACT sensor.. everytime I 'flick' it.. or the project is hit against something.. I want a sound/light to go off.. (and of course off again).. but everytime I stirke te project.. it shoudl repeat this process.. even if I repeatedly 'hit it'..

should keep executing the routine over and over..

Thanks

HI, first off - don't use 'serial.print' anything inside the interupt service routine - comment it out and try again.

also, you may have better luck if you use 'CHANGE' in the attach... line - then you will 'catch' RISING and FALLING edges of your signal.

After the interrupt is triggered - leave the ISR there to catch the next event.

Charles

Hi thanks for the reply..

why not use: Serial.println("--EVENT TRIGGERED--");

in the function being called by the interrupt? (just curious).. it seemed to 'work' when watching it through the serial monitor

secondly.. I did have 'change' in there initially (as well as HIGH/LOW/RISING).. CHANGE seemed to get STUCK if I recall.. (I'll re-hook everything up and check it out) with the LED just being ON all the time.

I basically just have one wire to pin2 and other to GND on Arduino..

thanks

I'll post back the exact result making the changes you suggested.

why not use: Serial.println("--EVENT TRIGGERED--");

Assume you're running the serial line at 9600 baud. That short message will take nearly 20ms to be printed, during which time, interrupts are disabled. Kinda defeats the purpose, don't you think?

sorry.. I didnt know the 'serial.print() disables the interrupts..

so I guess it 'would' defeat the purpose in a final project

still should break the application..or make the led constantly stay on would it?

I didnt know the 'serial.print() disables the interrupts

It doesn't - the interrupt service routine does.

ok..so the 'routine' disables the interrupt.

so what do people do if they want 'actions' to be triggered/executed from an interrupt change.

(I'd imagine sometimes the 'stuff' you want done on an interrupt 'CHANGE' could need to be lengthy...)

make it call another function? Does that still halt/disable the interrupt? or is the interrupt re-enabled after the statements in the 'interrupt routine/function' are done...regardless of what those statements do or tell other parts of the code to do?

and again.. just for testing/debugging.. are you saying this just inst proper form.. and is slow...etc

or would this actually break the 'program' from working correctly..

I posted a quick summary of what Im trying to do..

is this just not the correct approach? this is my first use of External Interrupts...and am just using the tutorial with that sensor.

this is really just another 'test' to have another OPTION than using an accelerometer for the same thing(s).. acceleration & hit detection..

trying to work up examples that uses:

1.) an accelerometer to detect acceleration (and eventually the 'jerk/hit' event)

(I have my example code here in this thread) http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1276585144

and (in this thread Im trying to work out a demo thats)...

2.) using external interrupts to 'watch' for a 'hit' using the sensor posted above..as well as 2 x 'swing/ball bearing sensors'

like these:

both projects will 'do' the same thing.. but using different components to do so..

just trying to give myself a goal to work towards.. being new to this platform.

anyways--

maybe I need to do a digitalRead() after the interrupt is triggered?

it should only 'fire/execute' when the 'sensor' completes the circuit.. not breaking it.. since the break is 'automatic'.. wouldnt it fire twice always as I have it?

once when it makes contact.and again when it breaks?

thanks

The best way to get actions done when an interrupt is detected, is to set a 'flag', then exit the ISR. main routine then tests for the flag's state, and actions accordingly... same as you have with ... 'if(state == high) ...

It is good practice to spend as little time inside ISRs as possible, since other interupts will be 'prioritised', if for e.g. you are receiving serial data, and have a long-running ISR, you may/will loose data.

Awesome..

thanks for the info.. so basically just move the serial output to the IF() statement? and I wont have the lag I was warned of?

I have another question (sorry if its noob..but I just want to be clear)

could I, instead of have the 'flag' being checked/evaluated in the MAIN LOOP..

could I instead call 'another function' from the ISR?..or does that function also keep the interrupt disabled/paused? (ie: calling another function from the ISR function)

example:

int pin = 13;
volatile int state = LOW;

void setup(){
  // initialize the serial communications:
  Serial.begin(9600);
  //set pim mode
  pinMode(pin, OUTPUT);
  //attach interrupt 'listener' to pin2 on Arduino
  attachInterrupt(0, ISR1, CHANGE);
}

void loop(){
  //nothing  
}

void ISR1(){
  
  //tone(8, 350, 250);
  state = HIGH;
  ledHandler();
}


void ledHandler(){
  if(state == HIGH){
    Serial.println("--EVENT TRIGGERED--");
    digitalWrite(pin, state);
    delay(500);
    state = LOW;
  }
}

short answer = NO.

not a good idea, I am not sure about this O.S. , but now you are bordering on ‘re-entrant code’ issues… thaaar be dragons !

calling another function from within an ISR will effectively lengthen the time spent ‘in the ISR’ - thus keeping other interupts of the same or lower priority dis-abled - not nice

C

On the hardware side, you need to pay attention to how you are generating the signal to the interrupt pin. It must not be allowed to just 'float' in it's 'off' state. You stated "I basically just have one wire to pin2 and other to GND on Arduino.." This will only work properly if you have a pull-up resistor installed between the interrupt pin and +5vdc, either by enabling the pin 2 internal pull-up in your setup function or by installing a real resistor (10k ohms will work fine) between pin 2 and +5vdc. This gives a valid HIGH when the sensor is 'off' and a valid LOW when the sensor conducts to ground.

Lefty

this is the 'latest' version of the code.. (I think I posted accidentally ..and kept going in another thread on accident)..

int pin = 13;
int pin2 = 2;
volatile int state = LOW;

void setup(){
  Serial.begin(9600);
  pinMode(pin, OUTPUT);
  pinMode(pin2, INPUT);
  digitalWrite(pin2, HIGH);
  attachInterrupt(0, ISR1, CHANGE);
}
void loop(){
  if(state == HIGH){
    Serial.println("--EVENT TRIGGERED--");
    //tone(8, 350, 50);
    digitalWrite(pin, state);
    delay(50);
    state = LOW;
    digitalWrite(pin, state);
  }
}
void ISR1(){
  state = HIGH;
}

I need to learn how to debounce the 'switches/sensors..as NOT to pick up any other minor 'contacts' after the first MAIN/major trigger/contact

debounce through code will be first approach.. before I jump into that though..what is the general IDEA behind the software debounce?

do you just un-attach interrupt for a small delay? then re-attach? halt your 'main' code that is probably checking for the flags set by the interrupt?

(wouldnt that possible slow or cause lag in other areas of the program/code?)

just asking cause Im new..on what the best practice is.. (of course best practice and easy for beginners! ) ::) ;D

I have found that using an interupt for a hardware (relay, reed switch, push-button, etc) input signal is not ideal. remember, interupt latency (the processing time used to detect and react to the interupt) is in the order of micro-seconds, while the reaction time of people and pushbuttons, or even relay contacts is usually in the order of milli-seconds. (being very broad here, but it illustrates the point).

What works well for these type of inputs (mechanical) where there is a high probability that there will be contact-bounce ( again, in the milli-second range) is to use a simple timer to sample the input each approx 10 milliseconds, if two consecutive reads are the same - assume that the ‘bounce’ has ended, and set the appropriate flag. The only down-side is that it will take at least 10 milliseconds between the first contact change and the flag being raised - but that is what a hardware de-bounce circuit will do anyway (re-triggerable monostable, for e.g.) - not really a problem, since this 10mS is in the same range as the reaction-time of the primary input anyway.

ISRs are best suited to other digitally sourced signals which you know will not ‘bounce’.

A bit long-winded, but hope it helps.

Charlie

thank you for the reply.. it was very enlightening.

are there any beginner/easy tutorials for learning how to work with timers??

I thought I had looked at one topic on it before...but either I got the impression or they made reference it o being hard or more advanced..etc

Is that the case?

You said external interrupts & ISR's are best used for digitally sourced signals?? Can you give me some examples or best use/practice for external interrupts? (not code, general communication)

Like with use in an accelerometer? this thread/project is similar to this one: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1276585144/8#8

in that I am trying to 'do' the same thing(s) with the switches/sensors as I am with an accelerometer

except in the accelerometer thread am I am tracking the acceleration..(no clue on how to detect the jerk/hit event with it)

where as here, I was using the 'hit' (nail & spring) portion to test with..

Id like to learn what the best approach to using both approaches og hardware to 'track' an X & Y 'swing/acceleration' event... and a hit/jerk event

I would say that is a huge portion of my project (along with audio)..

however Id of course like to be able to do other things with my program without delays/lag...etc for the other aspects..(controlling leds..and 1-4 PWM outputs controlling 1-4 high powered led dies.

for how Im focusing on learning and tracking those motion events both ways.

any help, links, tuts...(whatever) is great! and appreciated.

Thanks

okay - I didn’ mean to imply using timers, as in the built-in hardware timers. What I was trying to say was to use … um - see these code-snippets ( will be clearer than any text explanation I can come up with :wink: )

This is from a simple weather-station-logger. The Wind-speed and Rainfall sensors are both reed-switch/rotating magnet types, so hardware interupts are not ideal. The other sensors are all analog

  if ((millis() - previousMillis) >= 1 ) { // this will be each 1 mSec
    millisecNumber ++;
    previousMillis = millis();
    kPaSum += analogRead(PressPin);
    degCSum += analogRead(TempPin);
    LightSum += analogRead(LightPin);
    HumidSum += analogRead(HumidPin);
    WindDir = analogRead(WindDirPin);
    counter ++;
  }

For the switch-inputs, I have this further down in main

  if (millisecNumber == 10 ) { // this will be each 10 mSec - !contact bounce 
    millisecNumber = 0;
    WindSpeed1 = digitalRead(WindSpeedPin);
    if (WindSpeed1 != WindSpeed2) {
      WindSpeed2 = WindSpeed1;
      SpeedPulse++ ; 
    }
    RainState1 = digitalRead(RainPin);
    if (RainState1 != RainState2) {
      RainState2 = RainState1;
      RainCount++ ; 
    }
  }

For your application with the accelerometers, I would be tempted to have a Hardware Comparator circuit ‘looking’ at the accelerometer outputs, with an adjustable threshold, and use it’s output to trigger a real interrupt. This will enable you to set the ‘level’ of acceleration/deceleration which will cause an interrupt. You could then analogRead the accelerometer input to see if the INT was caused by an acceleration or a deceleration. (Sounds easy, but I’m sure you will learn a lot and have more grey hair at the end ;-))

In this weather-logger of mine, I have an I2C RTC chip. I want to record parametes once per minute, but didn’t want to continuously read the RTC to detect the minute. I set the RTS chip to output a 1 pps (Pulse Per Second) signal which I tied to the Interupt pin. Here is the code to get me my required once-per-minute flag to then trigger the logging code.

void setup() {
  attachInterrupt(1, ClockInterrupt, FALLING);
.
.
 and further down
.
void ClockInterrupt (){
  clocksecond ++;
  if (clocksecond == 60){
    clocksecond = 0;
    TimeToReport = true;
  }
}
.
.
and then
.
.
  if (TimeToReport == true){
    TimeToReport = false;
    kPaSum /= counter ;

I hope this makes sense - and please, if you see any &^%-ups, please point it out :wink:

Charlie

awesome…
thanks for the reply… (I am much more comfortable with code than I am with hardware)

so basically your not really ‘delaying’ (I know not the correct term since there is a function called delay as well) the interrupt…

it still fires and works as it does normally… but your not actually polling or doing anything when the iterrupt executes…except increment a counter variable…yes? and then read then var… if value is @ 60 (1 minute for you)…

then you actually ‘read’ and execute the interrupt function ‘fully’

ok…so dont really use the BUILT in timers… keep doing how I am doing it currently… but use a built in ‘timer/counter’ to only execute the ISR function every xx mS…right?

so while the interrupt fires each time a contact is made (even the ‘bounce’ contacts)… I will really only be executing the ISR after a slight pause?

I see how yours works…when you only want to take a ‘read’ at a set/timed interval…

not to sure how to go about this way for me though…since I dont really need it timed… more of a software de-bounce…

sorta the same thing though. you wanna TAKE your read at timed intervals…and I DONT wanna take reads again until after a timed interval…

What I was trying to illustrate, is that I think for your scenario, you would be best to use the 'if MilliSecond == 10' type of polling of the inputs - this way you will only ever read the input signal each 10 Milli Seconds - thereby avoiding the bounce, which could trigger your ISR 5 to 50 times in the same period.

The Interupt in my code example is pureley setting a flag so that I can take specific action after exactly 60 such interrupts.

ok..so youre saying abandon the external interrupts all together?

and using a polling method of checking the values on those pins?

my reason for trying to stay away from the polling method originally was because I thought using an interrupt would release my main code to do other things..

where as if I went down the polling approach path..I would be spending my time/resources on polling (at least) 3 different pins/sensors for the value...

would this be 'too' much polling? and might it interfere with other aspects of the 'program'..

such as the looping sound in the background..

I dont want poling for anything to interrupt looping audio..

or interferes with manual button input from the user (for additional audio FX or power on/off the project)

Im hoping to re-visit things tonight ..and hopefully get a bit of a demo working

and for the accelerometer... you think... an interrupt is the way to go there? since its a digital source??

I'll be trying to update BOTH of those demos then.

thanks

thanks