clickButton library

I echo everyone’s comments – many thanks @peekay123 for sharing this library. I was trying to write my own debounce functions, and this made my life way easier! The fact I can now handle different types of clicks will also be extremely useful in the future…

Since my project asks for debouncing multiple buttons, I combined this ClickButton class with Vectors for instantiating multiple ClickButton objects in a single array. Works great and makes for very elegant code. See below for the modified clickButtonDemo.cpp as an example:

#include <clickButton.h>
#include <vector>

#define INPUT_BTN_NUM 4

// the Buttons
const int buttonPin[INPUT_BTN_NUM] = {D0,D1,D2,D3};
std::vector <ClickButton> button;

// Button results 
int function[4] = {0,0,0,0};


void setup()
{
  Serial.begin(9600);
  
  for (int i = 0; i < INPUT_BTN_NUM; i++) {

    // Instantiate the ClickButton object
    button.push_back(ClickButton(buttonPin[i], LOW, CLICKBTN_PULLUP));

    pinMode(buttonPin[i], INPUT_PULLUP);

    // Setup button timers (all in milliseconds / ms)
    // (These are default if not set, but changeable for convenience)
    button[i].debounceTime   = 20;   // Debounce timer in ms
    button[i].multiclickTime = 250;  // Time limit for multi clicks
    button[i].longClickTime  = 1000; // time until "held-down clicks" register
  }
}


void loop()
{
    for (int i = 1; i < INPUT_BTN_NUM; i++) {
        // Update button state
        button[i].Update();
        
        // Save click codes in function, as click codes are reset at next Update()
        if(button[i].clicks != 0) function[i] = button[i].clicks;
        
        if(function[i] == 1) Serial.printlnf("Button %u: SINGLE click",i);
        
        if(function[i] == 2) Serial.printlnf("Button %u: DOUBLE click",i);
        
        if(function[i] == 3) Serial.printlnf("Button %u: TRIPLE click",i);
        
        if(function[i] == -1) Serial.printlnf("Button %u: SINGLE LONG click",i);
        
        if(function[i] == -2) Serial.printlnf("Button %u: DOUBLE LONG click",i);
        
        if(function[i] == -3) Serial.printlnf("Button %u: TRIPLE LONG click",i);
        
        function[i] = 0;
    }
    delay(5);
}

Cheers!

2 Likes

@elosier, nicely done and thanks for sharing. I just want to make sure the creds go to raronzen@gmail.com for creating this library. I simply made it available on the Particle IDE. :wink:

2 Likes

Hey @peekay123 thank you very much for porting this library, I really like it.

I tried to use it together with the Adafruit_MCP23017 Library were my buttons are connected to but unfortunately it didn’t work and my photon responded with a red error blinking. I think it was “usage fault”.

I tried to modify the library like that:

#include "Adafruit_MCP23017.h"
...
void ClickButton::Update(Adafruit_MCP23017* mcp)
{
    long now = (long)millis();      // get current time        
    _btnState = mcp->digitalRead(_pin);  // current appearant button state
    ...
}

I have also changed the definition in the corresponding .h file.

The call in my code was

#include "Adafruit_MCP23017.h"
#include "clickButton.h"

Adafruit_MCP23017 mcp;

const int buttonPin1 = 0;
ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP);

void setup() {  
      mcp.begin();      
      mcp.pinMode(buttonPin1, INPUT);
      mcp.pullUp(buttonPin1, HIGH);

      button1.debounceTime   = 20;
      button1.multiclickTime = 250;
      button1.longClickTime  = 1000;
}

void loop()
{
    button1.Update(&mcp);
    if(button1.clicks != 0) Serial.println('Button Click');
    delay(5);
}

I have also tried to set the MCP variable in the constructor of the clickButton but this didn’t work either.

ClickButton::ClickButton(uint8_t buttonPin, boolean activeType, boolean internalPullup, Adafruit_MCP23017* mcp)
{
    _pin           = buttonPin;
    _activeHigh    = activeType;
    _btnState      = !_activeHigh;  // initial button state in active-high logic
    _lastState     = _btnState;
    _clickCount    = 0;
    clicks         = 0;
    depressed      = 0;
    _lastBounceTime= 0;
    debounceTime   = 20;            // Debounce timer in ms
    multiclickTime = 250;           // Time limit for multi clicks
    longClickTime  = 1000;          // time until "long" click register
    
    _mcp = mcp;

    // Turn on internal pullup resistor if applicable
    if (_activeHigh == LOW && internalPullup == CLICKBTN_PULLUP){
        _mcp->pinMode(_pin, INPUT);
        _mcp->pullUp(_pin, HIGH);
   } else {
        _mcp->pinMode(_pin, INPUT);
        _mcp->pullUp(_pin, LOW);
   }
}

void ClickButton::Update()
{
    long now = (long)millis();      // get current time        
   _btnState = _mcp->digitalRead(_pin);  // current appearant button state
    ...
}

Does anybody have an idea how to combine the clickButton with the MCP23017?

Thank you very much for your help :slight_smile:

@Trekky, clickButton was not designed to be used with the MCP23017. You may, however, look at adapting this arduino library which does exactly that:

@peekay123 thank you very much for this hint. I was able to modify the clickButton library to get it working with a MCP23017 IO Expander. You can find the code here https://github.com/Trekky12/clickButtonMCP

After creating an button object you need to attach the mcp object to the button to get it working.

Maybe someone can need that too.

1 Like

Does anyone know how to get this library to compile locally? I can do it if all the code is in one file, but if I split it into a .h, a .cpp and a .ino, even when using includes, I get a load of errors. Should I also be including other files? “not declared in this scope” & “does not name a type” etc

(I have a good reason for needing to compile locally.)

@netpex, I put the clickButton .cpp and .h files along with the example .cpp file in a single folder and it compiled just fine. What errors are you getting?

Resolved my problem - needed to add more #includes in more places than I realised.

Shouldn't that be D4 where the buttonPin1 is defined?

We usually prefer the more elaborate/explicit naming convention, but since D4 is defined as 4 it doesn’t make any difference really.
I guess the reason for peekay123 having that in his code snippet is that he had taken that code from another source as is.

@ScruffR, that’s exactly why :nerd_face:

1 Like