Help with debounce / switch issue

I have been working on a little project controlling LEDs.

Here is what I have, an Arduino Pro mini. I have one LED on pin 10, another LED on pin 11, and a pushbutton on pin 12.

Wiring, I have a 10K ohm resistor from ground to pin 12 and the push button going from pin 12 to VCC.

The basic premise is turn on. set "stage" = 0. Press Push button, "stage" = 1. Press Push button, "stage" = 2. Press Push button, "stage" = 0, and just keeps looping.

Stage = 0, led 1 does stuff, led 2 off
Stage = 1, led 1 does other stuff, led 2 off
Stage = 2, led 2 does stuff, led 1 off

I copied the "debounce" code from the examples and modified it a little to count instead of just toggle. But here is the issue. when I hit the button, sometimes it will swap to the next stage, but most times it won't.

I really need some help to get this figured out. I have included the entire sketch.

The LED portion works just fine. It is the stepping through that is the issue.

I am open to any suggestions.

Thank you in advance for your help.

/*
 Fading

Created by Vader
22 July 2015

 */

const int buttonPin = 12;         // Mode switch

int stage;                   // Mode stage 0 = solid, 1 = yellow fade, 2 = color fade
int lastButtonState = LOW;
int buttonState;
byte ledPinY = 10;            // LED connected to digital pin 9
byte ledPinC = 11;            // LED connected to digital pin 10

long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 10;    // the debounce time; increase if the output flickers

void setup() {
  // Pin Setup
  pinMode(ledPinY, OUTPUT);
  pinMode(ledPinC, OUTPUT);
  pinMode(buttonPin, INPUT);
  stage = 0;
}

void loop() {

  // Button debouce control

  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);
/*
  if (reading == 1 && stage < 2) {
    stage = stage + 1;
  }

  if (reading == 1 && stage ==2) {
    stage = 0;
  }
*/
  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH),  and you've waited
  // long enough since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only change STAGE if the new button state is HIGH
      if (buttonState == HIGH) {
        if (stage < 2) {
          stage = stage + 1;
        }
        else {
          stage = 0;
        }
      }
    }
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = reading;

  //  LED flash control
/*
if (stage == 0) {
    analogWrite(ledPinY, 255);  // Yellow soild on
    analogWrite(ledPinC, 0);    // Colored off
  }

  if (stage == 1) {
    analogWrite(ledPinY, 0);  // Yellow soild on
    analogWrite(ledPinC, 255);    // Colored off
  }

  if (stage == 2) {
    analogWrite(ledPinY, 255);  // Yellow soild on
    analogWrite(ledPinC, 255);    // Colored off
  }
*/
  // Yellow LED solid on
  if (stage == 0) {
    analogWrite(ledPinY, 255);  // Yellow soild on
    analogWrite(ledPinC, 0);    // Colored off
  }

  //Yellow LED fade in and out
  if (stage == 1) {
    // fade in from min to max in increments of 5 points:
    for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinY, fadeValue);
      analogWrite(ledPinC, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(30);
    }

    // fade out from max to min in increments of 5 points:
    for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinY, fadeValue);
      analogWrite(ledPinC, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(30);
    }
  }

  // Color LED fade in and out
  if (stage == 2) {
    // fade in from min to max in increments of 5 points:
    for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinC, fadeValue);
      analogWrite(ledPinY, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(15);
    }

    // fade out from max to min in increments of 5 points:
    for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinC, fadeValue);
      analogWrite(ledPinY, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(15
      );
    }
  }
}

Are you wanting to do something like this? http://www.instructables.com/id/How-to-store-a-momentary-button-press-as-a-menu-se/

Almost identical, just I don't have an EEPROM to write to. Not sure how to pull that part out. But thank you for that instructables.

I take that back. According to the site, the Pro Mini has 1k of EEPROM on board. Let me load and try.

Yes. Pro Mini, Nano, and Uno all have the ATmega328P chip and therefore the same specs. Differences are almost non-existent when it comes to sketches.

Thank you sir. As soon as I get back home I can load his sketch straight up and make sure it works in general. Then modify as needed.

Only difference is the SMD parts can have analog only inputs A6 & A7 as well.

I tried to compile the sketch today, and I am getting an error or the #include <EEPROMex.h>

It says so such file or directory. Do you know where I can find it to add it to the library?

Vader:
I copied the "debounce" code from the examples

Did you ever try your program without any debounce code to see if it is really necessary ?

Never waste time fixing a non-existent problem.

If you look at planning and implementing a program you will see that it works fine without any debounce code. And there is a very simple system in several things at a time.

...R

Thanks for that link, but debounce isn't so much my issue as "runaway" (and I may be approaching it wrong using a debouce to accomplish this).

What I am trying to avoid is power on, in stage 0. Press the button, move to stage 1. press the button again, move to stage 2, press again, back to stage 0.

what I am afraid of happening is press the button and due to the fact that the arduino runs in milli seconds, I will end up holding the button for a few scan cycles and the system will go through 0, 1, 2, 0, 1, 2, 0..... all in the time I press the button once. I am trying to ensure that one press means one step change.

In my PLC programming, I refer to this as a one-shot. That is what I am really looking for. The one-shot is only live for one scan cycle, no matter how long I hold the button down.

Do you think this would do what I am looking for?

http://playground.arduino.cc/Code/Buttons

He has a library that does a one shot. Have you tried working with it?

If your code is slow enough, you won't need to debounce. Some people use delay() to achieve that and if your code works with that then fine.

Try running a button and led matrix with some sort of blocking code built into each button.

Or just appreciate that a task that takes 100 micros to run, takes 1100 with just a delay(1) added.

But much of the time you wouldn't miss 100 millis and debounce is unnecessary for those.


I went and grabbed my ioclasses library files, saw they needed fixing and fixed them. They could help Vader. The library files (ioclasses.cpp and ioclasses.h) are attached to this post, the example is posted below. Put the library files into the folder with the sketch and use the IDE Sketch->Add File... to work with them in the IDE.

The demo creates 4 button objects (Serial is a class object, these work like that) and 1 led object that interact. Note that the objects have names and the button objects are also pointed to by the array iobuttons[].
Yeah, how many buttons or leds do you want? I have multiplex code too, not in the library yet.

// ioclasses demo   Jul 28, 2015 by GoForSmoke
/*
  This sketch uses 2 classes from ioclasses8.h to make led13
 blink and grounded jumpers on pins 6 & 7 to control the rate.
 Ground pin 6 and the rate adds 100ms. Pin 7 subtracts 100ms.
 
 Button output is a state value for use in sketch code.
 -1, Undecided, pin state changed at least debounce-time ago.
 0, button currently still not pressed.
 1, button currently still pressed.
 2, button released since last checked by sketch. 
 3, button pressed since last checked by sketch.
 The sketch doesn't have to track previous output state. 
 */

#include "ioclasses.h"

// led13( blink-rate, arduino-pin, port, mask-to-toggle-PIN-reg ); 
ioblinker led13( 500, 13, 'B', 0x20 ); // pin 13 is port B pin 5

// button-name( arduino-pin, millis-debounce );
byte buttonIdx;
byte buttonRead;
iobutton  turnoff( 4, 20 ); // using jumpers for buttons = dirty buttons
iobutton  turnon( 5, 20 ); 
iobutton  goslower( 6, 20 ); 
iobutton  gofaster( 7, 20 );
iobutton  *buttons[ 4 ] = 
{ 
  &turnoff, &turnon, &goslower, &gofaster 
};

unsigned long val;

void setup( void )
{
  Serial.begin( 115200 );
  Serial.println( );
  Serial.println( F( "\n  Startup\n" ));
  // object starts set pinmodes and states
  led13.startBlinker( );

  for ( byte i = 0; i < 4; i++ )
  {
    buttons[ i ]->startButton();
  }
}

void loop( void )
{
  // gotta run them
  led13.runBlinker( );

  // by only running 1 button per loop(), many buttons don't load it down and make lag.
  buttonRead = buttons[ buttonIdx ]->runButton( ); // only running 1 button per loop
//  buttonRead = buttons[ buttonIdx ]->readOutput();

  if ( buttonRead == 3 ) // 1st read since pressed
  {
    // now using button data to change blink rate
    switch ( buttonIdx )
    {
    case 0 :         // turnoff
      Serial.print( F( "off " ));
      led13.setPin( 0 );
      break; 

    case 1 :       // turnon
      Serial.print( F( "on " ));
      led13.setPin( 1 );
      break; 

    case 2 :       // slower  
      Serial.print( F( "slower " ));

      val = led13.getWait();
      if ( val < 9900 )
      {
        val += 100;
      }    
      else
      {
        val = 10000;
      }
      led13.setBlinker( val ); 
      Serial.println( val );
      break;

    case 3 :  
      Serial.print( F( "faster " ));

      val = led13.getWait();
      if ( val > 199 )
      {
        val -= 100;
      }    
      else
      {
        val = 0;
      }
      led13.setBlinker( val ); 
      Serial.println( val );
      break;
    }
  }

  buttonIdx++; 
  buttonIdx &= 3;
}

ioclasses.h (1009 Bytes)

ioclasses.cpp (2.58 KB)

Vader:
IThe basic premise is turn on. set "stage" = 0. Press Push button, "stage" = 1. Press Push button, "stage" = 2. Press Push button, "stage" = 0, and just keeps looping.

Stage = 0, led 1 does stuff, led 2 off
Stage = 1, led 1 does other stuff, led 2 off
Stage = 2, led 2 does stuff, led 1 off

Have you ever heard of state machines? Because you make one there.

As I see the code you never get to stage 2. As soon as you set stage 2 it sets it to 0

if (reading != buttonState) {
buttonState = reading;

// only change STAGE if the new button state is HIGH
if (buttonState == HIGH) {
if (stage < 2) {
stage = stage + 1;
}
else {
stage = 0;
}

You never achieve stage 2.

Might change your code to something like this.

if (reading != buttonState) {
buttonState = reading;

// only change STAGE if the new button state is HIGH
if (buttonState == HIGH) {
stage = stage + 1;
if (stage >= 3) {
stage = 0;}
}

Are you including the library functions?

The demo only cares about state 3 which is pressed since last read, off-on detection.

The iobutton class in ioclasses.cpp returns output state values from -1 to 4.

-1 means it's debouncing, 0 is low, 1 is high, 2 is high to low and 3 is low to high
When 2 or 3 is output, the state subtracts 2. The state is read-dependent to not repeat.

Upshot is that your code does not need to track or compare previous state to detect change.
Change is when the object returns a 2 or 3. 0 and 1 are steady pin state and -1 is unsteady pin.

How's that?

Nasa:
Might change your code to something like this.

if (reading != buttonState) {
buttonState = reading;

// only change STAGE if the new button state is HIGH
if (buttonState == HIGH) {
stage = stage + 1;
if (stage >= 3) {
stage = 0;}
}

Mine is compiled and tested to demo 4 buttons and led 13. Have you tried it?

All you need is an UNO and 4 jumpers. Ground a jumper on the USB port box = push a button.
if you have nice push buttons, try cutting the debounce to 2 ms. It should go, jumpers are dirtier.

Pin 4 turns led 13 on steady, pin 5 turns it off, pin 6 increases delay and starts blink, pin 7 decreases delay and starts blink.

It shows how to make button and led objects and point to them with array elements you can iterate through with indexes and loops, all there working. And the details are in the library files.

Vader:
what I am afraid of happening is press the button and due to the fact that the arduino runs in milli seconds, I will end up holding the button for a few scan cycles and the system will go through 0, 1, 2, 0, 1, 2, 0..... all in the time I press the button once. I am trying to ensure that one press means one step change.

The arrangement in several things at a time should stop that. It ensures there is an interval between successive button reads.

...R

I added a loop() counter to the demo. It's running over 57kHz near idle. Each does count, one button, one led, and serial outputs but note that most of the time none of them does more than check a trigger condition.
I added delay(1) to that loop, it now runs 975 to 978. Don't block!

Thanks everyone for your help. GoForSmoke, I have not tried yours yet, that is my next step. I have been doing small steps to make sure I get it right.

Here is where I am.

Wiring:
Pin 10 = Yellow LED
Pin 11 = Red LED
Pin 12 = Push button

Stages:
Stage 0 = Yellow LED solid, Red LED off
Stage 1 = Yellow LED flash, Red LED off
Stage 2 = Red LED flash, Yellow LED off

Here is how it is reacting now:
Power up, I go in to stage 0.
Press the push button I got to stage 1.
Press the push button I got to stage 2.
Press the push button I got to stage 1.
Press the push button I got to stage 2.

I never get back to stage 0.

When I press the push button, sometimes it reacts quickly (not normal). Sometimes I have to hold the push button for a second or 2. Sometimes I have to let go of the push button and repress to get it to trigger.

This may be an issue with the push button. Testing by just using jumpers, the response it a little faster and more consistent, but there is still a delay.

Here is the code i am using now:

const int buttonPin = 12;         // Mode switch

int buttonState = 0;
int stage;                        // Mode stage 0 = solid, 1 = yellow fade, 2 = color fade
byte ledPinY = 10;                // LED connected to digital pin 9
byte ledPinC = 11;                // LED connected to digital pin 10

void setup() {
  pinMode(ledPinY, OUTPUT);
  pinMode(ledPinC, OUTPUT);
  pinMode(buttonPin, INPUT);
  stage = 0;
}

void loop() {
  buttonState = digitalRead(buttonPin);
  
  if (buttonState == HIGH) {
      stage = stage + 1;
      if (stage >= 3) {
        stage = 0;
      }
  }
  
  // Yellow LED solid on
  if (stage == 0) {
    analogWrite(ledPinY, 255);  // Yellow soild on
    analogWrite(ledPinC, 0);    // Colored off
  }

  //Yellow LED fade in and out
  if (stage == 1) {
    // fade in from min to max in increments of 5 points:
    for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinY, fadeValue);
      analogWrite(ledPinC, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(30);
    }

    // fade out from max to min in increments of 5 points:
    for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinY, fadeValue);
      analogWrite(ledPinC, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(30);
    }
  }

  // Color LED fade in and out
  if (stage == 2) {
    // fade in from min to max in increments of 5 points:
    for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinC, fadeValue);
      analogWrite(ledPinY, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(15);
    }

    // fade out from max to min in increments of 5 points:
    for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
      // sets the value (range from 0 to 255):
      analogWrite(ledPinC, fadeValue);
      analogWrite(ledPinY, 0);
      // wait for 30 milliseconds to see the dimming effect
      delay(15);
    }
  }
}