The buttons are tested and debounced individually, as you can see in the sample output that is shown following the program. (This program was tested on an Uno, with four independent buttons used in the test.Edit: Made corrections to handle 32-bit overflow, 2016年10月17日)
/* jw - 3 Nov 2015 - Program for button debounce demo
Ref: http://arduino.stackexchange.com/questions/17453/arduino-sending-keystrokes-via-push-buttons-proper-bouncing-and-manually-settin
*/
//--------------------------------------------------------
enum { sw0=8, sw1=9, sw2=10, sw3=11}; // Switchbutton lines
enum { nSwitches=4, bounceMillis=42}; // # of switches; debounce delay
struct ButtonStruct {
unsigned long int bounceEnd;bounceGo; // Debouncing-flag and end-time
// Switch number, press-action, release-action, and prev reading
byte swiNum, swiActP, swiActR, swiPrev;
};
struct ButtonStruct buttons[nSwitches] = {
{0, sw0, 'A','a', 0}, {0, sw1, 'B','b', 0}, {0, sw2, 'C','c', 0}, {0, sw3, 'D','d', 0}};
//--------------------------------------------------------
void setup() {
for (int i=0; i<nSwitches; ++i)
pinMode(buttons[i].swiNum, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("Starting");
}
//--------------------------------------------------------
byte readSwitch (byte swiNum) {
// Following inverts the pin reading (assumes pulldown = pressed)
return 1 - digitalRead(swiNum);
}
//--------------------------------------------------------
void doAction(byte swin, char code, char action) {
Serial.print("Switch ");
Serial.print(swin);
Serial.print(code);
Serial.print(' ');
Serial.print(action);
Serial.print(" at t=");
Serial.print(millis());
Serial.println();
}
//--------------------------------------------------------
void doButton(byte bn) {
struct ButtonStruct *b = buttons + bn;
if (b->bounceEnd>bounceGo) { // Was button changing?
// It was changing, see if debounce time is done.
if (millis() - b->bounceEnd>bounceGo <> millis()bounceMillis) {
b->bounceEnd>bounceGo = 0; // Debounce time is done, so clear flag
// See if the change was real, or a glitch
if (readSwitch(b->swiNum) == b->swiPrev) {
// Current reading is same as trigger reading, so do it
if (b->swiPrev) {
doAction(b->swiNum, 'P', b->swiActP);
} else {
doAction(b->swiNum, 'R', b->swiActR);
}
}
}
} else { // It wasn't changing; but see if it's changing now
if (b->swiPrev != readSwitch(b->swiNum)) {
b->swiPrev = readSwitch(b->swiNum);
b->bounceEnd>bounceGo = millis()+bounceMillis;; // Set the Debounce flag
}
}
}
//--------------------------------------------------------
long int seconds, prevSec=0;
void loop() {
for (int i=0; i<nSwitches; ++i)
doButton(i);
}
The buttons are tested and debounced individually, as you can see in the sample output that is shown following the program. (This program was tested on an Uno, with four independent buttons used in the test.)
/* jw - 3 Nov 2015 - Program for button debounce demo
Ref: http://arduino.stackexchange.com/questions/17453/arduino-sending-keystrokes-via-push-buttons-proper-bouncing-and-manually-settin
*/
//--------------------------------------------------------
enum { sw0=8, sw1=9, sw2=10, sw3=11}; // Switchbutton lines
enum { nSwitches=4, bounceMillis=42}; // # of switches; debounce delay
struct ButtonStruct {
unsigned long int bounceEnd; // Debouncing-flag and end-time
// Switch number, press-action, release-action, and prev reading
byte swiNum, swiActP, swiActR, swiPrev;
};
struct ButtonStruct buttons[nSwitches] = {
{0, sw0, 'A','a', 0}, {0, sw1, 'B','b', 0}, {0, sw2, 'C','c', 0}, {0, sw3, 'D','d', 0}};
//--------------------------------------------------------
void setup() {
for (int i=0; i<nSwitches; ++i)
pinMode(buttons[i].swiNum, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("Starting");
}
//--------------------------------------------------------
byte readSwitch (byte swiNum) {
// Following inverts the pin reading (assumes pulldown = pressed)
return 1 - digitalRead(swiNum);
}
//--------------------------------------------------------
void doAction(byte swin, char code, char action) {
Serial.print("Switch ");
Serial.print(swin);
Serial.print(code);
Serial.print(' ');
Serial.print(action);
Serial.print(" at t=");
Serial.print(millis());
Serial.println();
}
//--------------------------------------------------------
void doButton(byte bn) {
struct ButtonStruct *b = buttons + bn;
if (b->bounceEnd) { // Was button changing?
// It was changing, see if debounce time is done.
if (b->bounceEnd < millis()) {
b->bounceEnd = 0; // Debounce time is done, so clear flag
// See if the change was real, or a glitch
if (readSwitch(b->swiNum) == b->swiPrev) {
// Current reading is same as trigger reading, so do it
if (b->swiPrev) {
doAction(b->swiNum, 'P', b->swiActP);
} else {
doAction(b->swiNum, 'R', b->swiActR);
}
}
}
} else { // It wasn't changing; but see if it's changing now
if (b->swiPrev != readSwitch(b->swiNum)) {
b->swiPrev = readSwitch(b->swiNum);
b->bounceEnd = millis()+bounceMillis; // Set the Debounce flag
}
}
}
//--------------------------------------------------------
long int seconds, prevSec=0;
void loop() {
for (int i=0; i<nSwitches; ++i)
doButton(i);
}
The buttons are tested and debounced individually, as you can see in the sample output that is shown following the program. (This program was tested on an Uno, with four independent buttons used in the test.Edit: Made corrections to handle 32-bit overflow, 2016年10月17日)
/* jw - 3 Nov 2015 - Program for button debounce demo
Ref: http://arduino.stackexchange.com/questions/17453/arduino-sending-keystrokes-via-push-buttons-proper-bouncing-and-manually-settin
*/
//--------------------------------------------------------
enum { sw0=8, sw1=9, sw2=10, sw3=11}; // Switchbutton lines
enum { nSwitches=4, bounceMillis=42}; // # of switches; debounce delay
struct ButtonStruct {
unsigned long int bounceGo; // Debouncing-flag and end-time
// Switch number, press-action, release-action, and prev reading
byte swiNum, swiActP, swiActR, swiPrev;
};
struct ButtonStruct buttons[nSwitches] = {
{0, sw0, 'A','a', 0}, {0, sw1, 'B','b', 0}, {0, sw2, 'C','c', 0}, {0, sw3, 'D','d', 0}};
//--------------------------------------------------------
void setup() {
for (int i=0; i<nSwitches; ++i)
pinMode(buttons[i].swiNum, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("Starting");
}
//--------------------------------------------------------
byte readSwitch (byte swiNum) {
// Following inverts the pin reading (assumes pulldown = pressed)
return 1 - digitalRead(swiNum);
}
//--------------------------------------------------------
void doAction(byte swin, char code, char action) {
Serial.print("Switch ");
Serial.print(swin);
Serial.print(code);
Serial.print(' ');
Serial.print(action);
Serial.print(" at t=");
Serial.print(millis());
Serial.println();
}
//--------------------------------------------------------
void doButton(byte bn) {
struct ButtonStruct *b = buttons + bn;
if (b->bounceGo) { // Was button changing?
// It was changing, see if debounce time is done.
if (millis() - b->bounceGo > bounceMillis) {
b->bounceGo = 0; // Debounce time is done, so clear flag
// See if the change was real, or a glitch
if (readSwitch(b->swiNum) == b->swiPrev) {
// Current reading is same as trigger reading, so do it
if (b->swiPrev) {
doAction(b->swiNum, 'P', b->swiActP);
} else {
doAction(b->swiNum, 'R', b->swiActR);
}
}
}
} else { // It wasn't changing; but see if it's changing now
if (b->swiPrev != readSwitch(b->swiNum)) {
b->swiPrev = readSwitch(b->swiNum);
b->bounceGo = millis(); // Set the Debounce flag
}
}
}
//--------------------------------------------------------
long int seconds, prevSec=0;
void loop() {
for (int i=0; i<nSwitches; ++i)
doButton(i);
}
I'm not sure what you mean by "Is a matrix the way to go", so will ignore that question.
Shown below is a way of using an array of structs (one of C's ways of organizing a collection of items) to keep data for several buttons, such that it's straightforward to use one subroutine to process each button the same way, using a for-loop to call the routine for each button.
Each element of the array buttons
is a ButtonStruct
, and each ButtonStruct
contains five items: bounceEnd, swiNum, swiActP, swiActR, swiPrev, which respectively represent a debouncing-flag and end-time; a switch number [ie a pin number]; a code for action to take on a press; a code for action to take on a release; and previous state of button. (In many special cases, some of these items will be irrelevant and you can leave them out of the ButtonStruct
.) The form b->x
that is used in the doButton()
routine says to access element x
of the struct that b
points to.
At the start of each loop()
pass, doButton()
is called once for each button. It first tests if debouncing was underway for the button. If so, it sees if enough time has gone by to suppose button bounce is over. If so, it reads the button's state, and if different from previous state, does an action for whichever way the button changed. (If the button state is unchanged after a debounce delay, the program supposes there was a glitch.) If debouncing was not underway, the program checks if the button state is different from most recent pass. In that case, it sets up a debounce test for the button.
The buttons are tested and debounced individually, as you can see in the sample output that is shown following the program. (This program was tested on an Uno, with four independent buttons used in the test.)
/* jw - 3 Nov 2015 - Program for button debounce demo
Ref: http://arduino.stackexchange.com/questions/17453/arduino-sending-keystrokes-via-push-buttons-proper-bouncing-and-manually-settin
*/
//--------------------------------------------------------
enum { sw0=8, sw1=9, sw2=10, sw3=11}; // Switchbutton lines
enum { nSwitches=4, bounceMillis=42}; // # of switches; debounce delay
struct ButtonStruct {
unsigned long int bounceEnd; // Debouncing-flag and end-time
// Switch number, press-action, release-action, and prev reading
byte swiNum, swiActP, swiActR, swiPrev;
};
struct ButtonStruct buttons[nSwitches] = {
{0, sw0, 'A','a', 0}, {0, sw1, 'B','b', 0}, {0, sw2, 'C','c', 0}, {0, sw3, 'D','d', 0}};
//--------------------------------------------------------
void setup() {
for (int i=0; i<nSwitches; ++i)
pinMode(buttons[i].swiNum, INPUT_PULLUP);
Serial.begin(115200);
Serial.println("Starting");
}
//--------------------------------------------------------
byte readSwitch (byte swiNum) {
// Following inverts the pin reading (assumes pulldown = pressed)
return 1 - digitalRead(swiNum);
}
//--------------------------------------------------------
void doAction(byte swin, char code, char action) {
Serial.print("Switch ");
Serial.print(swin);
Serial.print(code);
Serial.print(' ');
Serial.print(action);
Serial.print(" at t=");
Serial.print(millis());
Serial.println();
}
//--------------------------------------------------------
void doButton(byte bn) {
struct ButtonStruct *b = buttons + bn;
if (b->bounceEnd) { // Was button changing?
// It was changing, see if debounce time is done.
if (b->bounceEnd < millis()) {
b->bounceEnd = 0; // Debounce time is done, so clear flag
// See if the change was real, or a glitch
if (readSwitch(b->swiNum) == b->swiPrev) {
// Current reading is same as trigger reading, so do it
if (b->swiPrev) {
doAction(b->swiNum, 'P', b->swiActP);
} else {
doAction(b->swiNum, 'R', b->swiActR);
}
}
}
} else { // It wasn't changing; but see if it's changing now
if (b->swiPrev != readSwitch(b->swiNum)) {
b->swiPrev = readSwitch(b->swiNum);
b->bounceEnd = millis()+bounceMillis; // Set the Debounce flag
}
}
}
//--------------------------------------------------------
long int seconds, prevSec=0;
void loop() {
for (int i=0; i<nSwitches; ++i)
doButton(i);
}
In the sample output below, a P line indicates a button press, detected at given millis()
time, and an R line indicates a button release. Observe, near the end, overlaps among separate button presses and releases.
Starting
Switch 8P A at t=2170
Switch 8R a at t=2322
Switch 9P B at t=2789
Switch 9R b at t=2969
Switch 10P C at t=3395
Switch 10R c at t=3562
Switch 11P D at t=4087
Switch 11R d at t=4260
Switch 11P D at t=6518
Switch 10P C at t=6961
Switch 8P A at t=7070
Switch 10R c at t=7112
Switch 11R d at t=7427
Switch 8R a at t=7598
Switch 10P C at t=8502
Switch 9P B at t=8642
Switch 10R c at t=8961
Switch 9R b at t=9054
Switch 9P B at t=9954
Switch 11P D at t=10073
Switch 8P A at t=10164
Switch 8R a at t=10215
Switch 9R b at t=10315
Switch 11R d at t=10354