See below. The only claim I make for this is that it works. I'm sure it can be improved. Example code is for 4 buttons but easily expandable to more.
Enjoy.
/* Simple button debounce for 4 buttons. Increments a count and sends the updated count to the serial monitor once per button press */
/* Tested on an Uno */
/* Connect simple push to make buttons between 0V and pin 2, 0V and pin 3, 0V and pin 4 and between 0V and pin 5 */
#define noOfButtons 4 //Exactly what it says; must be the same as the number of elements in buttonPins
#define bounceDelay 20 //Minimum delay before regarding a button as being pressed and debounced
#define minButtonPress 3 //Number of times the button has to be detected as pressed before the press is considered to be valid
const int buttonPins[] = {2, 3, 4, 5}; // Input pins to use, connect buttons between these pins and 0V
uint32_t previousMillis[noOfButtons]; // Timers to time out bounce duration for each button
uint8_t pressCount[noOfButtons]; // Counts the number of times the button is detected as pressed, when this count reaches minButtonPress button is regared as debounced
uint8_t testCount[noOfButtons]; //Test count, incremented once per button press
void setup() {
uint8_t i;
uint32_t baudrate = 115200;
Serial.begin(baudrate);
Serial.println("");
Serial.print("Serial port connected: ");
Serial.println(baudrate);
for (i = 0; i < noOfButtons; ++i) {
pinMode(buttonPins[i], INPUT_PULLUP);
Serial.print("Testcount ");
Serial.print(i);
Serial.print(" = ");
Serial.println(testCount[i]);
}
}
void loop() {
debounce();
delay(10); //Your other code goes here instead of this delay. DO NOT leave this delay here, it's ONLY for demonstration.
}
void debounce() {
uint8_t i;
uint32_t currentMillis = millis();
for (i = 0; i < noOfButtons; ++i) {
if (digitalRead(buttonPins[i])) { //Input is high, button not pressed or in the middle of bouncing and happens to be high
previousMillis[i] = currentMillis; //Set previousMillis to millis to reset timeout
pressCount[i] = 0; //Set the number of times the button has been detected as pressed to 0
} else {
if (currentMillis - previousMillis[i] > bounceDelay) {
previousMillis[i] = currentMillis; //Set previousMillis to millis to reset timeout
++pressCount[i];
if (pressCount[i] == minButtonPress) {
doStuff(i); //Button has been debounced. Call function to do whatever you want done.
}
}
}
}
}
// Function to do whatever you want done once the button has been debounced.
// In this example it increments a counter and send the count to the serial monitor.
// Put your own functions here to do whatever you like.
void doStuff(uint8_t buttonNumber) {
++testCount[buttonNumber];
Serial.print("Button ");
Serial.print(buttonNumber);
Serial.print(" testcount = ");
Serial.println (testCount[buttonNumber]);
}
fionab:
(I have actually tried really hard by cutting/pasting bits of code, but the syntax of the curly brackets and the bits of code in the example like;
if (reading != buttonState) {
buttonState = reading;
are difficult to understand for a beginner.
Someone thought of that and created a way for you to learn. Scroll down to "Parts of a Sketch" in this:
Many beginners seem to think that if they use a button, it must need to be debounced. But it's not always true, it is not needed in many situations. So before you go to all that trouble, are you sure you need to debounce the buttons in your project? Describe in more detail and we can tell you for sure, but the general rule is, if you press a button more than once, is anything supposed to change on the second press? If the answer is no, then debouncing is not required.
@PerryBebbington
That's great and very helpful. Thank you.
I need to do some homework on that and see what I can work out. It's a great starting point and much appreciated. Thanks.
@PaulRB
Thanks for being thorough. Yes, I'm confident I have a problem with contact bounce. The input is actually the contacts of 8 x 24v relays. You can't buy 24V relays without somewhat 'heavy duty' contacts.
There is false triggering - using a CRO, there is definitely contact bounce. As an electronics engineer of some years experience I could easily solve this with hardware using 'cross-connected' NAND/Schmitt Trigger Gates, but that seems dumb when someone somewhere must have already done this in software. I'm actually planning on using the "#include <Keyboard.h>" library to simply put out the keyboard numerals 1-8 when a relay operates. This looks on the face of it to be almost trivial, but I've searched high and low but can't find any sketches that do this. I probably can write my own in the fullness of time (I'm completely new to Arduino) but given all the fabulous robotic stuff I've seen I don't understand why it's hard to find a sketch for 8 debounced inputs, outputting keyboard text of say 1-8.
Fiona, nothing in your last post convinced me that debouncing is definitely required. Just because the relays contacts bounce does not necessarily mean they need debouncing! It depends what needs to be done with the information, as I tried to explain before. You didn't expand quite enough on that aspect in your reply.
An important question to ask is what type of Arduino are you planning to use? Not all types support the Keyboard library.
OK, so let's suppose when relay #5 contacts close, you want to send a "5" character to the pc. If the contacts bounce and you send 2 or 3 x "5", what would happen? Would this actually cause a problem or unwanted effect?
#include <mechButton.h> // include the mechanical button library.
// Create your buttons using your pin numbers.
mechButton button1(pin1);
mechButton button2(pin2);
mechButton button3(pin3);
mechButton button4(pin4);
mechButton button5(pin5);
mechButton button6(pin6);
mechButton button7(pin7);
mechButton button8(pin8);
// Nothing extra to add to setup().
void setup() {
bla bla bla
}
// Just check them while going through loop(). If they ground when pushed they will return false.
void loop() {
if (button1.trueFalse()==false) {
doSomething();
}
if (button2.trueFalse()==false) {
doSomethingElse();
}
.. and on and on..
}
If you want to try these, search in your IDE's library manager for LC_baseTools.
@PaulRB
Thank you for your follow up and continued interest. It is critical the contacts are debounced because I'm going to use the keyboard text output to operate some lighting software. The input to that is a 'toggle', e.g. you press "1" and (big theatre) lights come on. You press "1" again and the lights go off.
If there is bounce and we get two 'hits' e.g. the character is sent twice the lights will just flash and end up being off. This is a triple fail because the flash is disconcerting (they are big lights), then there is darkness, and then the next time a character is send to turn OFF the lights, they will turn ON (Aaah!) because the 'toggle logic' is out of step.
Please beleive me, the input contacts need debounceing.
The example sketch included with the IDE is fine, but it is only for one pin.
How do you do de-bouncing for say 8 pins ? Thank you.
@jimLee
Thank you. That is great food for thought. Thanks. I'll get into it and do some experiments today.
Cheers and thanks.
The input to that is a 'toggle', e.g. you press "1" and (big theatre) lights come on. You press "1" again and the lights go off.
That's all I needed to hear. Yes, you do need to debounce.
How do you do de-bouncing for say 8 pins ?
Just the same way as 1 pin. But use arrays to hold the pin numbers, last states etc. and iterate using a for-loop. An easy way to debounce is simply to read the buttons/relays just a few times (e.g. 5~10) per second, which should be plenty fast enough for your application.