The code below is closer to what you seem to be asking about:
// For Mega2560
const int BUTTONS = 4;
const int FIRST_SWITCH = 18;
const int FIRST_RELAY = 41;
const int CLICKS = 5;
const unsigned long DEBOUNCE_TIME = 20; // ms
int retardo = 300;
int finBoton = 1000;
volatile byte counts [BUTTONS];
unsigned long lastPress [BUTTONS];
void doInterrupts (const int which)
{
// debounce
if (millis () - lastPress [which] < DEBOUNCE_TIME)
return;
lastPress [which] = millis ();
counts [which]++;
} // end of doInterrupts
void pin18Pressed ()
{
doInterrupts (0);
} // end of pin18Pressed
void pin19Pressed ()
{
doInterrupts (1);
} // end of pin19Pressed
void pin20Pressed ()
{
doInterrupts (2);
} // end of pin20Pressed
void pin21Pressed ()
{
doInterrupts (3);
} // end of pin21Pressed
void setup()
{
// configure inputs / outputs
for (int i = 0; i < BUTTONS; i++)
{
pinMode (FIRST_SWITCH + i, INPUT_PULLUP);
pinMode (FIRST_RELAY + i, OUTPUT);
}
attachInterrupt (5, pin18Pressed, FALLING);
attachInterrupt (4, pin19Pressed, FALLING);
attachInterrupt (3, pin20Pressed, FALLING);
attachInterrupt (2, pin21Pressed, FALLING);
} // end of setup
// turn relay on for a particular switch
void handleSwitchPress (const int which)
{
for (int i = 0; i < CLICKS; i++)
{
digitalWrite(FIRST_RELAY + which, HIGH);
delay(retardo);
digitalWrite(FIRST_RELAY + which, LOW);
delay(retardo);
}
delay(finBoton);
} // end of handleSwitchPress
// main loop
void loop()
{
for (int i = 0; i < BUTTONS; i++)
if (counts [i] > 0)
{
handleSwitchPress (i);
counts [i]--;
}
} // end of loop
I'll explain parts of it from above:
Interrupts
To queue up switch presses we can use an interrupt. The Mega has quite a few external interrupts (See: attachInterrupt()) so I'll use those. You can read about interrupts on my page about interrupts.
This code attaches four interrupts handlers:
attachInterrupt (5, pin18Pressed, FALLING);
attachInterrupt (4, pin19Pressed, FALLING);
attachInterrupt (3, pin20Pressed, FALLING);
attachInterrupt (2, pin21Pressed, FALLING);
Because of the way the hardware works we have to use pins 18, 19, 20 and 21 (there are a couple more but these are in sequence).
I set the switches to be INPUT_PULLUP so that they are normally HIGH when not pressed, and go LOW when you press them. Hence the interrupts are looking for a FALLING edge.
Handle one interrupt
An interrupt handler is like this:
void pin18Pressed ()
{
doInterrupts (0);
} // end of pin18Pressed
Since they all do much the same thing I put all of the switch management into one function and used an array of switches, like this:
volatile byte counts [BUTTONS];
unsigned long lastPress [BUTTONS];
void doInterrupts (const int which)
{
// debounce
if (millis () - lastPress [which] < DEBOUNCE_TIME)
return;
lastPress [which] = millis ();
counts [which]++;
} // end of doInterrupts
In order to "queue" presses the interrupt handler adds one to a counter, for that array item. (So, pin 18 is position 0, pin 19 is position 1 and so on).
Debouncing
Debouncing of the switches is done by ignoring multiple presses in quick succession:
// debounce
if (millis () - lastPress [which] < DEBOUNCE_TIME)
return;
lastPress [which] = millis ();
Handling a queued press
Now in the main loop we just check if the counter has gone up, for each switch:
for (int i = 0; i < BUTTONS; i++)
if (counts [i] > 0)
{
handleSwitchPress (i);
counts [i]--;
}
If so, we call handleSwitchPress
which toggles the relay for the desired number of times.
Code for Uno
If you are using a Uno instead of a Mega2560 you don't have four external interrupts. The alternative version below uses pin change interrupts instead of external interrupts.
Pin change interrupts work on all pins of the Uno, however they are in batches of three: Pins A0 to A5, pins D0 to D7 and pins D8 to D13. In the code below I use pins 2, 3, 4 and 5 which are in the batch D0 to D7.
With a pin-change interrupt you only get notification of a change to the pin, so the code has to detect whether the pin changed from high to low or low to high.
// For Atmega328 (eg. Uno)
const int BUTTONS = 4;
const int FIRST_BUTTON = 2;
const int FIRST_RELAY = 8;
const int CLICKS = 5;
const unsigned long DEBOUNCE_TIME = 20; // ms
int retardo = 300;
int finBoton = 1000;
volatile bool oldState [BUTTONS];
volatile byte counts [BUTTONS];
unsigned long lastPress;
// handle pin change interrupt for D0 to D7 here
ISR (PCINT2_vect)
{
// debounce
if (millis () - lastPress < DEBOUNCE_TIME)
return;
lastPress = millis ();
// check each switch
for (int i = 0; i < BUTTONS; i++)
{
byte state = digitalRead (FIRST_BUTTON + i);
if (state != oldState [i])
{
oldState [i] = state; // detect state changes
if (state == LOW)
counts [i]++;
} // end of state change
} // end of for each button
} // end of PCINT2_vect
void setup()
{
// configure inputs / outputs
for (int i = 0; i < BUTTONS; i++)
{
pinMode (FIRST_BUTTON + i, INPUT_PULLUP);
oldState [i] = HIGH;
pinMode (FIRST_RELAY + i, OUTPUT);
}
// pin change interrupt (example for D9)
PCMSK2 |= bit (PCINT18) | bit (PCINT19) | bit (PCINT20) | bit (PCINT21); // want pins 2, 3, 4, 5
PCIFR |= bit (PCIF2); // clear any outstanding interrupts
PCICR |= bit (PCIE2); // enable pin change interrupts for D0 to D7
} // end of setup
// turn relay on for a particular switch
void handleSwitchPress (const int which)
{
for (int i = 0; i < CLICKS; i++)
{
digitalWrite(FIRST_RELAY + which, HIGH);
delay(retardo);
digitalWrite(FIRST_RELAY + which, LOW);
delay(retardo);
}
delay(finBoton);
} // end of handleSwitchPress
// main loop
void loop()
{
for (int i = 0; i < BUTTONS; i++)
if (counts [i] > 0)
{
handleSwitchPress (i);
counts [i]--;
}
} // end of loop