Button state changes to quickly*SOLVED*

Hi i’m trying to debug my code all though everything works for some reason my scroll butto to scroll between the pages on my lcd is far to sensitive when i press it sometimes it scrolls from page 1 to page 2 and back i just want it to change once until button is pressed again.

//Distance measure in cm converts to persentage
#include <Wire.h>
#include <LiquidCrystal_I2C.h> //sda=A4 scl=A5 
#include <NewPing.h>

const int trigPin1 = 5;    //Trigger pin for sensor 1.
const int echoPin1 = 6;    //Echo pin for sensor 1
const int trigPin2 = 8;    //Trigger pin for sensor 2
const int echoPin2 = 9;    //Echo pin for sensor2
LiquidCrystal_I2C lcd(0x27, 16, 2);
//Button scroll
int buzzer=5;
int page_counter=1 ;       //To move beetwen pages
int scroll=3;           //Scroll button/backlight button
int dt=100;
int pause = 2000;           //delay before restarting loop
int pause2 = 1000;
//Tank Measurments
int TankEmpty = 25;       // put your tank 1 depth here.
int TankEmpty2 = 20;       // put your tamkk 2 depth here,
int TankFull = 2;
int TankFull2 = 2;
int loopPause = 3000;
const int MAX_DISTANCE = 300;
//---------Storage debounce function-----//
boolean current_scroll = LOW;          
boolean last_scroll=LOW; 
//backlight control
boolean backLightOn;
unsigned long lastBacklight;
const int backLightDelay = 11000;



NewPing Sonar1 (trigPin1, echoPin1, MAX_DISTANCE);     //Use newping to calculate the distance
NewPing Sonar2 (trigPin2, echoPin2, MAX_DISTANCE);

int DistanceMeasured, DistanceMeasured2 = 0;  //stores the distances to water in tanks.
int percentage, percentage2 = 0;              //store the percentages of the tanks volume 

//Lcd Custom chars for bar graph
byte level0[] = {
  0x00,
  0x00,
  0x00,
  0x00,
  0x00,
  0x00,
  0x1F,
  0x1F
};
byte level1[] = {
  0x00,
  0x00,
  0x00,
  0x00,
  0x1F,
  0x1F,
  0x1F,
  0x1F
};
byte level2[] = {
  0x00,
  0x00,
  0x1F,
  0x1F,
  0x1F,
  0x1F,
  0x1F,
  0x1F
};
byte level3[] = {
  0x1F,
  0x1F,
  0x1F,
  0x1F,
  0x1F,
  0x1F,
  0x1F,
  0x1F
};
byte Nolevel[] = {
  0x00,
  0x00,
  0x00,
  0x00,
  0x00,
  0x00,
  0x00,
  0x00
};


void setup() {
  Serial.begin(9600);
   lastBacklight=millis();

//Pins conectaed to sensor
 pinMode (trigPin1, OUTPUT);       //Trigger pin 1 output
 pinMode (echoPin1, INPUT);        //Echo pin 1 input
 pinMode (trigPin2, OUTPUT);       //Trigger pin 2 output
 pinMode (echoPin2, INPUT);        //Echo pin 2 input
 pinMode (scroll, INPUT);          //Mode button  
 pinMode (buzzer, OUTPUT);         //buzzer pin

 
  
//lcd screen welcome message
lcd.backlight();
lcd.init();
lcd.createChar(4, Nolevel);
lcd.createChar(0, level0);
lcd.createChar(1, level1);
lcd.createChar(2, level2);
lcd.createChar(3, level3);
lcd.setCursor(3,0);           
lcd.print("Motor Home");
lcd.setCursor(2,1);
lcd.print("Water Levels");
lcd.setCursor(3,1);
delay(pause);
lcd.clear();
lcd.setCursor(3,0);
lcd.print("*WELCOME*");
delay (pause2);
lcd.clear();
delay(pause2);

}
            

   //---- De-bouncing function for all buttons----//
boolean debounce(boolean last, int pin){
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}


void loop() {
unsigned long currentMillis = millis();

//scroll button 
current_scroll = debounce(last_scroll, scroll);         //Debounce for button
 //Page scroll
    if (last_scroll== LOW && current_scroll == HIGH)    //When button is pressed
      {
      //if the backlight in on use the scroll button
      if (backLightOn)
      {
        //scroll page
      lcd.clear();                     //When page is changed, lcd clear to print new page  
      if(page_counter <2){              //Page counter never higher than 3(total of pages)
      page_counter= page_counter +1;   //Page up
      
      }
      else{
      page_counter= 1;  
      }
  }
  //Turn backlight on for the time
  backLightOn = true;
  lastBacklight = currentMillis;
  lcd.backlight();
  }
  //if the backlight is on and timer expires turn it off
  if (backLightOn && (currentMillis - lastBacklight >= backLightDelay))
  {
    backLightOn = false;
    lcd.noBacklight();
  }
  
  //------- Switch function to write and show what you want---// 
  switch (page_counter) {
   case 1:{     //Design of home page 1
      FreshWater();
    }
    break;

    case 2: { //Design of page 2 
     GreyWater();
    }
    break;
  
  }
}

                
void DisplayPercentage(unsigned percentage)
{
      if(percentage<=20)
      {
        ZeroPercent();
      }  
      else if(percentage>20 && percentage<=25)
      {
      TwentyFivePercent();
      }
      else if(percentage>25 && percentage<=50)
      {
      FiftyPercent();
     }
      else if(percentage>50 && percentage<=75)
      {
        SeventyFivePercent(); 
      }
    else if(percentage>75 && percentage<=100)
    {
      HundredPercent();
    }
    
}


void ZeroPercent()                 //Prints Bar graph chars to Lcd
{                                     
  lcd.setCursor(3, 1);                                       
  lcd.setCursor(3, 1);    
  lcd.write(byte(4));
  lcd.setCursor(4, 1); 
  lcd.write(byte(4));
  lcd.setCursor(5, 1); 
  lcd.write(byte(4));
  lcd.setCursor(6, 1); 
  lcd.write(byte(4));
  lcd.setCursor(7, 1);
  lcd.write(byte(4));
  lcd.setCursor(8, 1);
  lcd.write(byte(4));
  lcd.setCursor(9, 1);
  lcd.write(byte(4));
  lcd.setCursor(10, 1);
  lcd.write(byte(4));
  
}
void TwentyFivePercent()
{
  lcd.setCursor(3, 1); 
  lcd.write(byte(0));
  lcd.setCursor(4, 1); 
  lcd.write(byte(0));
  lcd.setCursor(5, 1); 
  lcd.write(byte(4));
  lcd.setCursor(6, 1); 
  lcd.write(byte(4));
  lcd.setCursor(7, 1);
  lcd.write(byte(4));
  lcd.setCursor(8, 1);
  lcd.write(byte(4));
  lcd.setCursor(9, 1);
  lcd.write(byte(4));
  lcd.setCursor(10, 1);
  lcd.write(byte(4));
}
void FiftyPercent()
{
  lcd.setCursor(3, 1); 
  lcd.write(byte(0));
  lcd.setCursor(4, 1); 
  lcd.write(byte(0));
  lcd.setCursor(5, 1); 
  lcd.write(byte(1));
  lcd.setCursor(6, 1); 
  lcd.write(byte(1));
  lcd.setCursor(7, 1);
  lcd.write(byte(4));
  lcd.setCursor(8, 1);
  lcd.write(byte(4));
  lcd.setCursor(9, 1);
  lcd.write(byte(4));
  lcd.setCursor(10, 1);
  lcd.write(byte(4)); 
}
void SeventyFivePercent()
{
  lcd.setCursor(3, 1); 
  lcd.write(byte(0));
  lcd.setCursor(4, 1); 
  lcd.write(byte(0));
  lcd.setCursor(5, 1); 
  lcd.write(byte(1));
  lcd.setCursor(6, 1); 
  lcd.write(byte(1));
  lcd.setCursor(7, 1);
  lcd.write(byte(2));
  lcd.setCursor(8, 1);
  lcd.write(byte(2));
  lcd.setCursor(9, 1);
  lcd.write(byte(4));
  lcd.setCursor(10, 1);
  lcd.write(byte(4));
  
}
void HundredPercent()
{
  lcd.setCursor(3, 1); 
  lcd.write(byte(0));
  lcd.setCursor(4, 1); 
  lcd.write(byte(0));
  lcd.setCursor(5, 1); 
  lcd.write(byte(1));
  lcd.setCursor(6, 1);
  lcd.write(byte(1));
  lcd.setCursor(7, 1);
  lcd.write(byte(2));
  lcd.setCursor(8, 1);
  lcd.write(byte(2));
  lcd.setCursor(9, 1);
  lcd.write(byte(3));
  lcd.setCursor(10, 1);
  lcd.write(byte(3));
}

  void GreyWater()
{  
   DistanceMeasured2 = Sonar2.ping_cm();
   percentage2 = map(DistanceMeasured2, TankEmpty2, TankFull2, 0, 100);
if(percentage2 <=1) {
 lcd.clear();
 lcd.setCursor (5,0);
 lcd.print ("EMPTY");
 delay(250);
} 
else if(percentage2 >=97){
  lcd.clear();
 lcd.setCursor (6,0);
 lcd.print ("FULL");
 delay(250);
}


lcd.home();
lcd.setCursor(0,0);                                              
lcd.print("Grey Water ");                                             //LCD Screen setup
lcd.setCursor(12,0);
lcd.setCursor(0, 1);
lcd.print("LOW");
lcd.setCursor(12, 1);
lcd.print("HIGH ");                                             
lcd.setCursor(12,0);
lcd.print(percentage2);
lcd.print("%    ");
DisplayPercentage(percentage2);
 
}
void FreshWater()
{
  DistanceMeasured = Sonar1.ping_cm();
  percentage = map(DistanceMeasured, TankEmpty, TankFull, 0, 100);     // Changes the distance measured in to percentage
  if(percentage <=4) {
 lcd.clear();
 lcd.setCursor (5,0);
 lcd.print ("EMPTY");
 delay(250);
} 
else if(percentage >=95){
  lcd.clear();
 lcd.setCursor (6,0);
 lcd.print ("FULL");
 delay(250);
}
lcd.home();
lcd.setCursor(0,0);                                              
lcd.print("Fresh Water");                                             //LCD Screen setup
lcd.setCursor(12,0);
lcd.setCursor(0, 1);
lcd.print("LOW");
lcd.setCursor(12, 1);
lcd.print("HIGH ");                                             
lcd.setCursor(12,0);
lcd.print(percentage);
lcd.print("%    ");
DisplayPercentage(percentage);

I don’t see any debounce code on your buttons. As you press the button, it touches the contact much like an airplane landing on a runway, only making full contact after a couple of bounces. these bounces are detectable by the microcontroller running 16 million cycles per second and are why you scroll a couple pages at a time.

Perehama is right. You can find info on switch inputs and debouncing on my site here

http://www.skillbank.co.uk/arduino/switches.htm
http://www.skillbank.co.uk/arduino/switchbounce.htm

but in short just put a small capacitor 0.022uF across the switch, and small resisitor 47 ohm as shown here Fig23B.

johnerrington:
Perehama is right. You can find info on switch inputs and debouncing on my site here

Digital inputs on an Arduino microcontroller
Digital inputs on an Arduino microcontroller

but in short just put a small capacitor 0.022uF across the switch, and small resisitor 47 ohm as shown here Fig23B.

This will modify the waveform, but you can also mitigate bounce in code. There are many examples on these forums, including older posts of mine, as well as the bounce2 library.

Perehama:
I don't see any debounce code on your buttons. As you press the button, it touches the contact much like an airplane landing on a runway, only making full contact after a couple of bounces. these bounces are detectable by the microcontroller running 16 million cycles per second and are why you scroll a couple pages at a time.

Hi this is the debounce section in my code is it applied correctly? I'm fairly new to this thanks.

   //---- De-bouncing function for all buttons----//
boolean debounce(boolean last, int pin){
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}

tooter:
Hi this is the debounce section in my code is it applied correctly? I'm fairly new to this thanks.

   //---- De-bouncing function for all buttons----//

boolean debounce(boolean last, int pin){
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}

So, last was LOW and current is HIGH, we wait 5 milliseconds, then return HIGH or LOW... Or, last was HIGH and current is LOW, we wait 5 milliseconds, then return the state... When do we change the value of last? what state do we want to consider true and why are we implicitly turning integers into booleans?
This is my personal favorite method to debounce, which I have adopted to this day.

hi thanks for the answer. but you lost me and the link you gave me was above my level.

You do have debounce code already, it’s pretty wierd. Did you write this? Did you try changing the 5ms delay in the debounce routine to something bigger?

First, let's go back a moment. Do you have a pull up or down resistor on your button? a pull-up/down resistor works electronically like the spring in the button. When you are not pressing the button, the spring lifts the button to an off state. Likewise, a pull-up/down resistor will pull the input HIGH or LOW respectively. If your button makes contact between the input and 0VDC, you want a pull-up resistor. If you make contact between the input and +5VDC, you want a pull-down resistor. Judging from the following line, you want a pull-down resistor, as you are making the switch to HIGH.if (last_scroll == LOW && current_scroll == HIGH)
Do you have this?

Perehama:
First, let's go back a moment. Do you have a pull up or down resistor on your button? a pull-up/down resistor works electronically like the spring in the button. When you are not pressing the button, the spring lifts the button to an off state. Likewise, a pull-up/down resistor will pull the input HIGH or LOW respectively. If your button makes contact between the input and 0VDC, you want a pull-up resistor. If you make contact between the input and +5VDC, you want a pull-down resistor. Judging from the following line, you want a pull-down resistor, as you are making the switch to HIGH.if (last_scroll == LOW && current_scroll == HIGH)
Do you have this?

Hi yes I have a pulldown resistor connected to ground.

...and.. did you try increasing the 5ms to say, 20ms?

tooter:
Hi yes I have a pulldown resistor connected to ground.

And, did you add a cap to square off the wave?

Perehama:
And, did you add a cap to square off the wave?

Not to be too picky, but:

And Or, did you add a cap to square off the wave? Since you don't need both.

aarg:
Not to be too picky, but:

And Or, did you add a cap to square off the wave? Since you don’t need both.

You DO need the resistor, and the capacitor MAY be added. But, squaring off the wave helps to debounce and increase responsiveness. Without the capacitor, the 5ms very likely needs extended to 50 or even 200 ms, but too much delay and the button response MAY feel sluggish.

Thanks I'll try tomorrow.

Ok so addedc the cap(10nf is all I had) changed the delay to 80 and it seems a lot better thanks for the help.