Simple Score Keeper

I'm working on the debounce its been a lot to digest so im getting other basic functions working in-between.

//LOOP==============================================
void loop() {

//LCD TOP ROW: SCORE / GAME OVER

  lcd.setCursor(0, 0);

  if (ballnumber < 1)
  {  
    lcd.clear();
    lcd.print("GAME OVER      ");
  }
  else
  {
  lcd.print("SCORE:    BALL:");
  lcd.print(ballnumber);
  }

This causes a rapid pulsing "GAME OVER" message because its constantly looping the clear. It also clears your numeric score under it, which I do not want. I'd want the player to be able to see their score at the end of the game.

*edit, included the rest of the loop code

Just clear the zone where the 1 appears

ok.

I tied:

lcd.clear(0, 0);

and

lcd.clear(ballnumber);

Both of those gave me errors. Googled the problem, only suggestion I found that was helpful was to add more spaces:

void loop() {

//LCD TOP ROW: SCORE / GAME OVER

  lcd.setCursor(0, 0);

  if (ballnumber < 1)
  {  
   
    lcd.print("GAME OVER         ");
  }
  else
  {
  lcd.print("SCORE:    BALL:");
  lcd.print(ballnumber);
  }

If anyone else is having the same problem, that's how I'm solving it for now unless someone can explain how to clear specific zones.

Let's say you want to clear 0,8 to 0,12

//position your cursor on the first location in the zone you want to clear
//then print spaces to the last position in the zone
lcd.setCursor(0,8 ); 
//         00111
//         89012
lcd.print("     ");

.

LarryD:
I don't recall how your switches are wired but you may need INPUT_PULLUP in pinMode.

Last we heard, there were neither pull-up resistors nor pull-down resistors.

It's important to get the buttons wired correctly before worrying about anything else.

How are your buttons wired?

You've only been posting the loop() function of your code. We really need to see all of the code.

As for displaying the score: it may be time to introduce sprintf().

If I were doing this, I would use lines like these in my code:

// declare a buffer for characters
char buf[21] = "\0"; // max 20 characters plus marker at end of string
// we really only need 16 characters, but I want to be on the safe side


// write the score and ball number to the character buffer
sprintf(buf, "%05d    %d ", score, ballnumber);

// display what is in the character buffer
lcd.print(buf);

ok, So I think I am beginning to wrap my head around debouncing, but ran into a road block.

I'm following this tutorial's code:

and I applied it to my (GREEN) 100pt button, and eventually got it working. I even tested the button in rapid succession and found that it worked exactly as it should, not allowing the points to be counted if the button was pushed within (50).

when I tried to apply this same code the 'Ball Lost' Button, I got an error:


debounce_tutorial:77: error: redeclaration of 'int reading'

int reading = analogRead(A1);

^

debounce_tutorial:59: error: 'int reading' previously declared here

int reading = analogRead(A0);


The error seems to say I cant use (analogRead) for two different functions in the loop?

Here is my code, and an image of my wiring:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

  boolean lastReadButton1;
  boolean lastReadButton2;
  boolean lastReadButton3;
  boolean lastReadButton4;

int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

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

  unsigned int score = 0;
  int ballnumber = 5;
  int a = 100;
  int b = 500;
  int c = 1000;


// SETUP===========================================
void setup() {

//input pins for scoring triggers
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  

// set up the LCD:
  lcd.begin(16, 2);
  lcd.clear();

}

//LOOP==============================================
void loop() {

//LCD TOP ROW: SCORE / GAME OVER

  lcd.setCursor(0, 0);

  if (ballnumber < 1)
  { 
   
    lcd.print("GAME OVER         ");
  }
  else
  {
  lcd.print("SCORE:    BALL:");
  lcd.print(ballnumber);
  }
//LCD BOTTOM ROW: NUMERIC SCORE
 
  lcd.setCursor(0, 1);
  lcd.print(score);

///LOST BALL///BLACK///////////////////////////////////
  int reading = analogRead(A0);

  if (reading != lastButtonState) {

    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {

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

      if (buttonState == HIGH) {
         ballnumber = ballnumber - 1;
      }
    }
  }
  lastButtonState = reading;
///SCORE a 100 PTS///GREEN////////////////
  int reading = analogRead(A1);

  if (reading != lastButtonState) {

    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {

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

      if (buttonState == HIGH) {
         score = score + a;
      }
    }
  }
  lastButtonState = reading;

///SCORE B 500 PTS///YELLOW////////////////
   boolean readButton3 = digitalRead(A2);
 
  if (readButton3 == LOW and lastReadButton3 == HIGH)
  {
      score = score + b;
  }
  lastReadButton3 = readButton3;

///SCORE C 1000 PTS///RED////////////////
   boolean readButton4 = digitalRead(A3);
 
  if (readButton4 == LOW and lastReadButton4 == HIGH)
  {
      score = score + c;
  }
  lastReadButton4 = readButton4;

}

replace the second use of the variable, i.e.:

int reading = analogRead(A1);

with

reading = analogRead(A1);

since you have previously defined the type of the variable, and the type cannot change. You can re-use the variable, but cannot re-define the type.

Thank you that did get rid of the error, however both buttons stopped working.
When I reverted back to the old the GREEN (A1) code, the (A0) code started working again.

So they are still combating each other?

Currently works (but no debounce on green)

///LOST BALL///BLACK///////////////////////////////////
  int reading = analogRead(A0);

  if (reading != lastButtonState) {

    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {

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

      if (buttonState == HIGH) {
         ballnumber = ballnumber - 1;
      }
    }
  }
  lastButtonState = reading;
///SCORE a 100 PTS///GREEN////////////////
   boolean readButton2 = digitalRead(A1);
 
  if (readButton2 == LOW and lastReadButton2 == HIGH)
  {
      score = score + a;
  }
  lastReadButton2 = readButton2;
  
  lastButtonState = reading;

Currently neither button works when I leave it like this:

///LOST BALL///BLACK///////////////////////////////////
  int reading = analogRead(A0);

  if (reading != lastButtonState) {

    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {

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

      if (buttonState == HIGH) {
         ballnumber = ballnumber - 1;
      }
    }
  }
  lastButtonState = reading;

///SCORE a 100 PTS///GREEN////////////////
reading = analogRead(A1);

  if (reading != lastButtonState) {

    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {

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

      if (buttonState == HIGH) {
         score = score + a;
      }
    }
  }

You have 2 buttons, you need to store the state for each button independently. You can only reuse a variable in this case if it is a temporary variable.

Something like this:

///LOST BALL///BLACK///////////////////////////////////
  int reading = analogRead(A0);

  if (reading != lastButtonState) {

    lastDebounceTime = millis();
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {

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

      if (buttonState == HIGH) {
         ballnumber = ballnumber - 1;
      }
    }
  }
  lastButtonState = reading;

///SCORE a 100 PTS///GREEN////////////////
reading = analogRead(A1);

  if (reading != lastButton2State) {

    lastDebounce2Time = millis();
  }
  if ((millis() - lastDebounce2Time) > debounceDelay) {

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

      if (button2State == HIGH) {
         score = score + a;
      }
    }
  }

well I tried making a unique naming convention for each copy of the button code as suggested, but that currently isnt working. I get no errors but neither button does anything at the moment:

Going to keep trying things. If anyone has other ideas let me know.

Code:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

  boolean lastReadButton1;
  boolean lastReadButton2;
  boolean lastReadButton3;
  boolean lastReadButton4;

int button_0State;             // the current reading from the input pin
int button_aState; 
int lastButton_0State = LOW;   // the previous reading from the input pin
int lastButton_aState = LOW;

long lastDebounce_0Time = 0;  // the last time the output pin was toggled
long lastDebounce_aTime = 0;
long debounceDelay = 50;    // the debounce time; increase if the output flickers

  unsigned int score = 0;
  int ballnumber = 5;
  int a = 100;
  int b = 500;
  int c = 1000;


// SETUP===========================================
void setup() {

//input pins for scoring triggers
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  

// set up the LCD:
  lcd.begin(16, 2);
  lcd.clear();

}

//LOOP==============================================
void loop() {

//LCD TOP ROW: SCORE / GAME OVER

  lcd.setCursor(0, 0);

  if (ballnumber < 1)
  { 
   
    lcd.print("GAME OVER         ");
  }
  else
  {
  lcd.print("SCORE:    BALL:");
  lcd.print(ballnumber);
  }
//LCD BOTTOM ROW: NUMERIC SCORE
 
  lcd.setCursor(0, 1);
  lcd.print(score);

///LOST BALL///BLACK///////////////////////////////////
  int reading = analogRead(A0);

  if (reading != lastButton_0State) {

    lastDebounce_0Time = millis();
  }
  if ((millis() - lastDebounce_0Time) > debounceDelay) {

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

      if (button_0State == HIGH) {
         ballnumber = ballnumber - 1;
      }
    }
  }
  lastButton_0State = reading;

///SCORE a 100 PTS///GREEN////////////////
analogRead(A1);

  if (reading != lastButton_aState) {

    lastDebounce_aTime = millis();
  }
  if ((millis() - lastDebounce_aTime) > debounceDelay) {

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

      if (button_aState == HIGH) {
         score = score + a;
      }
    }
  }
  lastButton_aState = reading;
///SCORE B 500 PTS///YELLOW////////////////
   boolean readButton3 = digitalRead(A2);
 
  if (readButton3 == LOW and lastReadButton3 == HIGH)
  {
      score = score + b;
  }
  lastReadButton3 = readButton3;

///SCORE C 1000 PTS///RED////////////////
   boolean readButton4 = digitalRead(A3);
 
  if (readButton4 == LOW and lastReadButton4 == HIGH)
  {
      score = score + c;
  }
  lastReadButton4 = readButton4;

}

Here's your problem:

  int reading = analogRead(A0);

  if (reading != lastButton_0State) {

    lastDebounce_0Time = millis();
  }
  if ((millis() - lastDebounce_0Time) > debounceDelay) {

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

      if (button_0State == HIGH) {
         ballnumber = ballnumber - 1;
      }
    }
  }
  lastButton_0State = reading;

basically,

  if ((millis() - lastDebounce_0Time) > debounceDelay) {

can only be true if "reading" has been the same as the "lastButton_0State" for greater than the debounce time (otherwise the debounce timer would reset again), but then inside this "if", you do a check of:

    if (reading != button_0State) {

which will never pass.

:confused: I do not follow. Sorry, I have no programming experience as of a week ago so I'm really trying hard to learn and understand this.

I have eliminated everything from the code except the ball loss button. I have added comments into the debounce code as to my understanding of how this works... if you could correct me where I'm going wrong or let me know where the logic falls apart I'd appreciate it.

P.S. the button does not currently work. not sure why.

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

  unsigned int score = 0;
  int ballnumber = 5;



// SETUP===========================================
void setup() {

//input pins for scoring triggers
  pinMode(A0, INPUT);


// set up the LCD:
  lcd.begin(16, 2);
  lcd.clear();

}

//LOOP==============================================
void loop() {

//LCD TOP ROW: SCORE / GAME OVER

  lcd.setCursor(0, 0);

  if (ballnumber < 1)
  { 
   
    lcd.print("GAME OVER         ");
  }
  else
  {
  lcd.print("SCORE:    BALL:");
  lcd.print(ballnumber);
  }
//LCD BOTTOM ROW: NUMERIC SCORE
  lcd.setCursor(0, 1);
  lcd.print(score);

///LOST BALL///BLACK///////////////////////////////////
  int reading = analogRead(A0);  //////Listen to what A0 is saying

  if (reading != lastButtonState) {///////If what you hear is not the same....

    lastDebounceTime = millis();/////...from the last reading 0 milliseconds ago.
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {///...and if your last change was longer than 50 milliseconds ago...

      if (reading != buttonState) {///if the signal is not high
        buttonState = reading;     ///then continue just reading

      if (buttonState == HIGH) {     ////if it IS high
         ballnumber = ballnumber - 1;/////Then take away 1 ball from the ballnumber
      }
    }
  }
  lastButtonState = reading; /////....Refering to the first "if" statement? 
}

analogRead(A0);
I believe you wanted
digitalRead(A0);
in fact I would use
digitalRead(14); //reminds you you are using a digital input rather than analog.

I have made some edits to your code which should now work. A big problem was that in your above post there was a closing brace (}) in the wrong spot (look at "if (reading != buttonState)"). Also another issue was your buttonState variable was only being set when reading != buttonState which since buttonState was never initialized it could be inconsistent.

The code below is quite a bit different so please compare it/read over it to and let me know if you have any questions.

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

int lastButtonState = LOW;   // the previous reading from the input pin
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 50;    // the debounce time; increase if the output flickers

  unsigned int score = 0;
  int ballnumber = 5;



// SETUP===========================================
void setup() {

//input pins for scoring triggers
  pinMode(A0, INPUT);


// set up the LCD:
  lcd.begin(16, 2);
  lcd.clear();

}

//LOOP==============================================
void loop() {

//LCD TOP ROW: SCORE / GAME OVER

  lcd.setCursor(0, 0);

  if (ballnumber < 1)
  { 
   
    lcd.print("GAME OVER         ");
  }
  else
  {
  lcd.print("SCORE:    BALL:");
  lcd.print(ballnumber);
  }
//LCD BOTTOM ROW: NUMERIC SCORE
  lcd.setCursor(0, 1);
  lcd.print(score);

///LOST BALL///BLACK///////////////////////////////////
  int reading = analogRead(A0);  //////Listen to what A0 is saying

  //Turn off timer when button is released
  if (reading == LOW)
  {
      lastDebounceTime = 0;
  }
   
  if (lastDebounceTime == 0)
  {
    if (reading == HIGH) 
    {///////If what you hear is not the same....
      //Added -debounceDelay to offset timer so the first ball is removed right away
      lastDebounceTime = millis() - debounceDelay;/////...from the last reading 0 milliseconds ago.
    }
  }
  else
  {
    if ((millis() - lastDebounceTime) > debounceDelay) 
    {///...and if your last change was longer than 50 milliseconds ago...
      ballnumber = ballnumber - 1;/////Then take away 1 ball from the ballnumber
      lastDebounceTime = millis(); //Restart Timer
    }
  }
}

The code is currently not working right. when I push the button it rapidly deletes all the balls in the ballnumber.

It may have to do with my wiring? Here's a pic of my wiring. The white wire goes to A0 which the black button is hooked up to.

50 milliseconds is pretty fast, see what happens if you change "debounceDelay=2000" do they still all disappear really fast or is there now a 2 second delay?

yup it just more slowly takes all the balls away.

Isn't this how you wanted it to work? Or did you just want it to take a ball away every time you press and wait until the next press to take the next one?

Yes, I want the button to remove a single ball from the ballnumber total. Then then the button is pressed again, another ball is removed.

That goes on until there are no more balls, then the LCD reads GAME OVER.