New in Arduino - Using Bounce2 and an ISR to change leds light mode effects

Im new with electronics so I started learning code with Arduino to learn, so start a code to switch between different led light modes just pressing a button so I tried the code without using an ISR and works fine, but when I want to change the light modes, need to hold the button pressed to change, so I used an ISR but doesn't work correctly because of the bounce soy I find on internet the Bounce2 library and works fine so I wanted to use it but when I use the ISR the program only execute the first instruction c = 1, and it doesn't do anything anymore if I press the button again, and I cant find how to fix it. I have quite a bit of knowledge about this and all I know comes from videos, the internet and just thinking and thinking about what's going on.

#include <Bounce2.h>

Bounce2::Button button = Bounce2::Button();

#define BotonPin 2
int c = 0;



void setup() {

  pinMode(BotonPin, INPUT_PULLUP);
  button.attach(BotonPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(2), suma, FALLING);
  button.interval(5);
  button.setPressedState(LOW);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  Serial.begin(9600);
  
}

void loop() {

    
 
  if (c == 0) {
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);

  }
  
  else if (c == 1) {
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(12, HIGH);

  }

  else if (c == 2) {
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
    digitalWrite(12, HIGH);
    delay(400);
    digitalWrite(8, LOW);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
    digitalWrite(11, LOW);
    digitalWrite(12, LOW);
    delay(400);
  }

  else {
     c = 0;
    }

}

void suma() {
  
  button.update();
    if ( button.pressed() ) {
    c++; 
    Serial.println(c);
  }
}

Warning: ...

  • Don't attempt to delay, eg: delay (100);
  • You can get the time from a call to millis, however it won't increment, so don't attempt to delay by waiting for it to increase.
  • Don't do serial prints (eg. Serial.println ("ISR entered"); )
  • Don't try to do serial reading

Source:

1 Like

You don't need interrupts to react on a button. You will need to learn to write non-blocking code (so not using delay).

There are plenty articles on the web to achieve the above; e.g.

And some more reading

You will also need to learn not to use magic numbers (your pin numbers); you do it correctly for the button pin but not for the LED pins.

1 Like

Hello arluino

Welcome to the worldbest Arduino forum ever.

In general, you should not use magic numbers. The I/O pins love to have a functional name.

Have a nice day and enjoy coding in C++.

1 Like

looks like you're trying to use both Bounce2 and an ISR. debouncing typically just requires a ~20msec delay after recognizing a button state change.

i'm not familiar with Bonuce2, but i'll bet that the Bounce2 update() needs to monitor the button continuously, not just when the button state changes to LOW in the ISR triggered on the FALLING edge.

because the delays under each of your if conditions prevent checking the button state

not about electronics, about coding

look this over


const byte BotonPin = 2;
const byte LedPins [] = { 8, 9, 10, 11, 12 };

const int  Nled = sizeof(LedPins);

byte butState;

unsigned long msecLast;
const int MaxC = 3;
bool cState;
int c;

enum { Off = HIGH, On = LOW };

// -----------------------------------------------------------------------------
void loop ()
{
    unsigned long msec = millis ();

    switch (c)  {
    case 0:
        for (int n = 0; n < Nled; n++)
            digitalWrite (LedPins [n], Off);
        break;

    case 1:
        for (int n = 0; n < Nled; n++)
            digitalWrite (LedPins [n], On);
        break;

    case 2:
        if (msec - msecLast >= 400)  {
            msecLast = msec;

            if (cState)  {
                for (int n = 0; n < Nled; n++)
                    digitalWrite (LedPins [n], On);
            }
            else  {
                for (int n = 0; n < Nled; n++)
                    digitalWrite (LedPins [n], Off);
            }
            cState = !cState;
        }
    }

    // check for button presses
    byte but = digitalRead (BotonPin);
    if (butState != but)  {     // state change
        butState = but;
        delay (20);             // debounce

        if (LOW == but)  {      // pressed
            if (MaxC <= ++c)
                c = 0;
            Serial.println (c);
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    pinMode (BotonPin, INPUT_PULLUP);
    butState = digitalRead (BotonPin);

    for (int n = 0; n < Nled; n++)  {
        pinMode      (LedPins [n], OUTPUT);
        digitalWrite (LedPins [n], Off);
    }
}
1 Like

Your code can be structured into parts where each parts is one senseful sub-unit

You have

  • switching LEDs off
  • switching LEDs ON
  • blink LEDs which does repeat switching LEDs off´/switching LEDs ON

You increment a value from 0 until 2 and then set it back to 0
0,1,2,0,1,2,0,1,2,0,1,2...
if the button is pressed. Which shall change the LED-mode
beeing OFF or On or Blinking

So here are the parts of your code

void switchLEDsOff() {
  for (int Idx = 0; Idx < NumberOfLEDs; Idx++) {
    digitalWrite(myLEDPin[Idx], LOW);
  }
}

.

void switchLEDsOn() {
  for (int Idx = 0; Idx < NumberOfLEDs; Idx++) {
    digitalWrite(myLEDPin[Idx], HIGH);
  }
}

.

void blinkLEDs() {
  // check if more time than specified in "myIntervall has passed by
  if (TimePeriodIsOver(myBlinkTimer, myIntervall) ) {
    // when REALLY more time has passed by
    // check if LEDs are OFF by reading IO-state first LED
    if (digitalRead(myLEDPin[0]) == LOW) {
      switchLEDsOn();
    }
    else {
      switchLEDsOff();
    }
  }
}

.

// function that gives back values starting from Min
// incrementing to Max and if Max is reached set back to Min
// example IncrementCircular(myVar,0,2)
// results 0,1,2  0,1,2  0,1,2
byte IncrementCircular(byte actualValue, byte Min, byte Max) {
  byte Value = actualValue;

  if (Value < Min) {
    Value = Min;
  }
  Value = actualValue + 1;

  if (Value > Max) {
    Value = Min;
  }
  return Value;
}

.

byte readButton(byte IO_PinNr) {
  byte firstButtonRead = digitalRead(IO_PinNr);
  delay(50);
  byte secondButtonRead = digitalRead(IO_PinNr);

  // both readings are the same the bouncing is over
  if (firstButtonRead == secondButtonRead) {
    return buttonPressed;
  }
  else {
    return buttonReleased;
  }
}

here is the complete code

const byte ButtonPin = 2;

const byte myLEDPin[] = {8, 9, 10, 11, 12};
// myLEDPin[0] gives a "8"
// myLEDPin[1] gives a "9"
// myLEDPin[2] gives a "10"
// myLEDPin[3] gives a "11"
// myLEDPin[4] gives a "12"


// calculate               No of bytes of complete array / number of bytes of one array-element
const byte NumberOfLEDs   = sizeof(myLEDPin) / sizeof(myLEDPin[0]);
const byte buttonPressed  = LOW;
const byte buttonReleased = HIGH;

byte buttonState;
byte lastButtonState;

byte mode = 0;

unsigned long myBlinkTimer;
const unsigned long myIntervall = 400;

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  pinMode(ButtonPin, INPUT_PULLUP);

  for (int Idx = 0; Idx < NumberOfLEDs; Idx++) {
    pinMode(myLEDPin[Idx], OUTPUT);
    Serial.print("configure myLEDPin[");
    Serial.print(Idx);
    Serial.println("] as OUTPUT");

    Serial.print("in fact pinMode(");
    Serial.print(myLEDPin[Idx]);
    Serial.println(",OUTPUT);");
  }
}

void loop() {

  buttonState = readButton(ButtonPin);
  // check if there is a stateCHANGE
  if (lastButtonState != buttonState) {
    // when there is REALLY a statechange
    lastButtonState = buttonState;
    if (buttonState == buttonPressed) {
      mode = IncrementCircular(mode, 0, 2);
    }
  }

  switch (mode) {
    case 0:
      switchLEDsOff();
      break; // IMMIDIATEALY jump down to END-OF-SWITCH

    case 1:
      switchLEDsOn();
      break; // IMMIDIATEALY jump down to END-OF-SWITCH

    case 2:
      blinkLEDs();
      break; // IMMIDIATEALY jump down to END-OF-SWITCH
  } // END-OF-SWITCH
  lastButtonState = buttonState;
}


byte readButton(byte IO_PinNr) {
  byte firstButtonRead = digitalRead(IO_PinNr);
  delay(50);
  byte secondButtonRead = digitalRead(IO_PinNr);

  // both readings are the same the bouncing is over
  if (firstButtonRead == secondButtonRead) {
    return buttonPressed;
  }
  else {
    return buttonReleased;
  }
}

// function that gives back values starting from Min
// incrementing to Max and if Max is reached set back to Min
// example IncrementCircular(myVar,0,2)
// results 0,1,2  0,1,2  0,1,2
byte IncrementCircular(byte actualValue, byte Min, byte Max) {
  byte Value = actualValue;

  if (Value < Min) {
    Value = Min;
  }
  Value = actualValue + 1;

  if (Value > Max) {
    Value = Min;
  }
  return Value;
}


void switchLEDsOff() {
  for (int Idx = 0; Idx < NumberOfLEDs; Idx++) {
    digitalWrite(myLEDPin[Idx], LOW);
  }
}


void switchLEDsOn() {
  for (int Idx = 0; Idx < NumberOfLEDs; Idx++) {
    digitalWrite(myLEDPin[Idx], HIGH);
  }
}


void blinkLEDs() {
  // check if more time than specified in "myIntervall has passed by
  if (TimePeriodIsOver(myBlinkTimer, myIntervall) ) {
    // when REALLY more time has passed by
    // check if LEDs are OFF by reading IO-state first LED
    if (digitalRead(myLEDPin[0]) == LOW) {
      switchLEDsOn();
    }
    else {
      switchLEDsOff();
    }
  }
}

// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

best regards Stefan

1 Like

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