Go Down

Topic: Arduino Uno rev 3 + Push Button Interrupt (Read 8707 times) previous topic - next topic

panini

May 14, 2016, 07:55 am Last Edit: May 14, 2016, 08:01 am by panini
Hi! I am using two push buttons with Arduino Uno Rev3 to use Interrupt Routines.

Below are my trimmed schematics and code.



Code: [Select]

...
#define swt_a 2 /* CCW */
#define swt_b 3 /* CW */
...

void setup()
{
  ...
  pinMode(swt_a, INPUT_PULLUP);
  pinMode(swt_b, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(swt_a),swt_afunc,FALLING);
  attachInterrupt(digitalPinToInterrupt(swt_b),swt_bfunc,FALLING);
  ...
  ready = 1;
}

...

void swt_afunc()
{
  if(ready==1)
  {
    ready = 0;
    ...
    // do thing A
    ...
    ready = 1;
  }
}

void swt_bfunc()
{
  if(ready==1)
  {
    ready = 0;
    ...
    // do thing B
    ...
    ready = 1;
  }
}




However, when I am pushing any one of the push-buttons SW1 or SW2, the corresponding function swt_afunc() or swt_bfunc() respectively runs twice instead of once.

My questions are the following:
  • Do I need to add a buffer between the Arduino Pins 2 and 3 and the push-switches?
  • Is my code for initializing the Interrupts okay?
  • What is going wrong about running two times per push?


Thanks in advance. :)

Power_Broker

I'm not too familiar with interrupts on Arduino, but the initialization looks correct to me.

On the other hand, I believe your problem about the ISR running twice a button press is with how you process the button presses. Have you "debounced" the buttons? If not, what's probably happening is that when you press the button, the contacts within the button will literally bounce, causing multiple "fake" button presses. If you are polling the button fast enough without the debouncing code, the program will think the button was pressed more times than it really was.
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla


Paul__B

Pushbuttons are one thing that should almost never be serviced by interrupts.  There is simply no reason to do so; it generally indicates that your code is not properly written.

De-bouncing is just one reason not to do so.
If you are polling the button fast enough without the debouncing code, the program will think the button was pressed more times than it really was.
Polling is one thing, but instantaneous response using interrupts (properly) is even more guaranteed to cause debounce problems.

panini

Hi Paul__B,

Thanks for the reply!

Do you have any pointer to easy hands-on tutorial for Arduino external interrupts with push switches.


Power_Broker

Is this Debounce what you are asking about? https://www.arduino.cc/en/Tutorial/Debounce
Yes and no. It's a very inaccurate way of denouncing. You need to be 100% sure that the button has stabilized before moving on instead of guessing the amount of time it takes to stabilize.
"The desire that guides me in all I do is the desire to harness the forces of nature to the service of mankind."
   - Nikola Tesla

Paul__B

Yes and no. It's a very inaccurate way of denouncing. You need to be 100% sure that the button has stabilized before moving on instead of guessing the amount of time it takes to stabilize.
My point precisely, which is why I did not comment on it.

I prefer "ironclad" code which continuously checks the state.

My contribution to the art:
Code: [Select]
// Blink without "delay()" - multi!  With button de-bounce.

const int led1Pin =  13;    // LED pin number
const int led2Pin =  10;
const int led3Pin =  11;
const int button1 =  4;     // buttons & switches always connect from input to ground

int led1State = LOW;        // initialise the LED
int led2State = LOW;
int led3State = LOW;
char bstate1 = 0;

unsigned long count1 = 0;   // will store last time LED was updated
unsigned long count2 = 0;
unsigned long count3 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.

// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) {
    *marker += interval;    // move on ready for next interval
    return true;      
  }
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
  case 0: // Button up so far,
    if (button == HIGH) return false; // Nothing happening!
    else {
      *butnstate = 2;                 // record that is now pressed
      *marker = millis();             // note when was pressed
      return false;                   // and move on
    }

  case 1: // Button down so far,
    if (button == LOW) return false; // Nothing happening!
    else {
      *butnstate = 3;                 // record that is now released
      *marker = millis();             // note when was released
      return false;                   // and move on
    }

  case 2: // Button was up, now down.
    if (button == HIGH) {
      *butnstate = 0;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else {
      if (millis() - *marker >= interval) {
        *butnstate = 1;               // jackpot!  update the state
        return true;                  // because we have the desired event!
      }
      else
        return false;                 // not done yet; just move on
    }

  case 3: // Button was down, now up.
    if (button == LOW) {
      *butnstate = 1;                 // no, not debounced; revert the state
      return false;                   // False alarm!
    }
    else {
      if (millis() - *marker >= interval) {
        *butnstate = 0;               // Debounced; update the state
        return false;                 // but it is not the event we want
      }
      else
        return false;                 // not done yet; just move on
    }
  default:                            // Error; recover anyway
    {  
      *butnstate = 0;
      return false;                   // Definitely false!
    }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);      
  pinMode(led2Pin, OUTPUT);      
  pinMode(led3Pin, OUTPUT);      
  pinMode(button1, INPUT);      
  digitalWrite(button1,HIGH);        // internal pullup all versions
}

void loop() {
  // Toggle LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    if (led1State == LOW) {
      led1State = HIGH;
    }
    else {
      led1State = LOW;
    }
    digitalWrite(led1Pin, led1State);
  }

  // Act if the latter time (ms) has now passed on this particular counter,
  if (timeout(&count2, 300UL )) {
    if (led2State == LOW) {
      led2State = HIGH;
    }
    else {
      led2State = LOW;
    }
    digitalWrite(led2Pin, led2State);
  }

  if (timeout(&count3, 77UL )) {
    if (led3State == LOW) {
      led3State = HIGH;
    }
    else {
      led3State = LOW;
    }
    digitalWrite(led3Pin, led3State);
  }
}

Go Up