Hello, I am using a pushbutton trigger. I would like to know how to tell the arduino to ignore the input unless it persists for more than a half second. ( if I quickly push and release, I want nothing to happen, but If I hold for at least 1/2 second, I want it to trigger) I keep getting some noise that sets it of randomly. My code and setup basically looks like this with relays instead of led outputs. http://arduino.cc/en/tutorial/button
#define relay1 = 11
#define relay2 = 12
#define relay3 = 7
const int trigger = 9;
int triggerState = 0;
void setup() {
pinMode(trigger, INPUT);
}
void loop() {
triggerState = digitalRead(trigger);
if (triggerState == HIGH) {
digitalWrite(relay1, HIGH); // relay1 is triggered
delay(1000);
} //End of if()
else {
digitalWrite(relay3, LOW);
digitalWrite(relay2, LOW);
digitalWrite(relay1, LOW);
}
} //End of loop()
The noise is many electrical contacts happening very close together as the switch closes.
You will likely have to debounce the switch you are using.
Something like this can work:
if (digitalRead(trigger) == HIGH) {
delay (500);
if (digitalRead(trigger) == HIGH) {
digitalWrite(relay1, HIGH); // relay1 is triggered
delay(1000);
}
In English it can be translated to: "the button is pressed? if yes wait half a second; after that the button still pressed? if yes it's realy a button pressed, so do something (in this case turn the relay ON and wait 1 second).
The debounce is definitely an issue with switches/buttons that bounce, which is most mechanical switch/button especially the cheap ones.
Example: my quick and dirty 'button' is to set up a pin as INPUT_PULLUP and stick a jumper in the hole that to 'press the button' I ground the other end of the jumper on the grounded USB jack housing. If I don't debounce that, the button will read a dozen to two on/offs.
I don't use a library though. I just check the pin until the state reads the same for 5 ms and then set my buttonState variable to that what it stayed at rather than what it is at some instant. My buttonState is the stable state only.
What the OP wants is a super-debounced button. Instead of 5 ms, 500 or more ms.
Thanks guys! I like the idea of checking then waiting 500ms to check again before proceeding. Works for me!
if (digitalRead(trigger) == HIGH) {
delay (500);
if (digitalRead(trigger) == HIGH) {
digitalWrite(relay1, HIGH); // relay1 is triggered
delay(1000);
}
Sorry but this has major possibility to go wrong.
The delay() means do nothing. It detects no changes. It trusts a blind assumption, really.
To escape the trap, learn the Blink Without Delay example sketch in your IDE in File->Examples->02.Digital or for a very full, easier explanation go here where the lesson becomes "How to do multiple things at once ... like cook bacon and eggs":
When I debounce, I can blink a led and read serial data, effectively at the same time as explained in that blog.
tyterh:
Thanks guys! I like the idea of checking then waiting 500ms to check again before proceeding. Works for me!
You really want to check for no change the whole time rather than assume there was none.
I agree with GoForSmoke. It can be done in much better way. But for beginners I believe it's the easiest way to do it.
After you are done, you can check the lesson that it's very well explained and improve your program.
Easier yet, use a library to manage the button. There are several out there. Here's one that I wrote. The code might be something like this:
//Toggle the built-in LED when a button is pressed for 1/2 second.
#include <Button.h> //http://github.com/JChristensen/Button
const uint8_t BUTTON_PIN = 2; //Connect a tactile button switch (or something similar)
//from Arduino pin 2 to ground.
const bool PULLUP = true; //To keep things simple, we use the Arduino's internal pullup resistor.
const bool INVERT = true; //Since the pullup resistor will keep the pin high unless the
//switch is closed, this is negative logic, i.e. a high state
//means the button is NOT pressed. (Assuming a normally open switch.)
const unsigned long DEBOUNCE_MS = 25; //A debounce time of 25 milliseconds usually works well for tactile button switches.
const unsigned long LONG_PRESS = 500; //Define a long press to be 500 milliseconds.
Button myBtn(BUTTON_PIN, PULLUP, INVERT, DEBOUNCE_MS); //Declare the button
void setup(void)
{
pinMode(LED_BUILTIN, OUTPUT);
}
void loop(void)
{
static bool ledState;
myBtn.read();
if ( myBtn.pressedFor(LONG_PRESS) ) {
digitalWrite(LED_BUILTIN, ledState = !ledState);
while ( myBtn.isPressed() ) myBtn.read(); //wait for button to be released
}
}
Mostly I wish that especially new people did not use libraries to do such simple tasks.
The reason is that they don't learn very basic lessons about code and hardware, but to rely on black boxes.
For complicated and big, sure, save it for later if/when you get that advanced.
GoForSmoke:
Mostly I wish that especially new people did not use libraries to do such simple tasks.
The reason is that they don't learn very basic lessons about code and hardware, but to rely on black boxes.
For complicated and big, sure, save it for later if/when you get that advanced.
On the one hand, I can agree with that, on the other I think that while a button seems like simplicity itself on the surface, dealing with it can be quite a challenge for a new person. The first couple times I used buttons in microcontroller projects, I was amazed at the hassle they created; mind you that I was well aware of switch bounce and what to do about it. Maybe it's just second nature to everyone else and I'm the exception. So I wrote a library to deal with the details, and also to clean up the main code. I don't like my code obscured by any more low-level details than necessary, I want to focus on the main project, blinking LEDs or whatever it might be.
I'm afraid that beginners will be discouraged getting off in the weeds with the details of handling buttons, and frustrated that they can't make progress on the main part of their project because of it. Buttons may not be "complicated and big" in the overall scheme of things, but everything is relative. Experienced folk tend to minimize the difficulty and effort required to solve problems that they solved long ago and are now ingrained to the point that they don't even need to think about them.
The beginner can and should dig into the black boxes at some point, and/or have a go at solving the problem themselves. These are important ways of learning and cannot be minimized. But they can be overwhelmed too and libraries are a way to help prevent that.
Looks to me like this is basic button reading with a long debounce time.
I read buttons this way mostly. It seems to work for most situations.
const byte BUTTON_PIN = 2; // for a switch on pin 2
const unsigned long DEBOUNCE_TIME = 20;
const long BAUD_RATE = 115200;
unsigned long debounceTimer = 0;
int lastButtonState = HIGH;
void setup()
{
pinMode(BUTTON_PIN, INPUT_PULLUP);
lastButtonState = digitalRead(BUTTON_PIN);
Serial.begin(BAUD_RATE);
}
void loop()
{
unsigned long currentMillis = millis(); // get the millis for the loop start
int buttonState = digitalRead(BUTTON_PIN); // read the switch
if (lastButtonState != buttonState) // check for any state change
{
lastButtonState = buttonState; // save new state
debounceTimer = currentMillis; // start the timer
}
if (debounceTimer > 0 && currentMillis - debounceTimer >= DEBOUNCE_TIME) // see if we are debouncing and whether we are done
{
debounceTimer = 0; // reset the timer
if (buttonState == LOW)
{
Serial.println(F("Button has been held"));
}
}
}
All you need to do with that code is change the value of DEBOUNCE_TIME to 500. The beauty of this is that the button must be actually held for the length of time as any state change will restart the timer. It also has to be released before it can be used again. Note that I set the internal pullups so the button state is LOW when pressed.
- black boxes are good for beginners
- they need to be opened, examined and hacked to bits as the beginner learns...hell thats what this hobby is all about isnt it?
- I have recently walked this same route, heres what I learned:
a. all switches even those of the same batch bounce differently. if you want to avoid the "mostly working, most of the time" you must tailor/tweak your debounce method FOR THAT SPECIFIC SWITCH. There is no one-size-fits-all solution. Anyone who thinks there is should hook up an encoder and then spin it hard. Promise me you wont design any life support systems based on a single fixed value!
b. there are holy wars on the hardware vs software debounce issue. generally my view is "whatever works" but that is based upon testing with an infinite number of monkeys randomly stabbing, stroking, smashing and tickling the button as the bounce profile is likely to be very different in each case, and sometimes dependent upon the RATE or order of stabbing, stroking etc. Teach your monkeys morse code and test, test test then test again. Then get someone else to repeat it.
c. (flame alert!) polling in a loop,is evil. OK, its fine for beginners and how I cut my teeth too...but once you have got some skill under your belt, go for interrupt.driven input. it will be easier soon as im writing a pinchange interrupt library that will take an input from any pin, and produce a clean debounced output on pretty much any avr device including tinies. dual encoder inputs dont need to be on adjacent pins...BUT...
d. hardware debouncing is IMHO the better option with interrupt code, especially if other interrupts are happening. its all well and good smoothing out 20 sub.millisecond spikes of th3 back end of encoder pulse, but thats 20 times into your ISR for software debouncing during which, loads of other interrupts (including your life support machine critical alert line) that get delayed or missed completely. Hence all my encoders are RC filtered through a schmitt trigger befor I let them near an interrupt line. THEN I software debounce them too, using the gray code state table method. Thus far, my monkeys have to really fight hard to get any spikes into my ISR, and so far the SW debounce has only ever produced one event per detent click on the encoder...there are still spiky pulses that get "missed" if a gorilla spins it 360...whichnreinforces my "no size fits all" argument, and my defence is that if you truly spin an encoder 360, do you really know how many clicks it SHOULD have made? The net result of my dual technique is that if I can feel/hear/count the number of clicks, thats how many times X happens, but it took me a long time to get to this point.
Finally, there is a LOT of good stuff out there on debouncing of all types of switches and encoders. google it and read it all. that how I got ot be able to write all the nonsense I just did...oh and some solder.burnt fingers and fried components too.
// All you need to do this example is an Arduino and a jumper in pin 2.
// Push and let go the button once, led blinks. Again, led turns off.
// Button is debounced and wired directly to ground or, the button can
// be a jumper from pin 2 grounded on USB connector. Tested with jumper.
// By GoForSmoke for free public use. Using Arduino 1.0.5-r2
/*
This sketch uses millis() timing but only the low bytes. Unsigned math
lets this work just as well as with all 32 bits.
This sketch has 3 separated code blocks.
--- 1 for the button that changes buttonState only after a debounced change.
--- 1 that processes changes in buttonState to control led blink.
--- 1 that blinks the led when it's supposed to.
Each code block could be replaced by another with minimal change to the others.
More blocks can be added, they don't have to deal with the led but they could.
If you want to merge sketches then here is one strategy to do it.
*/
// Look Ma, no extra libraries!
const byte ledPin = 13; // this is the onboard led pin
const byte buttonPin = 2;
byte ledPinState = 0;
byte blinkLed = 0; // led stays off when 0, blinks when 1
const word ledBlinkMs = 1000U; // blink interval
word ledBlinkNowMs = 0U; // low 16 bits of millis()
word ledBlinkStartMs = 0U; // 16 bit blink (on or off) time ms
// button variables
byte buttonRead; // wired for pullup -- if down then LOW, if up then HIGH
byte lastButtonRead = HIGH; // so debounce knows previous read
byte checkDebounce = 0; // only checks decounce after every button pin change
byte lastButtonState = 0; // last stable button state
byte buttonState = 0; // stable button state
// 0 = button is up after debounce
// 1 = button is down after debounce
// button debounce timing variables
const byte debounceMs = 10; // debounced when reads for debounceMs ms are the same
byte debounceMillsLowByte = 0; // only need to count to 10, don't need 32 bits
byte msNow = 0; // don't worry, unsigned rollover makes it work
byte processState = 0; // the button gets pushed and released twice
// 0 = 1st press has not happened, led blink is OFF, looking for press
// 1 = 1st press is down, led blink is ON, looking for release
// 2 = 1st push relesased, led blink stays ON, looking for 2nd press
// 3 = 2nd press is down, led blink is OFF, looking for release
// there is no state 4, 2nd push release changes state to 0
void setup()
{
Serial.begin( 57600 );
pinMode( ledPin, OUTPUT ); // default is LOW
pinMode( buttonPin, INPUT_PULLUP ); // my button connects to ground, not 5V
// however that means that the pin is LOW when the button is pressed.
}
void loop() // make sure that loop() runs fast and stays in the "now".
{
// BUTTON CODE BLOCK, it handles debouncing.
// the task is to set the variable buttonState when a Stable Button State is reached.
// other sensor code could change the same variable if desired
// read the pin which may be changing fast and often as the jumper contacts the housing
buttonRead = digitalRead( buttonPin ); // momentary state
// msNow gets the low byte of millis() to time the very short debounce time
msNow = (byte) ( millis() & 0xFF ); // don't worry, unsigned rollover makes it work
if ( buttonRead != lastButtonRead )
{
debounceMillsLowByte = msNow;
checkDebounce = 1;
}
else if ( checkDebounce )
{
if ( msNow - debounceMillsLowByte >= debounceMs ) // stable button state achieved
{
buttonState = !buttonRead; // mission accomplished, button is stable
// note that buttonState is opposite buttonRead
checkDebounce = 0; // stop debounce checking until pin change
}
}
lastButtonRead = buttonRead;
//
// End of the BUTTON CODE BLOCK
//==================================================================================
// LED CONTROL CODE BLOCK that uses buttonState and processState
if ( lastButtonState != buttonState )
{
lastButtonState = buttonState;
// debug type prints -- also testing some loading, does it alter the blink much?
Serial.println( F( "============================================================" ));
Serial.print( F( "processState " ));
Serial.print( processState );
Serial.print( F( " buttonState " ));
Serial.println( buttonState );
Serial.println( F( "============================================================" ));
switch ( processState )
{
case 0: // 0 = 1st press has not happened, led is OFF, looking for press
if ( buttonState == 1 ) // button is pressed
{
processState = 1;
blinkLed = 1;
ledPinState = 0;
ledBlinkStartMs = (word) ( millis() & 0xFFFF )- ledBlinkMs;
}
break; // note that until the 1st press, this case runs over and over
case 1: // 1 = 1st press is down, led is ON, looking for release
if ( buttonState == 0 ) // button is released
{
processState = 2;
}
break; // note that until the 1st release, this case runs over and over
case 2: // 2 = 1st push relesased, led stays ON, looking for 2nd press
if ( buttonState == 1 ) // button is pressed
{
processState = 3;
blinkLed = 0;
}
break; // note that until the 2nd press, this case runs over and over
case 3: // 3 = 2nd press is down, led is OFF, looking for release
if ( buttonState == 0 ) // button is released
{
processState = 0; // back to the start
}
break; // note that until the 2nd release, this case runs over and over
}
}
// End of the LED CONTROL CODE
//==================================================================================
// LED BLINK CODE BLOCK
if ( blinkLed )
{
ledBlinkNowMs = (word) ( millis() & 0xFFFF );
if ( ledBlinkNowMs - ledBlinkStartMs >= ledBlinkMs )
{
ledPinState = !ledPinState;
digitalWrite(ledPin, ledPinState );
ledBlinkStartMs = ledBlinkNowMs;
}
}
else
{
ledPinState = LOW;
digitalWrite(ledPin, LOW );
}
// End of the LED BLINK CODE
//==================================================================================
// want to add serial input?
}
is there any way for ordinary users ti give karma? goforsmoke sure as hell deserves a ton for his coding effort.
excellent job
I just cleaned up a thing I did for someone quite a while ago, and then added loads of comments.
It shows things often asked about and things I keep trying to tell about, like running a status light.
When I find the right serial code in my sketch collection, I'll add the ability to set the blink rate through serial.