My idea is to have a switch case inside the ISR functions.
Case 1 would change the variables dealing with the game if the button is pushed.
Case 2 would change the variables dealing with the number of players selected.
Switches operating at human speed don't usually need interrupts on an Arduino. However, I will attempt to answer your question.
ISRs should do the minimum possible and execute quickly. Do not call anything that uses interrupts. Importantly, this includes not calling Serial.print(...) or anything similar, which makes debugging difficult.
Variables shared between background code (setup() or loop()) and the ISR should be declared volatile so that GCC knows that the variable could change value unexpectedly.
Avoid analogRead() inside ISRs. That also uses interrupts. If you're using analogRead() in the normal program, an interrupt can occur in the middle of the read process, which gives you some idea of how little processing you should be doing inside the ISR. That is, the duration of a call to analogRead() is many times longer than a typical interrupt.
It has a busy-wait loop waiting for the A-D conversion to finish. I forget which flag or interrupt it is using for that. (Different on every chip.) But there certainly is an interrupt raised whenever the AD conversion is completed.
Also, if you are using any global variables in the ISR, you should define them as volatile. So, if counter is a global int that is used in an ISR, you should define it as:
volatile int counter;
The reason is because optimizing compilers often cache variables in a register, especially if they are heavily used. Because an interrupt can occur at any time, the current value of the cached variable might not be "update to date" in the cache. Using the volatile data modifier forces the compiler to reload the variable each time it's used, thus insuring the current value is being used.
econjack:
Also, if you are using any global variables in the ISR, you should define them as volatile. So, if counter is a global int that is used in an ISR, you should define it as:
volatile int counter;
The reason is because optimizing compilers often cache variables in a register, especially if they are heavily used. Because an interrupt can occur at any time, the current value of the cached variable might not be "update to date" in the cache. Using the volatile data modifier forces the compiler to reload the variable each time it's used, thus insuring the current value is being used.
volatile is needed when a global variable is shared between foreground and ISR.
If the ISR is the only entity that uses the global variable, it does not need to be declared volatile.
Generally speaking, interrupt routines should do almost nothing except setting volatile flags that indicate that an interrupt has occurred. Generally.
Remember that if an interrupt sets three variables, you will want to turn interrupts off while you read those three variables as a group and stuff them into local variables.
volatile boolean _flag = false;
volatile int _count = 0;
volatile int _othercount = 0;
void ISR() {
_flag = true;
_count ++;
if(digitalRead(3)) _othercount++;
}
void loop() {
nointerrupts();
boolean flag = _flag;
int count = _count;
int othercount = _otherCount;
_flag = false;
_count = 0;
_othercount = 0;
interrupts();
// do some stuff. Even use delay(), if you want.
if(flag) {
// ok! We had some interrupts while we were doing other stuff. Deal with it.
}
}