Skip to content

Driving push-buttons & tactile switches in C++, with esp-idf v5.0+.

License

Notifications You must be signed in to change notification settings

myles-parfeniuk/button_driver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

image

Table of Contents
  1. About
  2. Getting Started
  3. Usage
  4. License
  5. Contact

About

ButtonDriver is a C++ based component written for esp-idf version 5.0+, intended to simplify the use of push-buttons and tactile switches.

It allows for the creation of Button objects which automatically detect user input from externally connected tactile switches or push-buttons.
Call-back functions can be registered to button objects to handle detected user input.

(back to top)

Getting Started

(back to top)

Adding to Project

  1. Create a "components" directory in the root workspace directory of your esp-idf project if it does not exist already.

    In workspace directory:

    mkdir components
  2. Cd into the components directory and clone both the ButtonDriver, and DataControl repos.

    cd components
    git clone https://github.com/myles-parfeniuk/data_control.git
    git clone https://github.com/myles-parfeniuk/button_driver.git

    The ButtonDriver is dependent on DataControl and will not build without it.

  3. Ensure you clean your esp-idf project before rebuilding.
    Within esp-idf enabled terminal:

     idf.py fullclean

(back to top)

Usage

(back to top)

Quick Start

This is intended to be a quick-guide, api documentation generated with doxygen can be found in the documentation directory of the master branch.

(back to top)

Initializing Button Object

To initialize a button object, first initialize and configure a button_conf_t struct with the desired settings, then pass it into the Button constructor.

The settings available within a button_conf_t struct:

  • gpio_num — The GPIO number associated with the button, must not be initialized as GPIO_NUM_NC
  • active_lo — Set to true if the button is active low (falling edge trigger), cannot be true if active_hi is also true
  • active_hi — Set to true if the button is active high (rising edge trigger), cannot be true if active_lo is also true
  • pull_en — Set to true if internal pullup/pulldown resistor is enabled for button gpio pin, set to false if external resistors are used
  • long_press_evt_time — long-press event generation time in microseconds (us) if the button is held for longer than (long_press_evt_time+25ms) a long-press event is generated, if it is released before (long_press_evt_time+25ms) elapses, a quick-press event is generated instead suggested time of 300000us, must be between 10000us and 5000000us
  • held_event_evt_time — held event generation time in microseconds (us), if a long press event has already occurred and the button is still being held, held events will be generated every held_evt_time elapses, suggested time of 200000us, must be between 10000us and 5000000us

If the button_conf_t struct is not initialized correctly the Button constructor will output an error related to the issue in the terminal and dump a stack trace.

Example Initializations:

  1. Active-Low w/ external pullup

image

    //initialize button_config_t struct
    Button::button_config_t button_conf =
    {
        .gpio_num = GPIO_NUM_25, //gpio number connected to button, for ex.25
        .active_lo = true, //active low
        .active_hi = false, //not active high
        .pull_en = false, //internal pullup disabled
        .long_press_evt_time = 300000, //300ms long-press event generation time
        .held_evt_time = 200000, //200ms held event generation time
    };

    //declare & initialize Button object
    Button my_button(button_conf);
  1. Active-Low w/ no external pullup

image

    //initialize button_config_t struct
    Button::button_config_t button_conf =
    {
        .gpio_num = GPIO_NUM_25, //gpio number connected to button, for ex.25
        .active_lo = true, //active low
        .active_hi = false, //not active high
        .pull_en = true, //internal pullup enabled
        .long_press_evt_time = 300000, //300ms long-press event generation time
        .held_evt_time = 200000, //200ms held event generation time
    };

    //declare & initialize Button object
    Button my_button(button_conf);
  1. Active-High w/ external pulldown

image

    //initialize button_config_t struct
    Button::button_config_t button_conf =
    {
        .gpio_num = GPIO_NUM_25, //gpio number connected to button, for ex.25
        .active_lo = false, //not active low
        .active_hi = true, //active high
        .pull_en = false, //internal pulldown disabled
        .long_press_evt_time = 300000, //300ms long-press event generation time
        .held_evt_time = 200000, //200ms held event generation time
    };

    //declare & initialize Button object
    Button my_button(button_conf);
  1. Active-High w/ no external pulldown

image

    //initialize button_config_t struct
    Button::button_config_t button_conf =
    {
        .gpio_num = GPIO_NUM_25, //gpio number connected to button, for ex.25
        .active_lo = false, //not active low
        .active_hi = true, //active high
        .pull_en = true, //internal pulldown enabled
        .long_press_evt_time = 300000, //300ms long-press event generation time
        .held_evt_time = 200000, //200ms held event generation time
    };

    //declare & initialize Button object
    Button my_button(button_conf);

(back to top)

Button Events

After being initialized, a Button object will automatically detect any user input and generate an event.

These events come in 4 flavors:

  1. quick-press:
    This event indicates the button was momentarily pressed. This event is generated when the push-button is pressed & then released before (25ms + long_press_evt_time) has elapsed.

  2. long-press:
    This event indicates the button was pressed and held. This event is generated when the push-button is pressed & not released after (25ms + long_press_evt_time) has elapsed.

  3. held:
    This event indicates a long-press event has already occurred, and the button is still being held. This event is generated every time held_evt_time elapses, after a long-press event, until the button is released.

  4. released:
    This event indicates the button has been released. This event is generated if the button is released any time after a long_press event has occurred.

(back to top)

Handling Button Events

In order to be notified when a button-event has occurred, a call-back function (or multiple) can be registered with the button by calling the follow() method on its event member.

As many call-backs as desired can be registered to a button using follow(). When a button event occurs, any call-backs registered to the respective button will be called in the order they were registered— this means whichever call-back was registered first has highest priority.

It is recommended to initialize the call-back functions as lambda-functions for easy readability.
Any call-back function registered with follow() must take the form:

  void call_back_example(Button::ButtonEvent event);

Example call-back functions & registrations:

  1. Using a lambda call-back function:
//call the follow() method on a button event member to register a callback with a button
my_button.event.follow(
        //lambda call-back function— called automatically when button input is detected
        [](Button::ButtonEvent event)
        {
            //button event handler
            switch(event){
                case Button::ButtonEvent::quick_press:
                  //place code that should be run on quick-press here
                break;

                case Button::ButtonEvent::long_press:
                  //place code that should be run on long-press here
                break;

                case Button::ButtonEvent::held:
                  //place code that should be run when button is held here
                break;

                case Button::ButtonEvent::released:
                  //place code that should be run when button is released here
                break;
            }
        });
  1. Using call-back function pointer:
//call-back prototype
void my_callback(Button::ButtonEvent event);

//call the follow() method on a button event member to register a callback with a button
my_button.event.follow(my_callback);

//call-back function— called automatically when button input is detected
void my_callback(Button::ButtonEvent event)
{
  
  //button event handler
  switch(event)
  {
    case Button::ButtonEvent::quick_press:
      //place code that should be run on quick-press here
    break;

    case Button::ButtonEvent::long_press:
      //place code that should be run on long-press here
    break;

    case Button::ButtonEvent::held:
      //place code that should be run when button is held here
    break;

    case Button::ButtonEvent::released:
      //place code that should be run when button is released here
    break;
  }
}

(back to top)

Examples

Examples are available in the ButtonDriver directory of my esp_idf_cpp_examples repo:

(back to top)

https://github.com/myles-parfeniuk/esp_idf_cpp_examples

(back to top)

Program Flowchart

image

(back to top)

License

Distributed under the MIT License. See LICENSE.md for more information.

(back to top)

Contact

Myles Parfeniuk - [email protected]
Project Link: https://github.com/myles-parfeniuk/button_driver

(back to top)

About

Driving push-buttons & tactile switches in C++, with esp-idf v5.0+.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages