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!

@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:

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.

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: