Sunday, May 08, 2011

External Interrupts: Needs More Buttons

Any Arduino project you make is most likely going to be doing a lot of waiting. Instead of constantly polling your sensors for input changes, you can use interrupts to free up your processor so it can do other things without having to worry about missing a signal.

The Arduino IDE provides a function, attachInterrupt(), that can set-up external interrupts for you. The Arduino Mega 2560 has six available external interrupts, INT5:0. The ATmega2560 chip has eight external interrupts total, but the Arduino only connects six of those pins to headers. If you are going to be setting the interrupt registers yourself and choose not to use the provided function, be warned that the interrupt numbers don't necessarily correspond to the same pins listed below.

The External Interrupts are connected to the following Pins when using attachInterrupt():
              Digital Pin
INT5 :        18
INT4 :        19
INT3 :        20
INT2 :        21
INT1 :        3
INT0 :        2

The attachInterrupt() function uses three parameters to customize the interrupt:
  • Interrupt Number: Found in the left column in list above. Attach your sensor to the corresponding pin.
  • Function Name: The function that will be called when the interrupt occurs. This would be your Interrupt Service Routine if you were using a different micro-controller.
  • Trigger Mode: Determines when the interrupt will be triggered. Can be one of four values:  RISING, FALLING, CHANGE, and LOW.
    1. RISING: Triggers the interrupt only when the pin changes from low to high; a rising clock edge
    2. FALLING: Triggers the interrupt only when the pin changes from high to low; a falling clock edge 
    3. CHANGE: Triggers when the pin changes from either low to high or high to low; any clock edge
    4.  LOW: Triggers when the pin is low
The syntax of the function with all of the parameters included is attachInterrupt(interrupt, function, mode). If you wanted to create an external interrupt using pin 2, that triggered on a rising clock edge, and jumped to the function button(), the correct syntax would be attachInterrupt(0, button,  RISING).

Let's apply an interrupt to the following sketch:

int button_state = 0;             // variable for storing button's status

void setup() {
  pinMode(53, OUTPUT);           //Set LED on PIN53 to output  
  pinMode(52, INPUT);            //Set button on PIN52 as input


void loop(){
  button_state = digitalRead(52); //Read state of button
  if (button_state == HIGH) {      //If HIGH, the button has been pressed
    digitalWrite(53, HIGH);       //Turn LED on
  }
  else {                          //If LOW, button is open
    digitalWrite(53, LOW);        //Turn LED off:
  }
}


The sketch controls the state of an LED by polling a tactile button. When the button is pressed, the LED toggles ON/OFF. You can make the program more efficient by replacing the need for polling with an external interrupt. 


 More SCIENCE!

The following code sets up an External Interrupt using the attachInterrupt() function:

volatile int state = 0;

void setup(){
  pinMode(53, OUTPUT);
  attachInterrupt(0, button, CHANGE);
}

void loop(){
}

void button(){
  state = !state;
  digitalWrite(53, state);
}


If you are using a switch(button) for your interrupt trigger, you need to make sure to debounce the input (which I haven't) or the Arduino may read a single button press as multiple presses. The Arduino website offers one solution for a software debounce here. Normally, you could get away with just using a delay after the button press, but the delay() function is disabled inside of interrupt routines.

4 comments:

  1. Hi Noah,

    Thank you for the interrupt pin clarification. I was wrecking my brain to figure out what the hell was wrong with the pin mapping I was looking at. According to the Arduino mega 2560, the interrupts are supposed to be wired as follows:
    INT0 -> pin 21
    INT1 -> pin 20
    INT2 -> pin 19
    INT3 -> pin 18
    INT4 -> pin 2
    INT5 -> pin 3
    INT6 -> NOT CONNECTED
    INT7 -> NOT CONNECTED

    However, you mention the following, which is actually the correct wiring !!
    NT5 : 18
    INT4 : 19
    INT3 : 20
    INT2 : 21
    INT1 : 3
    INT0 : 2

    Why is the pin mapping not correct? What other errors should I expect from it? Do you have an alternative correct pin mapping diagram for me to use?

    Thanks,
    Cagri

    ReplyDelete
    Replies
    1. Man, I was going crazy over this too. If anyone can explain why they changed the interrupt connections I'd really appreciate it.

      Delete
  2. Hi,
    I am making a Robotic Arm using Arduino Mega 2560 and SSC 32 Servo controller.

    I want the arm to move and follow given commands only when i press the push button manually.

    for example: i want the arm to pick an object and place it in its end position and then come to its rest position.
    i want this cycle to take place only once when i press an external push button or a switch. hence whenever i push this push button, it completes this cycle.

    My query is how do i make the circuit connection to the arduino and how do i program the Arduino??

    ReplyDelete
  3. Noah, Cryptoman - this is really awesome. Been studying mega 2560 pinout and not receiving any interrupts until got stuck on this blog explaining the damn stuff. Arduino maintainers could at least mention INT0 on AVR is not INT0 on Arduino!!!

    ReplyDelete