New library for button managing

Hello everybody,

A few months ago, I wanted an easy-to-use library to manage the buttons of one of my projects, but I didn't find what I was looking for. Thus, I decided to write my own library (button_lib) !

Here I share you this library and I hope it will be useful for you.

I can't attach it because I'm a new user thus here's my code :

button_lib.cpp :

#include "button_lib.h"
#include "Arduino.h"

Button::Button(int pin)
{
  pinMode(pin, INPUT_PULLUP);
  _pin = pin;
}

bool Button::simpleClick()
{
  bool yesOrNo = false;
  bool read_button_state = digitalRead(_pin);
  if (read_button_state != _ButtonOldState)
  {
    _lastDebounce = millis();
  }
  if ((millis() - _lastDebounce) >= 50)
  {
    if (read_button_state != _ButtonNewState)
    {
      _ButtonNewState = read_button_state;

      if (_ButtonNewState == LOW)
      {
        yesOrNo = true;
      }
    }    
  }
  _ButtonOldState = read_button_state;
  return yesOrNo;
}

bool Button::longClick()
{
  bool yesOrNo = false;
  bool read_button_state = digitalRead(_pin);
  if ((read_button_state != _longButtonOldState) and (read_button_state == LOW))
  {
    _longlastDebounce = millis();
  }
  if ((millis() - _longlastDebounce) >= 50)
  {
    _longPossible = true;
  }
  if (((millis() - _longlastDebounce) < 1500) and (read_button_state == HIGH))
  {
    _longPossible = false;
  }
  if (((millis() - _longlastDebounce) >= 1500) and (_longPossible))
  {
    if (read_button_state != _LongButtonNewState)
    {
      _LongButtonNewState = read_button_state;

      if (_LongButtonNewState == LOW)
      {
        yesOrNo = true;
      }
    }    
  }
  _longButtonOldState = read_button_state;
  return yesOrNo;
}


bool Button::veryLongClick()
{
  bool yesOrNo = false;
  bool read_button_state = digitalRead(_pin);
  if ((read_button_state != _veryLongButtonOldState) and
     (read_button_state == LOW))
  {
    _veryLonglastDebounce = millis();
  }
  if ((millis() - _veryLonglastDebounce) >= 50)
  {
    _veryLongPossible = true;
  }
  if (((millis() - _veryLonglastDebounce) < 3000) and
     (read_button_state == HIGH))
  {
    _veryLongPossible = false;
  }
  if (((millis() - _veryLonglastDebounce) >= 3000) and (_veryLongPossible))
  {
    if (read_button_state != _veryLongButtonNewState)
    {
      _veryLongButtonNewState = read_button_state;

      if (_veryLongButtonNewState == LOW)
      {
        yesOrNo = true;
      }
    }    
  }
  _veryLongButtonOldState = read_button_state;
  return yesOrNo;
}


byte Button::multipleClick()
{
  byte nbreOfClicks = 0;
  bool read_button_state = digitalRead(_pin);
  if (read_button_state == LOW)
  {
    _pauseTime = millis();
  }
  if ((millis() - _pauseTime) > 1200)
  {
    nbreOfClicks = _nbreOfClicks;
    _nbreOfClicks = 0;
  }
  if ((read_button_state != _multipleButtonOldState) and
     (read_button_state == LOW))
  {
    _multipleLastDebounce = millis();
  }
  if ((read_button_state != _multipleButtonOldState) and
     (read_button_state == HIGH) and
     ((millis() - _multipleLastDebounce) < 1000) and
     ((millis() - _multipleLastDebounce) > 50))
  {
    _nbreOfClicks++;
    _pauseTime = millis();
  }
  if ((read_button_state != _multipleButtonOldState) and
     (read_button_state == HIGH) and
     ((millis() - _multipleLastDebounce) > 1000))
  {
    _nbreOfClicks = 0;
  }
  _multipleButtonOldState = read_button_state;
  return nbreOfClicks;
}

byte Button::longLevels()
{
  byte durationLevel = 0;
  bool read_button_state = digitalRead(_pin);
  if ((read_button_state != _longLevelButtonOldState) and
     (read_button_state == LOW))
  {
    _longLevellastDebounce = millis();
  }
  if ((millis() - _longLevellastDebounce) >= 50)
  {
    _longLevelPossible = true;
  }
  if ((_longLevelPossible) and (read_button_state == HIGH))
  {
    _longLevelPossible = false;
    durationLevel = _durationLevel;
    _durationLevel = 0;
  }
  /*I decided to make 3 levels of duration : the first at 2000 millis, the
   *second at 3500 and the third at 5000 millis. The method will return the
   *level, not the duration! So you can use a switch (var) {case 1: ...} in
   *your program and than case 1 is for the first level and so on... */
  if (((millis() - _longLevellastDebounce) > 2000) and (_durationLevel == 0) and
     (read_button_state == LOW))
  {
    _durationLevel++;
  }
  if (((millis() - _longLevellastDebounce) > 3500) and (_durationLevel == 1) and
     (read_button_state == LOW))
  {
    _durationLevel++;
  }
  if (((millis() - _longLevellastDebounce) > 5000) and (_durationLevel == 2) and
     (read_button_state == LOW))
  {
    _durationLevel++;
  }
  _longLevelButtonOldState = read_button_state;
  return durationLevel;
}

button_lib.h :

#ifndef Button_h
#define Button_h

#include "Arduino.h"

class Button
{
  public:

  Button(int pin);
  bool simpleClick();
  bool longClick();
  byte multipleClick();
  byte longLevels();
  bool veryLongClick();

  private:

  int _pin;
  bool _ButtonOldState = HIGH;
  unsigned long _lastDebounce = 0;
  bool _ButtonNewState;
  bool _Possible = false;
  bool _longButtonOldState = HIGH;
  unsigned long _longlastDebounce = 0;
  bool _LongButtonNewState = HIGH;
  bool _longPossible = false;
  bool _multipleButtonOldState = HIGH;
  unsigned long _multipleLastDebounce = 0;
  unsigned long _pauseTime = 0;
  byte _nbreOfClicks = 0;
  byte _durationLevel = 0;
  unsigned long _longLevellastDebounce = 0;
  bool _longLevelButtonOldState = HIGH;
  bool _longLevelPossible = false;
  bool _veryLongButtonOldState = HIGH;
  unsigned long _veryLonglastDebounce = 0;
  bool _veryLongPossible = false;
  bool _veryLongButtonNewState = HIGH;
};

#endif

readme.md

#Arduino button_lib library
The button_lib library is useful to manage the buttons in your Arduino projects.

You just need to instantiate a button object of the **```Button```** class and enter the pin of the button as an attribute. Then just apply the different methods on your button object and get the results.

##button_lib methods
###simpleClick()
This method will return a **```true```** boolean if there is a button click (short or long, it doesn't matter). **```simpleClick()```** will immediately return a value when the button is pressed, so this is a good method for things like a stopwatch, or other things where precision over time is important.
The default return value is **```false```**.
###multipleClick()
This method will return the number of times the button is pressed consecutively (return value type is byte, so maximum is 255). The method returns a value 1.2s after the button is no longer pressed because the method must verify that there are no more clicks coming.
The default return value is 0 (when there's no click).
###longLevels()
This method works a bit like **```multipleClick()```** but for long clicks : If you press 2s, the method returns 1, if you press 3.5s, the method returns 2, and if you press 5s, the method returns 3 (3 is the last level but you can easy add levels in the .cpp file).
The default return value is 0.
###longClick()
This method works like **```simpleClick()```** but for long clicks and returns a value (**```true```** or **```false```** boolean) when the button is no longer pressed.
The default return value is **```false```**.
###veryLongClick()
This method is the same as **```longClick()```** but for longer clicks. This method can be used in combination with **```longClick()```** : if you press the button a long time a led lights up, and if you keep pressing, a second led lights up.
The default return value is **```false```**.

##Compatibilities
Some of the methods above are not compatible between them. **```simpleClick()```** is not compatible with **```multipleClick()```** and **```longLevels()```**. In the same way, **```longClick()```** and **```veryLongClick()```** are not compatible with **```longLevels()```**. Each methods has its advantages, choose the right ones for your project. of course you can use **```simpleClick()```** on one button and **```multipleClick()```** on another!

example1 :

#include <button_lib.h>

Button button1(3);  //we instantiate a button which is connected to pin 9
Button button2(4);  //we instantiate a second button which is connected to pin 10
Button button3(5);  //...

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (button1.simpleClick())
  {
    Serial.print("\nbutton1 was pressed once (simple click)");
  }
  switch (button2.multipleClick())
  {
    case 1:
      Serial.print("\nbutton2 was pressed once");
      break;
    case 2:
      Serial.print("\nbutton2 was pressed twice");
      break;
    case 3:
      Serial.print("\nbutton2 was pressed thrice");
      break;
    //multipleClick() returns a byte so maximum is 255 ;-)
  }
  switch (button2.longLevels())
  {
    case 1:
      Serial.print("\nbutton2 was pressed once for a long time");
      break;
    case 2:
      Serial.print("\nbutton2 was pressed once for a very long time");
      break;
    case 3:
      Serial.print("\nbutton2 was pressed once for a very very long time");
      break;
  }
  if (button3.longClick())
  {
    Serial.print("\nbutton3 was pressed once for a long time");
  }
  if (button3.veryLongClick())
  {
    Serial.print("...A very long Click!!!");
  }
}
2 Likes

You could create a repository on GitHub then submit the library to Arduino registry.

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.