Reactiongame two players. Button problem

hello!

Im creating a reactiongame. Each player have their own button. What im strugling with is the function to read if the button is puched down at any given time and not only when it passes in the loop. Or is there a way to pause the program to wait for one of the buttons to be pressed before it continues? Is case an option?

many thanks!

const int ButtonPin1 = 3;
const int ButtonPin2 = 2;
const int BuzzPin = 5;
const int LedPin1 = 6;
const int LedPin2 = 4;
const int BuzzDuration = 20000;
const int ToneHz = 3000;
volatile int state = LOW;

void setup() {
pinMode(ButtonPin1, INPUT);
pinMode(ButtonPin2, INPUT);
pinMode(BuzzPin, OUTPUT);
pinMode(LedPin1, OUTPUT);
pinMode(LedPin2, OUTPUT);

//Test
digitalWrite(LedPin1, HIGH);
delay(200);
digitalWrite(LedPin1, LOW);
digitalWrite(LedPin2, HIGH);
delay(200);
digitalWrite(LedPin2, LOW);
digitalWrite(BuzzPin, HIGH);
delay(400);
digitalWrite(BuzzPin, LOW);

Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(ButtonPin1),TurnOff, CHANGE);
attachInterrupt(digitalPinToInterrupt(ButtonPin2),TurnOff, CHANGE);

}

int Seier = random(1,3);

void loop(){

int VinnerLedPin;
int VinnerButtonPin;

if (Seier == 1){
  VinnerLedPin = LedPin1;
  }
else {
  VinnerLedPin = LedPin2;
  }

if(Seier == 1){
  VinnerButtonPin = ButtonPin1;
  }
else {
  VinnerButtonPin = ButtonPin2;
  }


delay(random(1000,8000));
digitalWrite(BuzzPin, HIGH);



int Spiller1; 
int Spiller2;

Spiller1 = digitalRead(ButtonPin1);
Spiller2 = digitalRead(ButtonPin2);


if(Spiller1 || Spiller2){
  Seier = Spiller1? 1 : 2; 
 Serial.print(Seier);
digitalWrite(BuzzPin,LOW); 
}


}
  
  
void TurnOff(){
  state = !state;
  digitalWrite(BuzzPin,state);
  
  }


[code]

Take a look at the PinChangeInt library. This allows one to catch a changing pin state.

Your Loop() should cycle very quickly, compared to typical Human response time.
Post your code using the "</>" button.
Explain the problem with your code, in more detail.

Yes, you could "WAIT" for one or both buttons to pressed by using an extremely fast while() statement

Or each button could trigger an Interrupt and
then the Interrupt could check a Global Flag to determine the order of the buttons pressed.

If you only need two buttons the attachInterrupt() function will be easier to use than pinChange interrupts.

Nick Gammon has a good interrupt tutorial

...R

code is on top. It is a bit messy at the moment but i kind of got it to work like it is now. Any tips on improvments ? :slight_smile:

Tiur:
code is on top.

Please don't make major changes to an earlier post. Anything more than corrections for typos usually makes a nonsense of the flow of discussion in a Thread.

I suspect that you should have two separate functions for your two buttons so you can tell which button caused the interrupt.

Although your code is not very long I can't immediately figure how it is supposed to work.

And please use the AutoFormat tool to improve the layout of your code. It makes it much easier to read.

...R

"blink" appears to be a LCD function.

The compiler doesn't seem to mind your using "blink" as the ISR name but I'm hoping someone can comment if using built in function names like this is acceptable practice.

I've always changed my variable or function names if they turn orange.

i got the buttons to work. The first who press it turns off the buzzer. But the problem i have now is my IF function who is suppose to declare the winner. It seem like because i used interrupt it wont enter the IF function, it will only register the winner if i hold one of the buttons down 2-3sec.

Any help on this part?

Tiur:
Any help on this part?

I bet you'd get lots of help if you post your code.

I would look at a state machine

player1 = digitalinput pin6
player2 = digitalinput pin7
player3 = digitalinput pin9

player4 = digitalinput pin9

player5 = digitalinput pin10

player6 = digitalinput pin11

test = (player1 + player2 + player3 + player4 + player5 + player6 )

if test is not equal to zero // or 6
go to your logic and display state.

this would scan the pins as fast as it can.
all pins would be either high or low, however you set them
if they are boolean, then they are either 1 or 0

the normal or ready state would be either 0 or 6
as soon as a pin is pressed, you exit this loop and then do the rest of the logic loop.

testing for scan time :

if you want to see the scan time, do an experiment
put in a state machine.
in the main loop, do as above

if count = 0 duration = millis()
long count = count ++
if count = 1,000,000
length = millis()-duration
go to your state machine.
length will be the milliseconds it took to run this loop 1,000,000 times.

say it takes 10 seconds to run this loop 1 million times, that it 100 thousand times a second
the chances of two players buzzing in at the same time are a googleplex.

if that happens, then just pick which ever player is older.
older, because reflexes are slower and they had the intention to buzz in first. .
the delay is in the nerves and muscles. and it would be unfair to penalize someone for age.

The TurnOff() function is the only function that should be reading the pins. It should set variables that the rest of the program can use. It should not perform any action of its own.

//copy paste button declarations and setup from before

volatile byte Winner = 0;

void TurnOff() {
  if(digitalRead(ButtonPin1)) Winner = 1;
  if(digitalRead(ButtonPin2)) Winner = 2;
}

void loop() {
  if(Winner != 0) {
    Serial.print("Winner is ");
    Serial.println(Winner);
    Winner = 0;
  }
}

Of course this doesn't do the buzzer. You can add that back later.

thanks, that helped a lot, made my code a lot easier. Any tips on how i can reduce the delay from when im pushing the button until the corrosponding LED light up? Right now it takes a good second before the Winning LED lights up.

const int ButtonPin1 = 3;
const int ButtonPin2 = 2;
const int BuzzPin = 5;
const int LedPin1 = 6;
const int LedPin2 = 4;
const int BuzzDuration = 20000;
const int ToneHz = 3000;
volatile byte Vinner = 0;

void setup() {
pinMode(ButtonPin1, INPUT);
pinMode(ButtonPin2, INPUT);
pinMode(BuzzPin, OUTPUT);
pinMode(LedPin1, OUTPUT);
pinMode(LedPin2, OUTPUT);

//Test
digitalWrite(LedPin1, HIGH);
delay(200);
digitalWrite(LedPin1, LOW);
digitalWrite(LedPin2, HIGH);
delay(200);
digitalWrite(LedPin2, LOW);
digitalWrite(BuzzPin, HIGH);
delay(400);
digitalWrite(BuzzPin, LOW);

Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(ButtonPin1),TurnOff, CHANGE);
attachInterrupt(digitalPinToInterrupt(ButtonPin2),TurnOff, CHANGE);

}

int Seier = random(1,10);

void loop(){

int Spiller1; 
int Spiller2;

delay(random(1000,8000));
digitalWrite(BuzzPin, HIGH);


int VinnerLedPin = Vinner == 1? LedPin1 : LedPin2;
  
if(Vinner != 0){
  digitalWrite(VinnerLedPin, HIGH);
  
  }

Spiller1 = digitalRead(ButtonPin1);
Spiller2 = digitalRead(ButtonPin2);


Vinner = 0;



}
  
  
void TurnOff(){
 if(digitalRead(ButtonPin1)) Vinner = 1;
 if(digitalRead(ButtonPin2)) Vinner = 2;
  digitalWrite(BuzzPin,LOW);
  
}




[code]

[/code]

OK, I couldn't resist re-writing it.

const int ButtonPin1 = 3;
const int ButtonPin2 = 2;
const int BuzzPin = 5;
const int LedPin1 = 6;
const int LedPin2 = 4;
const int BuzzDuration = 20000;
const int ToneHz = 3000;
volatile byte Vinner = 0;

void setup() {
  pinMode(ButtonPin1, INPUT);
  pinMode(ButtonPin2, INPUT);
  pinMode(BuzzPin, OUTPUT);
  pinMode(LedPin1, OUTPUT);
  pinMode(LedPin2, OUTPUT);

  //Test
  digitalWrite(LedPin1, HIGH);
  delay(200);
  digitalWrite(LedPin1, LOW);
  digitalWrite(LedPin2, HIGH);
  delay(200);
  digitalWrite(LedPin2, LOW);
  digitalWrite(BuzzPin, HIGH);
  delay(400);
  digitalWrite(BuzzPin, LOW);

  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(ButtonPin1), TurnOff, CHANGE);
  attachInterrupt(digitalPinToInterrupt(ButtonPin2), TurnOff, CHANGE);

}

int Seier = random(1, 10); //random variable does nothing - suggest removing this

void loop() {
  int tmpVinner;    //temporary copy of the volatile variable 
  int VinnerLedPin; //which LED to light to declare the winner

  delay(random(1000, 8000));
  digitalWrite(BuzzPin, HIGH);
  Vinner = 0;  //Erase any "winner" detected before the buzzer started.

  do {
    //do nothing while we wait for a winner to be declared

    //Take a "safe" copy of the winner, so that the interrupt
    //can't change it, like maybe the second player presses their button next.
    tmpVinner = Vinner;
  } while(tmpVinner == 0) 

  //The trinary operator (?:) is cool but too easy to make a mistake
  //use an if() statement to make the logic clear
  if(tmpVinner == 1) {
    VinnerLedPin = LedPin1;
  } else { //since it's not 1 and not zero, the winner must be 2
    VinnerLedPin = LedPin2;  
  }
  digitalWrite(VinnerLedPin, HIGH);

  delay(2000); //let the winner bask in their glory for 2 seconds

  //turn off the winner light and reset for the next round
  digitalWrite(LedPin1, LOW);
  digitalWrite(LedPin2, LOW);
  
  while(digitalRead(ButtonPin1)==HIGH || digitalRead(ButtonPin2)==HIGH) {
    //do nothing while we wait for BOTH buttons to be released
  }
}


void TurnOff() {
  //Interrupt
  //Turn off the buzzer and note which player it was pressed their button first
  if (digitalRead(ButtonPin1)) Vinner = 1;
  if (digitalRead(ButtonPin2)) Vinner = 2;
  digitalWrite(BuzzPin, LOW);
}