Debounce a push button

I have my code doing almost everything I want it to do, yet I think the debounce of a button is not working. I have looked up some ways to do this properly online and I was thinking I figured it out. Sometimes it will still double click!!! At least its not tripple clicking often anymore. If anyone has some ideas on how to make it better i would love to hear about it ]:smiley:

Heres the function with the button

void savecolor()
{
  int fadeChooseState = digitalRead(fadechoose);
  if (fadeChooseState != lastFadeChooseState)
  {
    if ( (millis() - lastDebounceTime) > debounceDelay)
    {
      if (fadeChooseState == LOW) 
      {
        delay (200);
        if (fadeChooseState == LOW)
        {
          if (fadeChooseCounter < 10)
          {
            fadeChooseCounter++;
            lastDebounceTime = millis();
          }
        }
      }
    }
    place[fadeChooseCounter][0] = analogRead(rpot)/4;
    place[fadeChooseCounter][1] = analogRead(gpot)/4;
    place[fadeChooseCounter][2] = analogRead(bpot)/4;


    redVal = place[fadeChooseCounter][0];
    grnVal = place[fadeChooseCounter][1];
    bluVal = place[fadeChooseCounter][2];

    lastFadeChooseState = fadeChooseState;



    Serial.print("Fade choose state");
    Serial.println(fadeChooseCounter);
    Serial.print("red (1)");
    Serial.print(place[0][0]);
    Serial.print("red (2)");
    Serial.print(place[1][0]);
    Serial.print("red(3)");
    Serial.print(place[2][0]);
  }
}

heres the full code

//led pins 
const byte red =11;
const byte green =9;
const byte blue =10;

//potentiometer pins
const int rpot =A3;
const int gpot =A4;
const int bpot =A5;

//potentiometer values
int rpotval = 0;
int gpotval = 0;
int bpotval = 0;

//buttons choose 
int fadeChooseCounter = 0;
int lastFadeChooseCounter = 0;
int lastFadeChooseState = 0;

// buttons display
int fadeon =2; 
int fadechoose =3;

//packages the values 
int rgb[3]={
  0};
int place[100][3]={
  {
    0            }
};
int column = 0;

int fadeval1;
int fadeval2;
int fadeval3;

// saved values
int loopCount = 60;
int black[3] = {
  0, 0, 0};
int redVal= black[0];
int grnVal= black[1];
int bluVal= black[2];
int prevR = redVal;
int prevG = grnVal;
int prevB = bluVal;
int rval1;
int gval1;
int bval1;

void setup()
{
  //declair pins functions 
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  pinMode(fadechoose, INPUT);
  pinMode(fadeon, INPUT);

  Serial.begin(9600);
}

void savecolor();
void displaycolors();
void potfun();

void loop()
{
  //runs the functions 
  savecolor();
  displaycolors();
}

long lastDebounceTime = 0;
long debounceDelay = 50; 
//stores the color in memory 
void savecolor()
{
  int fadeChooseState = digitalRead(fadechoose);
  if (fadeChooseState != lastFadeChooseState)
  {
    if ( (millis() - lastDebounceTime) > debounceDelay)
    {
      if (fadeChooseState == LOW) 
      {
        delay (200);
        if (fadeChooseState == LOW)
        {
          if (fadeChooseCounter < 10)
          {
            fadeChooseCounter++;
            lastDebounceTime = millis();
          }
        }
      }
    }
    place[fadeChooseCounter][0] = analogRead(rpot)/4;
    place[fadeChooseCounter][1] = analogRead(gpot)/4;
    place[fadeChooseCounter][2] = analogRead(bpot)/4;


    redVal = place[fadeChooseCounter][0];
    grnVal = place[fadeChooseCounter][1];
    bluVal = place[fadeChooseCounter][2];

    lastFadeChooseState = fadeChooseState;



    Serial.print("Fade choose state");
    Serial.println(fadeChooseCounter);
    Serial.print("red (1)");
    Serial.print(place[0][0]);
    Serial.print("red (2)");
    Serial.print(place[1][0]);
    Serial.print("red(3)");
    Serial.print(place[2][0]);
  }
}



// fades  stored values 
void displaycolors()
{

  int fadeOnState = digitalRead(fadeon);

  if(fadeOnState == LOW)
  {

    int i;
    for ( i = 0; i < fadeChooseCounter; i++)
    {
      crossFade (place[i]);
    }
    Serial.print("crossFade");
    Serial.print(place[i][0]);

  }

  else if (fadeOnState == HIGH) 
  {
    potfun();
  }



  delay(20);
}

void crossFade(int color[3])
{ 
  int R = color[0] ;
  int G = color[1] ;
  int B = color[2] ;

  int stepR = calculateStep(prevR, R);
  int stepG = calculateStep(prevG, G);
  int stepB = calculateStep(prevB, B);

  if (fadeChooseCounter != lastFadeChooseCounter)
  {
    fadeChooseCounter ++;
    lastFadeChooseCounter = fadeChooseCounter;
  }

  for (int i = 0; i <= 1020; i++)
  {
    redVal = calculateVal(stepR, redVal, i);
    grnVal = calculateVal(stepG, grnVal, i);
    bluVal = calculateVal(stepB, bluVal, i);

    analogWrite(red, redVal);
    analogWrite(green, grnVal);
    analogWrite(blue, bluVal);

    rpotval = analogRead(rpot) / 10;
    if (rpotval <= 5)
    {
      delay(44);
    }
    if (rpotval <= 25)
    {
      delay(24);
    }
    else if (rpotval <= 50)
    {
      delay(12);
    }
    else if (rpotval <= 75)
    {
      delay(9);
    }
    else if (rpotval <= 100)
    {
      delay(3);
    } 
    if (i == 0 or i % loopCount == 0) { // beginning, and every loopCount times
      Serial.print("Loop/RGB: #");
      Serial.print(i);
      Serial.print(" | ");
      Serial.print(redVal);
      Serial.print(" / ");
      Serial.print(grnVal);
      Serial.print(" / ");  
      Serial.println(bluVal); 
    }
  }

  prevR = redVal; 
  prevG = grnVal; 
  prevB = bluVal;

  gpotval = analogRead(gpot) / 10;
  if (gpotval <= 25)
  {
    delay(2000);
  }
  else if (gpotval <= 50)
  {
    delay(1000);
  }
  else if (gpotval <= 75)
  {
    delay(500);
  }
  else if (gpotval <= 100)
  {
    delay(3);
  }

}


int calculateStep(int prevValue, int endValue)
{
  int step = endValue - prevValue;
  if (step) 
  {
    step = 1020/step;
  }
  return step; 
}

int calculateVal(int step, int val, int i) 
{
  if ((step) && i % step == 0)
  {
    if (step > 0)
    { 
      val += 1;
    }
    else if (step < 0) 
    {
      val -= 1;
    }
  }

  if (val > 255)
  {
    val = 255;
  }
  if (val < 0)
  {
    val = 0;
  }
  return val;
}


// reads potentiometers value and turns it from 1023 to 255 
void potfun()
{

  rpotval = analogRead(rpot)/4;
  gpotval = analogRead(gpot)/4;
  bpotval = analogRead(bpot)/4;

  // sends values to leds so you can pick full range of colors
  analogWrite(red, rpotval);
  analogWrite(green, gpotval);
  analogWrite(blue, bpotval);

  Serial.print("redpot");
  Serial.print(rpotval);
  Serial.print("greenpot");
  Serial.print(gpotval);
  Serial.print("bluepot");
  Serial.print(bpotval);
  delay(3);
}

Moderator edit: Quote tags replace with CODE TAGS. Duplicate post deleted.

Thanks for the edit

How I do debouncing:

When the button state changes, record the fact, along with the time the change happened. Every state change records this data.

If the last state change happened more than 10ms ago (or 20ms, or whatever debounce period you want to use), then take the recorded state as the new button state and pass it on to whatever it is you're doing.

Something like:

static unsigned char dbState = digitalRead(3);
static unsigned char buttonState = digitalRead(3);
static unsigned long dbTime = 0;
unsigned char buttonValue;
boolean buttonChanged = false;

buttonValue = digitalRead(3);

if (buttonValue != dbState) {
  dbState = buttonValue;
  dbTime = millis();
}

// 50ms debounce
if ((dbTime > 0) && (millis() - dbTime > 50)) {
  dbTime = 0;
  buttonState = dbState;
  buttonChanged  = true;
}

if (buttonChanged) {
  // Do something with buttonState
}

Note: this is untested - don't even know if it compiles.

I normally use a time-triggered architecture in my designs, so the pushbuttons are polled regularly every few milliseconds. On each poll, I count down towards 0 whenever the button is open and up towards a constant (usually 3) whenever it is closed. When the count goes from 2 to 3 I register a press, and when it goes from 1 to 0 I register a release. You can find the code at GitHub - dc42/arduino: Reusable modules, drivers and patches for the Arduino platform.

Ok thanks guys.

If you don't mind spending 10 cents, a sure=fire debounce that can be tailored to just about any situation involves using the stimulus signal to trigger a 555 in monostable mode, and read the 555 output as the switch input to your code. Just set the 555 pulse width to exceed the max debounce, then use software delay to reset the 555 so it's ready soon enough for the next trigger.

I just posted my version of this tonight, actually.

http://appleause.com/2013/04/13/part-3-debouncing-digital-inputs/

That code monitors as many inputs as needed, with debounce time adjustable. It was the first thing I ever wrote for Arduino, and we were specifically using it to monitor pressure mats in a commercial haunted house attraction here in Iowa.