Interrupt Pin Counting Both Rising and Falling?

Good Afternoon,

I am attempting to use interrupt pins for the first time but running into an issue that I cannot quite understand.

I am using an Arduino MEGA and have a limit switch hooked up to pin 19. I have the pin set to detect a RISING edge as the switch goes to high when it is pressed. However, while watching the serial monitor and clicking the switch manually I can see that "Current Position" increased both when the switch is pressed and goes from LOW to HIGH and again when the switch is released going from HIGH to LOW.

My understanding is that since I defined the interrupt as "RISING" it should only execute the ISR when the switch goes from LOW to HIGH.

I added the debounce in case it was just noise from the moment the switch mechanically switches but that did not help. So now I am assuming that I am misunderstanding something important with interrupts. Any guidance would be appreciated.

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);  // set the LCD address to 0x3F for a 16 chars and 2 line display

volatile int limitSwitchOneFlag;

int limitSwitchDebounce = 100;

const int limitSwitchOne = 19;
int limitSwitchOneState;
int limitSwitchOnePrevState;
int limitSwitchOneCount = 0;

const int motorPin1 = 11;
const int motorPin2 = 13;
const int pwm = 12;
int motorSpeed = 100;

#define CLK 3
#define DT 4
#define SW 2
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir = "";
unsigned long lastButtonPress = 0;

int currentPosition;
int prevPosition = 1;
int currentRotation;
int prevRotation;

void setMotor(int dir, int motorSpeed, int pwm) {
  currentRotation = dir;
  analogWrite(pwm, motorSpeed);
  if (dir == 1) {
    digitalWrite(motorPin1, HIGH);
    digitalWrite(motorPin2, LOW);
  } else if (dir == -1) {
    digitalWrite(motorPin1, LOW);
    digitalWrite(motorPin2, HIGH);
  } else {
    digitalWrite(motorPin1, LOW);
    digitalWrite(motorPin2, LOW);
  }
}

void autoHome() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Homing....");
  delay(1000);
  limitSwitchOneState = digitalRead(limitSwitchOne);
  while (limitSwitchOneState != HIGH) {
    setMotor(1, motorSpeed, pwm);
    limitSwitchOneState = digitalRead(limitSwitchOne);
    Serial.println();
    if (limitSwitchOneState == HIGH) {
      Serial.print("limitSwitchOne State: HIGH");
    } else if (limitSwitchOneState == LOW) {
      Serial.print("limitSwitchOne State: LOW");
    } else {
      Serial.print("limitSwitchOne State: Unknown");
    }
  }
  setMotor(0, motorSpeed, pwm);
  currentPosition = 1;
  delay(1000);
}

void ISR_limitSwitchOne() {
  limitSwitchOneFlag = 1;
}

void setup() {
  Serial.begin(9600);
  lcd.init();
  lcd.clear();
  lcd.backlight();  // Make sure backlight is on

  attachInterrupt(digitalPinToInterrupt(19), ISR_limitSwitchOne, RISING);

  pinMode(limitSwitchOne, INPUT_PULLUP);
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(pwm, OUTPUT);

  // Set encoder pins as inputs
  pinMode(CLK, INPUT);
  pinMode(DT, INPUT);
  pinMode(SW, INPUT_PULLUP);

  // Setup Serial Monitor
  Serial.begin(9600);

  // Read the initial state of CLK
  lastStateCLK = digitalRead(CLK);  // put your setup code here, to run once:
  autoHome();
  limitSwitchOneFlag = 0;
}

void loop() {

  int btnState = digitalRead(SW);
  if (btnState == LOW) {
    setMotor(1, motorSpeed, pwm);
    currentPosition = 1;
  }
  limitSwitchOneState = digitalRead(limitSwitchOne);
  Serial.print("Current Poistion is: ");
  Serial.print(currentPosition);
  Serial.print("  limitSwitchOne Previous State is: ");
  Serial.print(limitSwitchOnePrevState);
  Serial.print("  Flag State is: ");
  Serial.print(limitSwitchOneFlag);
  Serial.print("      limitSwitchOne State is: ");
  Serial.println(limitSwitchOneState);



  while (currentPosition < 13) {
     setMotor(1, motorSpeed, pwm);
    Serial.print("Current Poistion is: ");
    Serial.print(currentPosition);
    Serial.print("  limitSwitchOne Previous State is: ");
    Serial.print(limitSwitchOnePrevState);
    Serial.print("  Flag State is: ");
    Serial.print(limitSwitchOneFlag);
    Serial.print("      limitSwitchOne State is: ");
    Serial.println(limitSwitchOneState);

    limitSwitchOneState = digitalRead(limitSwitchOne);
    // currentRotation = -1;
    if (limitSwitchOneFlag == 1 ) {
      // if (limitSwitchOneState == LOW && limitSwitchOneState != limitSwitchOnePrevState) {
      //   currentPosition = currentPosition + 1;
      if (currentRotation == 1) {
        currentPosition = currentPosition + 1;
      } else if (currentRotation == -1) {
        currentPosition = currentPosition - 1;
      }
      limitSwitchOnePrevState = limitSwitchOneState;
      limitSwitchOneFlag = 0;
      delay(limitSwitchDebounce);
    }
  }
  setMotor(0, motorSpeed, pwm);
}

//}

a byte type would probably help with the atomicity as you don't use any critical section in the loop when you play with limitSwitchOneFlag. Ideally you would make a copy at the start of the loop in a critical section and use the copy all along.

also instead of

      limitSwitchOneFlag = 0;
      delay(limitSwitchDebounce);

you could write

      delay(limitSwitchDebounce);
      limitSwitchOneFlag = 0; // doing so in a critical section would help too

as the bouncing can happen during the delay and you'll exit the loop and the if with limitSwitchOneFlag set to 1 again.

How, and with what timing? Switch bounce timing can range from microseconds to tens of milliseconds.

Interrupts are usually the wrong choice for reading switches, as they tend to introduce more problems than they solve.

1 Like

In addition to what @J-M-L has written you could increment limitSwitchOneFlag every interrupt and change

if (limitSwitchOneFlag == 1 )

to

if (limitSwitchOneFlag > 0 )

By printing limitSwitchOneFlag you can identify bouncing effects.

P.S.: I found the following issues in your sketch which you might take care of:

  • Two times "Serial.begin(9600);" in setup()
  • No debouncing of limitSwitchOne in autoHome() and in loop()
  • No debouncing of the Rotary Encoder Switch in loop()

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.