Arduino Button Bouncing - c++

What is my Issue with the button, it dont work correctly and I am wondering why. I dont get it. The Button is connected over the 5V Then a 10k resistor and connected with a wire to the ground. I think the isr is correctly implemented. And the function is also correct. But I do not really get whats the issue with the Button is. I tried a capacitor but that didnt also work well... I connected it directly before the the button.
#include <LiquidCrystal.h>
LiquidCrystal lcd(5, 6, 9, 10, 11, 12);
unsigned long volatile startTime = 0;
unsigned long volatile endTime = 0;
unsigned long volatile sec;
volatile boolean buttonState;
const int button = 2;
long ms;
long timeT;
long z;
void setup() {
Serial.begin(9600);
// put your setup code here, to run once:
pinMode(button, INPUT_PULLUP);
lcd.setCursor(0, 0);
lcd.print("Stopwatch");
attachInterrupt(digitalPinToInterrupt(button), isr, FALLING);
}
void loop() {
if (buttonState == LOW) {
startTime = millis();
}
while (buttonState == HIGH) {
z = (millis() - startTime);
sec = (z / 1000);
ms = z % 1000;
lcd.setCursor(0, 1);
lcd.print(sec);
lcd.print(".");
lcd.print(ms);
lcd.setCursor(9, 1);
lcd.print("Secs");
}
}
//Interrupt Service Routines
void isr() {
buttonState = !buttonState;
}

Buttons are quirky things. It can happen that they send multiple signals (rather, that the contact isn't immediately stable). A condenser might help, but that too can output a wavy signal and trigger multiple "events" and, anyway, it introduces a delay.
So, delay for delay, you could do something like this which should be more controllable:
if (buttonState !== previousState) {
startTime = millis();
previousState = buttonState;
triggered = 0;
} else {
if (0 == triggered) {
if ((millis() - startTime) > threshold) {
triggered = 1;
// Okay, buttonState is now reliably LOW or HIGH
...
}
} else {
// Continuous event (pressed or not-pressed)
}
}
In practice, this should only react when the button has been uninterruptedly pressed or released for "threshold" millis. Assuming BTN is the actual signal from the button without any other attending hardware,
1 2 3 4 5 6
BTN: LLLLLLLLLLLLLLHLHHLHHHLHHHHHHHHHHHHHHHHHHHHHHHHHHHLHHHLLHHLLLLLLLLL
FLT: ___________________________-----------------------------------_____
Time --------------------------------------------------------------->
1 button is physically pressed
2 button is now truly pressed
3 stable button press is detected
4 button begins to be released
5 button is now fully released
6 stable button release is detected

Related

ESP32 Simple button hold for 3 seconds example. Output doesn't seem to make sense?

Hoping someone can see what I'm missing as it's gotta be right there staring at me in the face..
I've got this code (below) set up on an ESP32 to spawn a thread that simply monitors the state of a pin connected to a switch. Essentially this code is supposed to wait for the button to be held for 3 seconds and then do something important. The actual input seems to read fine, but for some reason once I've pressed the button, the button state is stuck for like 15 seconds after un-pressing the switch.
For example,
Press the switch, the actualBtnState reads 1, buttonState reads 1 (after 50us),and btnPressTime increments as expected.
Release switch, actualBtnState reads 0, btnState reads 1, and btnPressTime stops incrementing.
After 50us, expecting to see btnState read 0 and then trigger the else or elseif blocks (depending on how long the button was held). Actual results continue to read btnState = 1 and btnPressTime = [whatever the last held time was] for a solid 15 seconds or more. actuyalBtnState reads correctly at 0 this entire time and for some reason lastDebounceTime keeps incrementing?
I should note that this is part of a much larger project, hence the threading. I also can't seem to print anything within the resetBtnCB function as I immediately get a "guru mediation error kernel panic whatever-the-error-is" error and the esp reboots.
Code:
#include <Arduino.h>
#define BUTTON_PIN 27
// Variables will change:
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
unsigned long buttonPressTime = 0; //Amount of time the button has been held down
unsigned long actualBtnState = 0; //The actual reading from the pin without noise filtering
void resetBtnCB(void *pvParameters)
{
pinMode(BUTTON_PIN, INPUT);
while (true)
{
// read the state of the switch into a local variable:
int reading = digitalRead(BUTTON_PIN);
actualBtnState = reading;
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState)
{
// reset the debouncing timer
lastDebounceTime = millis();
}
unsigned long timeSinceDebounce = millis() - lastDebounceTime;
if (timeSinceDebounce > debounceDelay)
{
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
buttonState = reading;
if (buttonState == HIGH)
{
buttonPressTime += timeSinceDebounce;
}
else if (buttonPressTime > 300)
{
buttonPressTime = 0;
// SUCCESS! Do something important here as we've held the button for x seconds
}
else
{
buttonPressTime = 0;
}
}
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
vTaskDelay(10);
}
}
void setup()
{
Serial.begin(115200);
xTaskCreate(resetBtnCB, "reset_button", 1024, NULL, 10, NULL);
}
void loop()
{
char debug[512];
sprintf(debug, "button state %u, lastD %u, buttonPressTime %u, actualBtnState %u, lastBtnState %u", buttonState, lastDebounceTime, buttonPressTime, actualBtnState, lastButtonState);
Serial.println(debug);
delay(50);
yield();
}

Setting delay for capacitive touch sensor to prevent "double press"

I am building a number numpad using 3 different capacitive touch sensor. So my function will be to label each the 3 touch sensors with a different number to create a password system.
However i realised that whenever i try to press the button to key in the number, for example the button tagged with number "3", multple values of 3 came out even though i only pressed once. Is there any function on arduino that i can use so that it only generate 1 results with 1 press instead of multiple results in a press.
Is there anyway to change my code such that i can create some sort of debounce for each button so that when i press the button once only 1 result will be shown.
Would appreciate an edit on my code, thanks!
#include <LiquidCrystal.h>
#include <CapacitiveSensor.h>
CapacitiveSensor cs_2_3= CapacitiveSensor(2,3);
CapacitiveSensor cs_2_4= CapacitiveSensor(2,4);
CapacitiveSensor cs_2_5= CapacitiveSensor(2,5);
int pos=0;
LiquidCrystal lcd(A0,A1,A2,A3,A4,A5);
char pass[]= "321";
int currentposition=0;
char code=0;
void setup() {
cs_2_3.set_CS_AutocaL_Millis(0xFFFFFFFF);
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
Serial.begin(9600);
lcd.begin(16,2);
}
void loop() {
long total1= cs_2_3.capacitiveSensor(100);
long total2=cs_2_4.capacitiveSensor(100);
long total3= cs_2_5. capacitiveSensor(100);
if(total1>=1000)
{
code= '1';
}
if(total2>=1000)
{
code= '2';
}
if(total3>=1000)
{
code='3';
}
delay(100);
if(currentposition==0)
{
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
}
int lu ;
if(code!=0)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("PASSWORD:");
lcd.setCursor(7,1);
lcd.print(" ");
lcd.setCursor(7,1);
for(lu=0;lu<=currentposition;++lu)
{
lcd.print(code);
delay(25);
}
if (code==pass[currentposition])
{
++currentposition;
if(currentposition==3)
{
delay(900);
lcd.setCursor(0,0);
lcd.println(" ");
lcd.setCursor(1,0);
lcd.print("Correct Password");
lcd.setCursor(4,1);
lcd.println("HELLO!!");
lcd.setCursor(15,1);
lcd.println(" ");
lcd.setCursor(16,1);
lcd.println(" ");
lcd.setCursor(14,1);
lcd.println(" ");
lcd.setCursor(13,1);
lcd.println(" ");
delay (5000);
lcd.clear();
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
}
}
else
{
delay(500);
lcd.clear();
lcd.setCursor(1,0);
lcd.print("PASSWORD");
lcd.setCursor(6,0);
lcd.print("INCORRECT");
lcd.setCursor(15,1);
lcd.println(" ");
lcd.setCursor(4,1);
lcd.println("GET AWAY!!!");
code=0;
lcd.setCursor(13,1);
lcd.println(" ");
delay(3000);
currentposition=0;
lcd.clear();
lcd.setCursor(0,0);
lcd.println("Enter Password: ");
}
}
}
Just debounce it like any other button. Only accept signal changes longer then a certain time.
From https://www.arduino.cc/en/tutorial/debounce
/*
Debounce
Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
minimum delay between toggles to debounce the circuit (i.e. to ignore noise).
The circuit:
- LED attached from pin 13 to ground
- pushbutton attached from pin 2 to +5V
- 10 kilohm resistor attached from pin 2 to ground
- Note: On most Arduino boards, there is already an LED on the board connected
to pin 13, so you don't need any extra components for this example.
created 21 Nov 2006
by David A. Mellis
modified 30 Aug 2011
by Limor Fried
modified 28 Dec 2012
by Mike Walters
modified 30 Aug 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Debounce
*/
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
// set initial LED state
digitalWrite(ledPin, ledState);
}
void loop() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// only toggle the LED if the new button state is HIGH
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
// set the LED:
digitalWrite(ledPin, ledState);
// save the reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
}
You could use INPUT_PULLUP like this:
void setup() {
pinMode(pin, INPUT_PULLUP)
}
But since your using i library this may be an issue.
You could simply use the delay() function, as stated here: https://www.brainy-bits.com/arduino-switch-debounce/
This might be the fastest and simplest way to do it.
Debouncing the button will help - Adafruit got something especially on this topic: https://learn.adafruit.com/make-it-switch/debouncing
But for a quick and dirty solution delay() will do.

Detecting continuous motion using millis with a PIR sensor

I am trying to detect when continuous motion has been triggered from a PIR sensor for more than 8 seconds. Here is what I have. When sensor is LOW 'no motion...' is displayed, then short motion fires the first '< 8 sec' IF statement. When sensor returns to LOW - no motion is displayed as it should but then when motion is detected a second time, the code seems to freeze and nothing happens.
unsigned long startMillis;
boolean timingFlag = false;
const int buttonPin = 2;
int buttonState = 0;
void setup() {
pinMode(buttonPin, INPUT);
Serial.begin(19200);
delay(500);
}
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH && millis() - startMillis <= 8000UL)
{
Serial.println("Motion Detected but less than 8");
delay(1000);
//the PIR timed out with in the three seconds so cancel timing
timingFlag = false; //disable timing
}
if (buttonState == LOW)
{
Serial.println("No Motion...");
delay(1000);
timingFlag = true; //enable timing
}
//when nine seconds have gone by with consistant detection do something
if (timingFlag == false && millis() - startMillis >= 9000UL)
{
//There has now been nine seconds of constant PIR detection
Serial.println("Motion Detected and greater than 9 sec");
delay(1000);
//Do Something
}
}
There is one very obvious problem with your current code, as Scheff already mentioned in the comments: You never actually set your startMillis to anything, so they are probably (but not necessarily) always 0.
This means, that the statement if (buttonState == HIGH && millis() - startMillis <= 8000UL) will always be false after 8000 ms (until millis() flows over, after around 50 days* ), so timingFlag will never be reset to false after that. This ultimately leads to your "freezing" situation.
I tried to find a good place to set the startMillis in your code, but I honestly find it a little confusing, so I allowed myself to rewrite your logic, hope you don't mind. (Please note that I also changed the variable names from button to detector, since it seemed more fitting to me):
(This version triggers at the transitions from HIGH to LOW)
// define the threshold, after which an action shall be triggered
const int detectionThreshold = 8000;
const int detectorPin = 2;
unsigned long startTime = 0;
int lastDetectorState = LOW;
void setup() {
pinMode(detectorPin, INPUT);
Serial.begin(19200);
delay(500);
}
void triggerDetectionAction(){
// do whatever needs to be done after 8 seconds of motion in here
}
void loop() {
int currentDetectorState = digitalRead(detectorPin);
// if detector is low, no motion is detected
if( currentDetectorState == LOW ){
// when the detector is LOW, we want to check if the last state was HIGH
// because then we just arrived at the transition from HIGH to LOW =>
// "something was detected" to "there is no longer something detected"
if( lastDetectorState == HIGH ){
// then, we can get the total duration, the detection lasted
unsigned long detectionDuration = millis() - startTime;
// and print it for easier debugging
Serial.print("Detection ended after ");
Serial.print(detectionDuration);
Serial.println(" milliseconds");
// finally, we check if the durations was more than
// or equal to our threshold
if( detectionDuration >= detectionThreshold ){
// and trigger stuff if necessary
triggerDetectionAction();
}
}
// if last detector state was LOW too,
// we don't want to do anything
}else{
// here we wan't to check for the transition of LOW to HIGH,
// so we check our last detector state
if( lastDetectorState == LOW ){
// if we caught the transition,
// set the start time to the current millis
startTime = millis();
// we could also set an indicator LED
// or Serial.print something here
Serial.println("Detection started");
}
// otherwise, we don't wan't to do anything
}
// finally, we save our current state into the last state,
// so we have it available in the next loop
lastDetectorState = currentDetectorState;
// do your other loop stuff here
}
Please note that I couldn't test the code at the time writing, so there may be (syntax) errors
*More about millis and overflow here: https://www.arduino.cc/reference/en/language/functions/time/millis/
Update: This version will trigger immediately when the threshold is reached. It also includes an example how to trigger an action once and every loop after the threshold was reached.
// define the threshold, after which an action shall be triggered
const int detectionThreshold = 8000;
const int detectorPin = 2;
unsigned long startTime = 0;
int lastDetectorState = LOW;
bool actionTriggered = false;
void setup() {
pinMode(detectorPin, INPUT);
Serial.begin(19200);
delay(500);
}
void triggerOnce(){
// this will be called once, when the threshold is reached
}
void triggerEveryLoop(){
// this will be called every loop, after the threshold was reached
// for as long as the detector stays high
}
void loop() {
int currentDetectorState = digitalRead(detectorPin);
if( currentDetectorState == LOW ){
if( lastDetectorState == HIGH ){
// since we want to trigger immediately when the threshold is reached,
// we actually don't need this transition any longer.
// We can still keep it for debugging reasons thought.
// If you don't need this, you can simply remove the entire block
unsigned long detectionDuration = millis() - startTime;
Serial.print("Detection ended after ");
Serial.print(detectionDuration);
Serial.println(" milliseconds");
}
}else{
// Check for LOW => HIGH transition change
if( lastDetectorState == LOW ){
// if we caught the transition,
// set the start time to the current millis
startTime = millis();
// and reset the flag
actionTriggered = false;
// we could also set an indicator LED
// or Serial.print something here
Serial.println("Detection started");
}else{
// otherwise we want to check the duration
unsigned long detectionDuration = millis() - startTime;
// and trigger immediatley when the threshold is reached
if( detectionDuration >= detectionThreshold ){
// as long as it wasn't already triggered before
if( !actionTriggered ){
Serial.println("Threshold reached, triggering");
// now we also need to set a flag, so we know we already triggerd this action once
actionTriggered = true;
triggerOnce();
}
// we can also do something every loop
// this can be handy for e.g. blinking a light or playing a sound or something
triggerEveryLoop();
}
}
}
// finally, we save our current state into the last state,
// so we have it available in the next loop
lastDetectorState = currentDetectorState;
// do your other loop stuff here
}

Arduino How can i store the last IR code to check if it needs repeating?

I'm just learning Arduino and i've got a DC Motor & IR Receiver connected. It's working fine if i press the button once but i can't figure out how to keep the motor spinning if i hold the button down as the REPEAT command is the same numbers.
I figured i would store the last code sent and check if the repeat command and last code match but it doesn't seem to be working and can't figure out why.
#include <IRremote.h>
int IRpin = 11; // pin for the IR sensor
IRrecv irrecv(IRpin);
decode_results results;
int lastCode;
void setup() {
// put your setup code here, to run once:
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(13, OUTPUT);
Serial.begin(9600);
irrecv.enableIRIn(); // Enable IR Receiver.
}
void loop() {
// put your main code here, to run repeatedly:
if
(irrecv.decode(&results)) {
Serial.println(results.value);
irrecv.resume();
Serial.println("Last Code is set to: ");
Serial.write(lastCode);
if(results.value== 16748655 || (results.value== 4294967295 && lastCode== 16748655)) // Your ON button value
{
digitalWrite(8, HIGH);
digitalWrite(7, LOW);
analogWrite(9, 255);
delay(1000);
analogWrite(9, 0);
lastCode= 16748655;
}
else if(results.value == 16769055 || (results.value== 4294967295 && lastCode== 16769055)) // Your OFF button value
{
digitalWrite(8, LOW);
digitalWrite(7, HIGH);
analogWrite(9, 255);
delay(1000);
analogWrite(9, 0);
lastCode= 16769055;
}
}
}
A more reliable approach to running the motor until the button is released is to use a "no-code" timeout. That is, if the "no code" state persists for a period longer than the auto-repeat period, then it has been released.
It is not clear in your code what the 1 second analogue pulse is for, but placing long delays in your loop() function makes your system far less responsive. Better to poll the system tick and "do stuff" when it is time to do so. Also magic numbers should be avoided if you want anyone to understand your code and avoid errors in maintenance.
The following uses system tick polling to implement the "no-code" timeout. I have omitted the motor on/off code because it is not clear what you are doing there with the 1 second delays.
#define NO_CODE 0xFFFFFFFFul
#define MOTOR_ON_CODE 0xFF906Ful
#define MOTOR_OFF_CODE 0xFFE01Ful
#define STOP_TIME_MS 250ul // stop after button release for 250ms
void loop( )
{
static unsigned long last_on_time = 0 ;
if( irrecv.decode( &results ) )
{
irrecv.resume() ;
unsigned long code = results.value ;
// If motor off code or no code timeout...
if( code == MOTOR_OFF_CODE ||
(code == NO_CODE && millis() - last_on_time > STOP_TIME_MS) )
{
// Motor off
...
}
else if( code == MOTOR_ON_CODE )
{
// Continuously update last on time while button is held
last_on_time = millis() ;
// Motor on
...
}
}
}
I have included response to the motor-off code, but that may not be necessary, since the motor will be switched off 250ms (or whatever time you choose) after the ON button is released in any case. You might instead have a forward/reverse button and release either to stop:
#define NO_CODE 0xFFFFFFFFul
#define MOTOR_FWD_CODE 0xFF906Ful
#define MOTOR_REV_CODE 0xFFE01Ful
#define STOP_TIME_MS 250ul // stop after button release for 250ms
void loop( )
{
static unsigned long last_on_time = 0 ;
if( irrecv.decode( &results ) )
{
irrecv.resume() ;
unsigned long code = results.value ;
switch( code )
{
case NO_CODE :
{
if( millis() - last_on_time > STOP_TIME_MS )
{
// Motor off
...
}
}
break ;
case MOTOR_FWD_CODE :
{
// Continuously update last on time while button is held
last_on_time = millis() ;
// Motor forward
...
}
break ;
case MOTOR_FWD_CODE :
{
// Continuously update last on time while button is held
last_on_time = millis() ;
// Motor reverse
...
}
break ;
}
}
}

How to hold value for the state of a button for a timer?

I am making a timer with 3 push buttons with a 16x2 LCD screen on Arduino. Obviously I want to press my start button once for the timer to count up until the stop button is pressed. I have a reset button that it is connected to the reset pin so I did not write code for it.
I have already been to the ladayada.com tutorial about button state I followed the instructions closely. I am still getting the wrong results.
signed short minutes, seconds;
char timeline[16];
int startPin = 7;
int stopPin = 6;
int buttonState1;
int buttonState2;
int oldState;
int currentState;
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
pinMode(startPin,INPUT_PULLUP);
pinMode(stopPin,INPUT_PULLUP);
buttonState1 = digitalRead(startPin);
buttonState2 = digitalRead(stopPin);
void loop() {
currentState = digitalRead(startPin);
if(currentState!= buttonState1){
if(currentState==LOW){
lcd.setCursor(0, 1);
sprintf(timeline,"%0.2d mins %0.2d secs", minutes, seconds);
lcd.print(timeline);
delay(1000);
seconds++;
if (seconds == 60){
seconds = 0;
minutes ++; }
}
}
if(buttonState2==LOW){
delay(500);
sprintf(timeline,"%0.2d mins %0.2d secs", minutes, seconds);
}
buttonState1 = currentState;
}
I expected the Arduino to save the state of the button and count up until the stop button is pressed. When the stop button is pressed it should display the time(current count) when it was pressed. Instead the Start button has to be pressed twice to count one second. I cannot even get to the logic of the stop button.
If you press the start button only at the beginning of the program, why don't you just wait for a button action in setup()?
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
pinMode(startPin,INPUT_PULLUP);
pinMode(stopPin,INPUT_PULLUP);
while (digitalRead(startPin) != LOW); // <- wait for button action
}
In loop(), you want to count up until the stop button is pressed. If you do hardware reset afterwards, you can just put the program into an infinite loop once the stop button has been pressed.
void loop() {
lcd.setCursor(0, 1);
sprintf(timeline,"%0.2d mins %0.2d secs", minutes, seconds);
lcd.print(timeline);
delay(1000);
seconds++;
if (seconds == 60) {
seconds = 0;
minutes ++;
}
if (digitalRead(stopPin) == LOW) {
delay(500);
sprintf(timeline,"%0.2d mins %0.2d secs", minutes, seconds);
while(true) {} // infinite loop
}
}