Code Monkey home page Code Monkey logo

Comments (6)

Nagymadar avatar Nagymadar commented on July 16, 2024

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.

LennartHennigs avatar LennartHennigs commented on July 16, 2024

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.

Nagymadar avatar Nagymadar commented on July 16, 2024

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.

LennartHennigs avatar LennartHennigs commented on July 16, 2024

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.

LennartHennigs avatar LennartHennigs commented on July 16, 2024

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.

Fishbone69 avatar Fishbone69 commented on July 16, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.