How to detect a push button while in a iterative block?

Hi there. I don’t have any code yet; because, for now, I don’t have anything for testing it.

Okay let’s get into the subject’s point. I’m going to program some animations for a RGB LED strip (not the one that I can control each LED individually); and as you may know, the for and delay statements are perfect for making LEDs fade-in and out.
My idea is to have a “counter” variable that chooses the animation to execute over and over (until the button is pressed again). Then, each animation gets enclosed in a “case” of a switch statement.

But the next thing is my question: how to make my program detect the button even when it’s “trapped” in a for statement execution? The effect that I expect is when I push the button while fading-in or out, change the animation immediately.

I hope you understood me and I will appreciate your answers.

PD: another question: how to implement a “debounce” algorithm into my sketch? Because I read somewhere that mechanical switches “bounces” for a very small fraction of a second when pressed, but long enough to lead into microcontroller misreadings.

Put a switch check in the loop then exit if pressed.

Use the search box above for denounce.

Weedpharma

This sketch handles de-bouncing of switches for you.

:sleeping: time.

/*SwitchManager skeleton 

 This is sketch is to introduce new people to the SwitchManager library written by Nick Gammon
 
 The library handles switch de-bouncing and provides timing and state change information in your sketch.
 The SwitchManager.h file should be placed in your libraries folder, i.e.
 C:\Users\YouName\Documents\Arduino\libraries\SwitchManager\SwitchManager.h
 You can download the library at:
 http://gammon.com.au/Arduino/SwitchManager.zip    Thank you Nick!
 
 In this example we have 2 normally open (N.O.) switches connected to the Arduino - increment and decrement.
 The increment switch will also be used as a "Reset" switch if pressed for more than two seconds.
 The two switches are connected between GND (0 volts) and an Arduino input pin.
 The library enables pull-up resistors for your switch inputs.
 Pushing a switch makes its pin LOW. Releasing a switch makes its pin HIGH.
 
 The SwitchManager library provides 10ms de-bounce for switches. 
 i.e. enum { debounceTime = 10, noSwitch = -1 };
 If you need more time, edit the SwitchManager.h file
 i.e. enum { debounceTime = 50, noSwitch = -1 }; //here it is changed to 50ms
 */

#include <SwitchManager.h>             
//object instantiations
SwitchManager myIncSwitch;
SwitchManager myDecSwitch;

unsigned long currentMillis;
unsigned long heartBeatMillis;
unsigned long heartFlashRate  = 500UL; // time the led will change state       
unsigned long incShortPress   = 500UL; // 1/2 second
unsigned long incLongPress    = 2000UL;// 2 seconds 
unsigned long decShortPress   = 500UL; // 1/2 second

const byte heartBeatLED       = 13;
const byte incSwitch          = 4; //increment switch is on Arduino pin 4
const byte decSwitch          = 5; //decrement switch is on Arduino pin 5

int myCounter;

//======================================================================

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

  //gives a visual indication if the sketch is blocking
  pinMode(heartBeatLED, OUTPUT);  

  myIncSwitch.begin (incSwitch, handleSwitchPresses); 
  myDecSwitch.begin (decSwitch, handleSwitchPresses);
  //the handleSwitchPresses() function is called when a switch changes state

} //                   E N D  O F  s e t u p ( )

//======================================================================

void loop()
{
  //leave this line of code at the top of loop()
  currentMillis = millis();

  //***************************
  //some code to see if the sketch is blocking
  if (CheckTime(heartBeatMillis, heartFlashRate, true))
  {
    //toggle the heartBeatLED
    digitalWrite(heartBeatLED,!digitalRead(heartBeatLED));
  }

  //***************************
  //check to see what's happening with the switches
  //"Do not use delay()s" in your sketch as it will make switch changes unresponsive 
  //Use BlinkWithoutDelay (BWD) techniques instead.
  myIncSwitch.check ();  
  myDecSwitch.check (); 

  //***************************
  //put other non-blocking stuff here


} //                      E N D  O F  l o o p ( )


//======================================================================
//                          F U N C T I O N S
//======================================================================


//                        C h e c k T i m e ( ) 
//**********************************************************************
//Delay time expired function
//parameters:
//lastMillis = time we started
//wait = delay in ms
//restart = do we start again  

boolean CheckTime(unsigned long  & lastMillis, unsigned long wait, boolean restart) 
{
  //has time expired for this task?
  if (currentMillis - lastMillis >= wait) 
  {
    //should this start again? 
    if(restart)
    {
      //yes, get ready for the next iteration
      lastMillis += wait;  
    }
    return true;
  }
  return false;

} //                 E N D   o f   C h e c k T i m e ( )


//                h a n d l e S w i t c h P r e s s e s( )
//**********************************************************************

void handleSwitchPresses(const byte newState, const unsigned long interval, const byte whichPin)
{
  //  You get here "ONLY" if there has been a change in a switches state.

  //When a switch has changed state, SwitchManager passes this function 3 arguments:
  //"newState" this will be HIGH or LOW. This is the state the switch is in now.
  //"interval" the number of milliseconds the switch stayed in the previous state
  //"whichPin" is the switch pin that we are examining  

  switch (whichPin)
  {
    //***************************
    //are we dealing with this switch?
  case incSwitch: 

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //The incSwitch was just released
      //was this a short press followed by a switch release
      if(interval <= incShortPress) 
      {
        Serial.print("My counter value is = ");
        myCounter++;
        if(myCounter > 1000)
        {
          //limit the counter to a maximum of 1000
          myCounter = 1000; 
        }
        Serial.println(myCounter);
      }

      //was this a long press followed by a switch release
      else if(interval >= incLongPress) 
        //we could also have an upper limit
        //if incLongMillis was 2000UL; we could then have a window between 2-3 seconds
        //else if(interval >= incLongMillis && interval <= incLongMillis + 1000UL) 
      {
        //this could be used to change states in a StateMachine
        //in this example however, we will just reset myCounter
        myCounter = 0;
        Serial.print("My counter value is = ");
        Serial.println(myCounter);
      }

    }

    //if the switch is a normally closed (N.C.) and opens on a press this section would be used
    //the switch must have gone from HIGH to LOW 
    else 
    {
      Serial.println("The incSwitch was just pushed");
    } 

    break; //End of case incSwitch

    //*************************** 
    //are we dealing with this switch?
  case decSwitch: 

    //has this switch gone from LOW to HIGH (gone from pressed to not pressed)
    //this happens with normally open switches wired as mentioned at the top of this sketch
    if (newState == HIGH)
    {
      //The decSwitch was just released
      //was this a short press followed by a switch release
      if(interval <= decShortPress) 
      {
        Serial.print("My counter value is = ");
        myCounter--;
        if(myCounter < 0) 
        {
          //don't go below zero
          myCounter = 0;
        }
        Serial.println(myCounter);
      }

    }

    //if the switch is a normally closed (N.C.) and opens on a press this section would be used
    //the switch must have gone from HIGH to LOW
    else 
    {
      Serial.println("The decSwitch switch was just pushed");
    } 

    break; //End of case decSwitch

    //*************************** 
    //Put default stuff here
    //default:
    //break; //END of default

  } //End switch (whichPin)

} //      E n d   o f   h a n d l e S w i t c h P r e s s e s ( )


//======================================================================
//                      E N D  O F  C O D E
//======================================================================

and as you may know, the for and delay statements are perfect for making LEDs fade-in and out.

Delay() is NOT perfect for anything other than completely [edit for language - watch it please] your program get rid of it. The above shows you to be totally unfit to make such a judgement!

A good rule for any one is, Never wait for an input, in a loop of any kind! It means you can't react to anything else.

Mark

Have a look at the demo Several Things at a Time. It flashes 3 leds and reads a switch and includes a simple debounce system.

...R

Lucario448: and as you may know, the for and delay statements are perfect for making LEDs fade-in and out.

No, they are dreadful for managing things that happen over time.

Look at the "blink without delay" example and learn to do it right. You'll be glad you did.

Everything has to be non-blocking and delay() blocks. I would approach it by using loop() to read the switch or switches. I'd write non-blocking functions for the animations. Each time loop() executed it would check on the switches and call the animation function which just checks the time and performs any needed updates and then returns to loop(). Now you could use a switch statement to control which function is called. I'd use an array of pointers to the functions myself. The push button switch would simply advance a pointer. Don't forget to check for roll over.

You could develop the animation functions in a separate sketch that doesn't bother with switches. If you made a new one you can just copy it into your main sketch and update the switch statement and rollover and such.

Ok thanks guys. Now my concern goes into three things:

  • Will this Debounce library be useful for my sketch?
  • If I should not use the delay function, the alternative methods will "lag" the execution more than a 50 ms delay?
  • When I just want to test the animations (use no button), then it's OK to use the delay function?

Lucario448:
Now my concern goes into three things:

I guess you missed Reply #4

…R

Lucario448: Ok thanks guys. Now my concern goes into three things:

  • Will this Debounce library be useful for my sketch?
  • If I should not use the delay function, the alternative methods will "lag" the execution more than a 50 ms delay?
  • When I just want to test the animations (use no button), then it's OK to use the delay function?

You should definitely go read the information linked to in Reply #4.

To answer your questions.

1 Debouncing is easy no real need for a library.

2 The alternative is using millis() values to time events. The arduino can do many things in 50ms.

3 Write your animations to be non-blocking using millis values for timing. The function should just update and check the state of the animation and return control to loop().

Once you get the hang of using millis values for timing you'll wonder why you ever used a delay().

Now, goto Reply #4