Stopping a count after a single button press (SOLVED)

I'm working on a "button mashing" game. The goal is for two players to hit their respective buttons as fast as they can. As they continue to press the buttons, each player can track their progress on an LED bar graph. First player to fill up their bar graph wins.

Short version: It's a race to see which player can hit the button a certain number of times the fastest.

As far as my code goes, they game plays exactly as I want it to but there is one thing I'm having trouble figuring out. When a button is engaged, the Arduino will count. The problem is that a player could just hold down the button and the count will continue. This defeats the purpose of the game.

What I would like is for the Arduino to increase the count by only 1 when the button is pressed and that the count will not increase until the user releases the switch and then presses it again. Any ideas/suggestions would be awesome. Thanks folks!

int red1 = 2;
int red2 = 3;
int red3 = 4;
int grn1 = 5;
int grn2 = 6;
int grn3 = 7;
int redButton = 8;
int blackButton = 9;
int redButtonState = 0;
int blackButtonState = 0;
int redCount = 0;
int lastRedState = 0;
int blackCount = 0;
int lastBlackState = 0;
unsigned long previousRedMillis = 0;
long redInterval = 150;
unsigned long previousBlackMillis = 0;
long blackInterval = 150;

void setup() 
{
  pinMode(red1, OUTPUT);
  pinMode(red2, OUTPUT);
  pinMode(red3, OUTPUT);
  pinMode(grn1, OUTPUT);
  pinMode(grn2, OUTPUT);
  pinMode(grn3, OUTPUT);
  pinMode(redButton, INPUT);
  pinMode(blackButton, INPUT);
  Serial.begin(9600);
}

void loop() 
{
  redButtonState = digitalRead(redButton);
  blackButtonState = digitalRead(blackButton);
  
  unsigned long currentRedMillis = millis();
  if (currentRedMillis - previousRedMillis >= redInterval)
  {
    previousRedMillis = currentRedMillis;
    if (redButtonState != lastRedState)
    {
     if (redButtonState == HIGH)
      {
        redCount++;
        Serial.println(redCount);
      }
    }
  }


  
  if (blackButtonState != lastBlackState)
  {
    if (blackButtonState == HIGH)
    {
       unsigned long currentBlackMillis = millis();
       if (currentBlackMillis - previousBlackMillis >= blackInterval)
       {
        previousBlackMillis = currentBlackMillis;
        blackCount++;
        Serial.println(blackCount);
       }
    }
  }

  
  if (redCount >= 20)
  {
    digitalWrite(red1, HIGH);
    if (redCount >= 40)
    {
      digitalWrite(red2, HIGH);
      if (redCount >= 60)
      {
        digitalWrite(red3, HIGH);
      }
    }
  }

  
  if (blackCount >= 20)
  {
    digitalWrite(grn1, HIGH);
    if (blackCount >= 40)
    {
      digitalWrite(grn2, HIGH);
      if (blackCount >= 60)
      {
        digitalWrite(grn3, HIGH);
      }
    }
  } 

  
  if (redCount >= 60 && redCount > blackCount)
  {
    blackCount = 0;
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    delay(1000);
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    delay(500);
    digitalWrite(red1, HIGH);
    digitalWrite(red2, HIGH);
    digitalWrite(red3, HIGH);
    delay(500);
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    delay(500);
    digitalWrite(red1, HIGH);
    digitalWrite(red2, HIGH);
    digitalWrite(red3, HIGH);
    delay(500);
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    delay(500);
    digitalWrite(red1, HIGH);
    digitalWrite(red2, HIGH);
    digitalWrite(red3, HIGH);
    delay(500);
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    delay(500);
    digitalWrite(red1, HIGH);
    digitalWrite(red2, HIGH);
    digitalWrite(red3, HIGH);
    delay(500);
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    delay(500);
    digitalWrite(red1, HIGH);
    digitalWrite(red2, HIGH);
    digitalWrite(red3, HIGH);
    delay(500);
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    delay(500);
    digitalWrite(red1, HIGH);
    digitalWrite(red2, HIGH);
    digitalWrite(red3, HIGH);
    delay(500);
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    redCount = 0;
  }

  
  if (blackCount >= 60 && blackCount > redCount)
  {
    redCount = 0;
    digitalWrite(red1, LOW);
    digitalWrite(red2, LOW);
    digitalWrite(red3, LOW);
    delay(1000);
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    delay(500);
    digitalWrite(grn1, HIGH);
    digitalWrite(grn2, HIGH);
    digitalWrite(grn3, HIGH);
    delay(500);
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    delay(500);
    digitalWrite(grn1, HIGH);
    digitalWrite(grn2, HIGH);
    digitalWrite(grn3, HIGH);
    delay(500);
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    delay(500);
    digitalWrite(grn1, HIGH);
    digitalWrite(grn2, HIGH);
    digitalWrite(grn3, HIGH);
    delay(500);
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    delay(500);
    digitalWrite(grn1, HIGH);
    digitalWrite(grn2, HIGH);
    digitalWrite(grn3, HIGH);
    delay(500);
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    delay(500);
    digitalWrite(grn1, HIGH);
    digitalWrite(grn2, HIGH);
    digitalWrite(grn3, HIGH);
    delay(500);
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    delay(500);
    digitalWrite(grn1, HIGH);
    digitalWrite(grn2, HIGH);
    digitalWrite(grn3, HIGH);
    delay(500);
    digitalWrite(grn1, LOW);
    digitalWrite(grn2, LOW);
    digitalWrite(grn3, LOW);
    blackCount = 0;
  }
}

If you are trying to see who can click the fastest I don't understand why are using time intervals with millis(). Also you should not have separate currentRedMillis and currentBlackMillis. Just use the same value for both. And if you look at your program you will see that you have positioned if (currentBlackMillis in a different part if the logical sequence to if (currentRedMillis - that does not make sense.

I would expect the line if (redButtonState != lastRedState) to require the user to release the button.

...R

And depending on the type of button switch, you will need to ignore contact bounce which means if you see a time less than some predetermined value, it is switch bounce, not a contestant pressing the switch.

Paul

Got it working. It was a silly mistake. I forgot to include this line into my code.

lastRedState = redButtonState;

(And then same for the black button)

As a result it didn't save the current state of the switch as its previous state.

Also Robin, I took care of currentBlackMillis and currentRedMillis thing. The reason I'm using Millis() is so I can prevent bouncing without using a delay. I tried it with a delay function at first but I need the board to be able to multitask so both button presses can be counted at the same time.

Machinimax:
The reason I'm using Millis() is so I can prevent bouncing without using a delay.

Ahhh. That's understandable. But I suspect 50 milllisecs would be plenty.

And I think you have your millis() on the wrong side of your digitalRead()s. I would do it like this

	unsigned long currentRedMillis = millis();
	if (currentRedMillis - previousRedMillis >= redInterval) {
		previousRedMillis += redInterval;
		redButtonState = digitalRead(redButton);
		blackButtonState = digitalRead(blackButton);
	}
	// and then check your button states

Note that with this system the one interval deals with both buttons.

...R

Robin2:
Ahhh. That's understandable. But I suspect 50 milllisecs would be plenty.

You are correct. I wound up making the change not long after I fixed the problem.