You should also read the Using millis() for timing. A beginners guide tutorial that is anchored at the top of the forum.
this is not the safe way to do a compare (if you want this to be fool proof in the long run)
Is there a 2 second delay before the 2nd Hello prints? There is nothing in the code to prevent it from printing multiple times if buttonB remains high.
You are mixing signed ints and unsigned longs in that comparison too, that kind of thing is best avoided unless you can convince yourself it always does what you expect.
In addition to the comments on the comparison issues, I’m not sure if this is an attempt to debounce the buttons or not. I would suggest a software debounce or an RC for a hardware debounce in additions to pull-ups.
Sorry I couln't be at the forum for a while
Answer to #1: x is unused, Thank you to know about code tags.
answer to #2: i am using external pulldown resistors 10k.
answer to #3 and #5: I have learnt about not mixing long and int
answer to #4: There is an 2 second delay before the 2nd Hello prints
I want to use millis() instead of delay() because I not want the program hooked up during run.
Why can not millis() delay for two sec before and not after printing the text?
ToddL1962:
In addition to the comments on the comparison issues, I’m not sure if this is an attempt to debounce the buttons or not. I would suggest a software debounce or an RC for a hardware debounce in additions to pull-ups.
The debounce is done with delay(50) in both cases. It "only" wastes 800000 cycles that could be wasted on other code.
There are many approaches to button debouncing. Using delay() does not require as much thought as writing button task code and a non-blocking sketch to run it in. Using delay() does limit the code it is in, there's tradeoffs.
Here's one way of doing debounce using millis. This is only intended as a demonstration, you will need to adapt to your code.
/* 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) {
++testCount[i];
Serial.print("Button ");
Serial.print(i);
Serial.print(" testcount = ");
Serial.println (testCount[i]);
}
}
}
}
}
GoForSmoke:
The debounce is done with delay(50) in both cases. It "only" wastes 800000 cycles that could be wasted on other code.
There are many approaches to button debouncing. Using delay() does not require as much thought as writing button task code and a non-blocking sketch to run it in. Using delay() does limit the code it is in, there's tradeoffs.
It appears to me the 50ms delay after the button did not debounce it because there is not a line to read the pin again and see if it changed in the last 50ms. You could get a HIGH input from pressing or releasing the button if it bounces.
In any case, I feel the millis() approach to debounce is better because you can accurately determine if the input is stable for the prescribed debounce time since you always reset the timer every time the input bounces.
ToddL1962:
In any case, I feel the millis() approach to debounce is better because you can accurately determine if the input is stable for the prescribed debounce time since you always reset the timer every time the input bounces
if you are only interested in capturing the moment the button get pressed (transition from HIGH to LOW if you use INPUT_PULLUP) and add a delay() right after identifying that change, you can be pretty sure the press-bouncing will be finished.
if you do the same upon release, catching the transition from LOW to HIGH and add a delay() right after identifying that change, you can be pretty sure the release-bouncing will be also finished.
If the buttons are really pressed by humans, a 15ms delay (50 is way too long for most buttons) after detecting the state change will be quite invisible to the human interface which will feel reactive and if the code does not have anything better to do during those 15ms (human eye won't even catch a 15ms delay in screen update - retina persistence is 30/40ms), there is no harm in using delay() --> so that's the poor's man debounce approach and it works pretty well in many many cases and easier to code
I just did a quick test running that sketch using one of these which is a few years old: with delay(5) I was getting false counts very often, at 10 sometimes and at 15 never.
ToddL1962:
It appears to me the 50ms delay after the button did not debounce it because there is not a line to read the pin again and see if it changed in the last 50ms. You could get a HIGH input from pressing or releasing the button if it bounces.
In any case, I feel the millis() approach to debounce is better because you can accurately determine if the input is stable for the prescribed debounce time since you always reset the timer every time the input bounces.
It's a crappy debounce for sure and I have objected to it since 2012 if not late 2011 when I joined the forum.
My latest approach checks each button about twice a milli where earlier methods checked about 67 times per milli. I had to slow it down to fit a decent pin state history in one byte. 3.5 ms of no change, I'll call that stable.
I just did a quick test running that sketch using one of these which is a few years old: with delay(5) I was getting false counts very often, at 10 sometimes and at 15 never.
Better debounce routines start counting time when the pin changes and call the state stable after some > 2+ms without change.
One caveat: millis() skips 6 values every 250ms. The value of (millis() - start) will occasionally be off by 1. Use micros timing or add 1 milli when you're working with small intervals, micros() doesn't skip but the low 2 bits are always 0.
J-M-L:
if you are only interested in capturing the moment the button get pressed (transition from HIGH to LOW if you use INPUT_PULLUP) and add a delay() right after identifying that change, you can be pretty sure the press-bouncing will be finished.
if you do the same upon release, catching the transition from LOW to HIGH and add a delay() right after identifying that change, you can be pretty sure the release-bouncing will be also finished.
If the buttons are really pressed by humans, a 15ms delay (50 is way too long for most buttons) after detecting the state change will be quite invisible to the human interface which will feel reactive and if the code does not have anything better to do during those 15ms (human eye won't even catch a 15ms delay in screen update - retina persistence is 30/40ms), there is no harm in using delay() --> so that's the poor's man debounce approach and it works pretty well in many many cases and easier to code
I don't wish to belabor this but if your program has other delays, for example, and the button were pressed during one of those it may be that when you check for a transition later you could get a LOW to HIGH or a HIGH to LOW. You really have to pay attention to the overall structure of the program with this method vs. having a function that always returns the stable state no matter what is going on. That's all I am saying. Indeed, if you implement your debounce using a timer interrupt then you can program your main loop any way you like and you are guaranteed the stable state of the input. I've been doing this stuff for over 30 years and have seen pretty much everything...
GoForSmoke:
Better debounce routines start counting time when the pin changes and call the state stable after some > 2+ms without change.
One caveat: millis() skips 6 values every 250ms. The value of (millis() - start) will occasionally be off by 1. Use micros timing or add 1 milli when you're working with small intervals, micros() doesn't skip but the low 2 bits are always 0.
I agree. And depending on the electrical environment and shielding of the signal a judicious combination of hardware filtering and debounce may be required. However, I have found that SW debounce suffices for most of what I do. I try to shield long wires especially for applications where the input is normally open, which I try to avoid.
ToddL1962:
I don't wish to belabor this but if your program has other delays, for example, and the button were pressed during one of those it may be that when you check for a transition later you could get a LOW to HIGH or a HIGH to LOW. You really have to pay attention to the overall structure of the program with this method vs. having a function that always returns the stable state no matter what is going on. That's all I am saying. Indeed, if you implement your debounce using a timer interrupt then you can program your main loop any way you like and you are guaranteed the stable state of the input. I've been doing this stuff for over 30 years and have seen pretty much everything...
I guess that If you have long delays() and expect a button to work well, then you are toast anyway
I'm not saying you are wrong, this is the best approach, I agree. It requires a bit more work and coding skills.
What I was saying is that for most simple programs we see here, the delay() approach works well and you won't catch a LOW to HIGH if you are not listening for it (ie you have a small state machine that know what's the state and the transition you expect).
I had posted in the past the following state machine as a sample code to handle a button without delays