Comments (6)
My version to solve this: if you have a negative attachTo input, then it is an active HIGH button. This demands a float input, what distinguishes between -0 (negative zero) and +0 (positive zero). Not the nicest workaround, but 100% backward compatible and works. Other way: using the buttonMode with an enum?
Button2::Button2(float attachTo, byte buttonMode /*= INPUT_PULLUP*/, unsigned int debounceTimeout /*= DEBOUNCE_MS*/) {
if (std::signbit(attachTo)) {
state_active = HIGH;
state = LOW;
pin = -attachTo;
} else {
state_active = LOW;
state = HIGH;
pin = attachTo;
}
setDebounceTime(debounceTimeout);
pinMode(pin, buttonMode);
}
from button2.
Sorry, I don't really understand your request.
In the constructor you can define the button mode (INPUT or INPUT_PULLUP).
Does this not solve your problem?
If not, could you please elaborate a bit? thx.
from button2.
The library does not work with active HIGH buttons, only active LOW. If it is active HIGH, it generates a unintentional click_cb call after the object is created, beside of the fact that isPressed is inverted, etc, etc. I modified your library (renamed to Button3), and it works like a charm. Have a look:
button3.h
/////////////////////////////////////////////////////////////////
/*
Button3.cpp - Arduino Library to simplify working with buttons.
Created by Lennart Hennigs, October 28, 2017.
Modified by Nagymadar, 2020 March
*/
/////////////////////////////////////////////////////////////////
#pragma once
#ifndef Button3_h
#define Button3_h
/////////////////////////////////////////////////////////////////
#include "Arduino.h"
/////////////////////////////////////////////////////////////////
#define DEBOUNCE_MS 50
#define LONGCLICK_MS 200
#define DOUBLECLICK_MS 300
#define SINGLE_CLICK 1
#define DOUBLE_CLICK 2
#define TRIPLE_CLICK 3
#define LONG_CLICK 4
/////////////////////////////////////////////////////////////////
class Button3 {
private:
byte pin;
int state_active;
int prev_state;
int state;
byte click_count = 0;
unsigned int last_click_type = 0;
unsigned long click_ms;
unsigned long down_ms;
unsigned int debounce_time_ms;
unsigned int down_time_ms = 0;
bool pressed_triggered = false;
bool longclick_detected = false;
typedef void (*CallbackFunction) (Button3&);
CallbackFunction pressed_cb = NULL;
CallbackFunction released_cb = NULL;
CallbackFunction change_cb = NULL;
CallbackFunction tap_cb = NULL;
CallbackFunction click_cb = NULL;
CallbackFunction long_cb = NULL;
CallbackFunction double_cb = NULL;
CallbackFunction triple_cb = NULL;
public:
Button3(float attachTo, byte buttonMode = INPUT_PULLUP, unsigned int debounceTimeout = DEBOUNCE_MS);
void clear();
void setDebounceTime(unsigned int ms);
void setChangedHandler(CallbackFunction f);
void setPressedHandler(CallbackFunction f);
void setReleasedHandler(CallbackFunction f);
void setClickHandler(CallbackFunction f);
void setTapHandler(CallbackFunction f);
void setLongClickHandler(CallbackFunction f);
void setDoubleClickHandler(CallbackFunction f);
void setTripleClickHandler(CallbackFunction f);
unsigned int wasPressedFor();
boolean isPressed();
unsigned int getNumberOfClicks();
unsigned int getClickType();
bool operator==(Button3 &rhs);
void loop();
};
/////////////////////////////////////////////////////////////////
#endif
/////////////////////////////////////////////////////////////////
Button3.cpp
/////////////////////////////////////////////////////////////////
/*
Button3.cpp - Arduino Library to simplify working with buttons.
Created by Lennart Hennigs, October 28, 2017.
Modified by Nagymadar, 2020 March
*/
/////////////////////////////////////////////////////////////////
#include "Arduino.h"
#include "Button3.h"
/////////////////////////////////////////////////////////////////
Button3::Button3(float attachTo, byte buttonMode /*= INPUT_PULLUP*/, unsigned int debounceTimeout /*= DEBOUNCE_MS*/) {
if (std::signbit(attachTo)) {
state_active = HIGH;
state = LOW;
pin = -attachTo;
} else {
state_active = LOW;
state = HIGH;
pin = attachTo;
}
setDebounceTime(debounceTimeout);
pinMode(pin, buttonMode);
}
/////////////////////////////////////////////////////////////////
bool Button3::operator==(Button3 &rhs) {
return (this==&rhs);
}
/////////////////////////////////////////////////////////////////
void Button3::setDebounceTime(unsigned int ms) {
debounce_time_ms = ms;
}
/////////////////////////////////////////////////////////////////
void Button3::setChangedHandler(CallbackFunction f) {
change_cb = f;
}
/////////////////////////////////////////////////////////////////
void Button3::setPressedHandler(CallbackFunction f) {
pressed_cb = f;
}
/////////////////////////////////////////////////////////////////
void Button3::setReleasedHandler(CallbackFunction f) {
released_cb = f;
}
/////////////////////////////////////////////////////////////////
void Button3::setClickHandler(CallbackFunction f) {
click_cb = f;
}
/////////////////////////////////////////////////////////////////
void Button3::setTapHandler(CallbackFunction f) {
//Serial.printf("Pin %d tap handler set to %ld\n", pin, (long)f);
tap_cb = f;
}
/////////////////////////////////////////////////////////////////
void Button3::setLongClickHandler(CallbackFunction f) {
long_cb = f;
}
/////////////////////////////////////////////////////////////////
void Button3::setDoubleClickHandler(CallbackFunction f) {
double_cb = f;
}
/////////////////////////////////////////////////////////////////
void Button3::setTripleClickHandler(CallbackFunction f) {
triple_cb = f;
}
/////////////////////////////////////////////////////////////////
unsigned int Button3::wasPressedFor() {
return down_time_ms;
}
/////////////////////////////////////////////////////////////////
boolean Button3::isPressed() {
return (state == state_active);
}
/////////////////////////////////////////////////////////////////
unsigned int Button3::getNumberOfClicks() {
return click_count;
}
/////////////////////////////////////////////////////////////////
unsigned int Button3::getClickType() {
return last_click_type;
}
/////////////////////////////////////////////////////////////////
void Button3::loop() {
prev_state = state;
state = digitalRead(pin);
// is button pressed?
if (prev_state == !state_active && state == state_active) {
down_ms = millis();
pressed_triggered = false;
click_count++;
click_ms = down_ms;
// is the button released?
} else if (prev_state == state_active && state == !state_active) {
down_time_ms = millis() - down_ms;
// is it beyond debounce time?
if (down_time_ms >= debounce_time_ms) {
// trigger release
if (change_cb != NULL) change_cb (*this);
if (released_cb != NULL) released_cb (*this);
// trigger tap
if (tap_cb != NULL) tap_cb (*this);
// was it a longclick? (preceeds single / double / triple clicks)
if (down_time_ms >= LONGCLICK_MS) {
longclick_detected = true;
}
}
// trigger pressed event (after debounce has passed)
} else if (state == state_active && !pressed_triggered && (millis() - down_ms >= debounce_time_ms)) {
if (change_cb != NULL) change_cb (*this);
if (pressed_cb != NULL) pressed_cb (*this);
pressed_triggered = true;
// is the button pressed and the time has passed for multiple clicks?
} else if (state == !state_active && millis() - click_ms > DOUBLECLICK_MS) {
// was there a longclick?
if (longclick_detected) {
// was it part of a combination?
if (click_count == 1) {
last_click_type = LONG_CLICK;
if (long_cb != NULL) long_cb (*this);
}
longclick_detected = false;
// determine the number of single clicks
} else if (click_count > 0) {
switch (click_count) {
case 1:
last_click_type = SINGLE_CLICK;
if (click_cb != NULL) click_cb (*this);
break;
case 2:
last_click_type = DOUBLE_CLICK;
if (double_cb != NULL) double_cb (*this);
break;
case 3:
last_click_type = TRIPLE_CLICK;
if (triple_cb != NULL) triple_cb (*this);
break;
}
}
click_count = 0;
click_ms = 0;
}
}
void Button3::clear() {
state = !state_active;
click_count = 0;
last_click_type = 0;
down_time_ms = 0;
pressed_triggered = false;
longclick_detected = false;
pressed_cb = NULL;
released_cb = NULL;
change_cb = NULL;
tap_cb = NULL;
click_cb = NULL;
long_cb = NULL;
double_cb = NULL;
triple_cb = NULL;
}
from button2.
Hey Nagymadar,
thanks for your input. I am currently updating the class and pushing commits to close the issues you posted. (The commits are also linked the issues).
I'll now test the class a bit and take a look at the suggestion of yours:
if (std::signbit(attachTo)) {
state_active = HIGH;
state = LOW;
pin = -attachTo;
} else {
state_active = LOW;
state = HIGH;
pin = attachTo;
}
Best
l.
from button2.
I didn't want to use floats to assign pins to a button.
Instead, I opted to add a boolean parameter to the constructor of the Button2
class:
Button2(byte attachTo, byte buttonMode = INPUT_PULLUP, boolean activeLow = true, unsigned int debounceTimeout = DEBOUNCE_MS);
After setting the second parameter to false the class works correctly with active high buttons.
Thank you for your input, Nagymadar.
from button2.
Hi...I tried this lib with active high buttons and still no luck. Maybe it is my constructor syntax? I am using the following:
buttonUp.begin(BUTTON_UP,INPUT,false);
although I also tried
buttonUp.begin(BUTTON_UP,INPUT_PULLDOWN,false);
Any help is appreciated!
from button2.
Related Issues (20)
- detection of long presses does not work properly inside of an interupt timer HOT 2
- Interrupt wdt timeout on CPU1 HOT 2
- button.isPressed(); seems to stay latched. HOT 1
- Long press is not reported in polling mode HOT 1
- Change std::functional guards from platform-based to language version-based HOT 1
- multiple ESP32CapacitiveTouch.ino HOT 1
- 2.3.0 breaks at least on RP2040 with type errors HOT 3
- 2.3.x breaks default implementation? HOT 4
- Advices for implementing a speed-sensitive button-press control HOT 1
- setStateHandler Functions HOT 1
- Multiplexed buttons support HOT 1
- Use hall sensor instead button HOT 1
- 2.3.x does not compile on Arduino Uno R4 HOT 3
- Watchdog timer triggered on both ESP32 Capacitive Touch examples HOT 1
- virtual button init callback HOT 1
- another i2c PE button question HOT 8
- update constants in examples
- Problem with longpress behavior HOT 3
- [question] Is it compatible with all microcontrollers having an Arduino framework implementation? HOT 2
- Multiple Button Issue
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from button2.