Coder Social home page Coder Social logo

esp32-button's Introduction

Button press detector

This implements a version of THE ULTIMATE DEBOUNCER(TM) from hackaday.

It can monitor multiple pins, and sends button events over a queue for your application to process.

Available input GPIO pins

Only the following pins can be used as inputs on the ESP32:

0-19, 21-23, 25-27, 32-39

Example Usage

button_event_t ev;
QueueHandle_t button_events = button_init(PIN_BIT(BUTTON_1) | PIN_BIT(BUTTON_2));
while (true) {
    if (xQueueReceive(button_events, &ev, 1000/portTICK_PERIOD_MS)) {
        if ((ev.pin == BUTTON_1) && (ev.event == BUTTON_DOWN)) {
            // ...
        }
        if ((ev.pin == BUTTON_2) && (ev.event == BUTTON_DOWN)) {
            // ...
        }
    }
}

Event Types

BUTTON_DOWN

Triggered when the button is first considered pressed.

BUTTON_UP

Triggered when the button is considered released. In most cases you can use either the UP or DOWN event for your application, and ignore the other.

BUTTON_HELD

Triggered starting after 2 seconds of long holding a button and then every 50ms thereafter.

esp32-button's People

Contributors

fremouw avatar happenpappen avatar lukecyca avatar mkfrey avatar odx avatar schoosch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp32-button's Issues

Adding `#include "button.h"` to my otherwise working code causes a compiler meltdown.

I've attached

ESP32-TDisplayDeck.tar.gz

which contains my code. If you comment out the #include <button.h> in line 3 of main/main.c the code will compile fine. However, with that line uncommented, the compiler just melts down.

Here is the tail end of the compile output:

main/main.c:7:20: error: storage class specified for parameter 'TAG'
 static const char *TAG = (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__);
                    ^~~
main/main.c:7:1: error: parameter 'TAG' is initialized
 static const char *TAG = (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__);
 ^~~~~~
main/main.c:9:17: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
 void app_main() {
                 ^
In file included from /home/peter/.platformio/packages/framework-espidf/components/freertos/include/freertos/task.h:36,
                 from /home/peter/.platformio/packages/framework-espidf/components/freertos/include/freertos/queue.h:40,
                 from lib/esp32-button-master/include/button.h:4,
                 from main/main.c:3:
/home/peter/.platformio/packages/framework-espidf/components/freertos/include/freertos/list.h:345:6: error: old-style parameter declarations in prototyped function definition
 void vListInitialise( List_t * const pxList ) PRIVILEGED_FUNCTION;
      ^~~~~~~~~~~~~~~
main/main.c:11: error: expected '{' at end of input
 }
 
cc1: some warnings being treated as errors
*** [.pio/build/ttgo-t1/main/main.o] Error 1
=========================================================================================== [FAILED] Took 16.42 seconds ===========================================================================================
The terminal process "platformio 'run', '--environment', 'ttgo-t1'" terminated with exit code: 1.

Terminal will be reused by tasks, press any key to close it.

Button: NN Long all the time?

Hi,
For some reason, I am getting BUTTON_HELD all the time unless I press the button, at which time i get a BUTTON_DOWN.
But even if I then hold the button, I do not get a new (BUTTON_HELD) event. In fact, I get no event.

The constant BUTTON_HELD I am getting, I am getting even though the actual GPIO is low at the time.

It is just quite strange, I am probably doing some dumb thing wrong.
But the combination of GPIO low and BUTTON_HELD is incomprehensible to me..

Only works 3 times on BUTTON_DOWN then stops working?

Sorry for the noob question, I am extremely new to this. I've got this working off a really simple application built in platformio, only running the following in app_main():

    button_event_t ev;
    QueueHandle_t button_events = button_init(PIN_BIT(BUTTON_1));

My app main is a .cpp file so I've had to do an include on your files with:

extern "C" {
    #include "button.h"
}

However in my application the button events only work three times. From my serial logs:

␛[0;32mI (3657) BUTTON: 0 DOWN␛[0m
␛[0;32mI (3877) BUTTON: 0 UP␛[0m
␛[0;32mI (4867) BUTTON: 0 DOWN␛[0m
␛[0;32mI (5217) BUTTON: 0 UP␛[0m
␛[0;32mI (6257) BUTTON: 0 DOWN␛[0m

After this pressing the buttons has no action and that last button up event is never triggered. Any idea what may be the cause of this?

If i reset the board, I get three button down events again and then nothing.

Integrating with ESP-IDF project

Hi,

I am trying to use your implementation as a component into my existing ESP-IDF project configuration. I have the following questions.

  1. Do I need something more than an ESP32 board and a push button in order to setup the circuit?
  2. I am unable to include it as a component.

Do you maybe have a tiny example?

For your consideration: Proof of concept ISR version

Hi guys, yesterday I put together just as the title says a functional prototype of the ISR flavor of this debouncing code

Find it here https://github.com/malachi-iot/esp32-button/blob/exp-isr-working1/src/button_isr.c

As a prototype, it lacks a number of important qualities such as:

  • Crit section protection
  • Configurability
  • Optimization
  • General cleanliness

However it does work well for my single button scenario. The general approach is a direct morph of the existing code. In essence:

  1. Edge detection ISR notices incoming GPIOs and triggers a hardware timer ISR
  2. Hardware timer does most of the familiar stuff you see in the RTOS task, but without an RTOS task

I don't love that we're essentially "ticking" in phase 2 as @X-Ryl669 pointed out in #15 . I'm undecided if it's worth the extra complexity for this approach vs an RTOS task. Undoubtedly this approach is leaner. I hurt my brain yesterday trying to "detickify" the thing, so screw it :)

I invite comment, discussion, approval or disapproval. If the general notion is liked, I will clean it up and make it production worthy and do a PR

Test code is here https://github.com/malachi-iot/esp32-button/tree/exp-isr-working1/test/interactive/isr

enabling GPIO pullup might be necessary

I got this code working on the AiThinker ESP32-A1S audio/wifi/bluetooth dev board.
The rev 2.2 board which I have has 6 pushbuttons, which attach to IO5, IO13, IO18, IO19, IO23, and IO36.

I was having trouble getting the code to work until I added the following two lines to button.c (right after the line with io_conf.mode):

io_conf.mode = GPIO_MODE_INPUT;  
io_conf.pull_up_en = 1;
io_conf.pull_down_en = 0;

Now it works great. Thanks! Just leaving this as a comment more than anything else.

CPP changes

I have made just enough modifications to get a cpp version of this library so that it compiles under Arduino inside VSCode. The only change left for me to make is to properly handle the gpio_pull_mode_t assignment (I have it hardcoded to PULLUP for my environment).

Are you interested in an Arduino compat CPP file or should I just fork the repo?

Tx!

Maybe not the best for button debouncing

Debouncing the Elliot's way has multiple disadvantages:

  1. Needs to be polled so it consumes a task and the polling frequency should be constant (it's not on a FreeRTOS task).
  2. Can't detect 000101011111 like bouncing pattern. The mask used to detect a button press edge is 00xxx111. So there is at least a frequency of the bouncing that'll fail detection. In your code, you're using longer patterns, but it's the same issue.
  3. Use of a Queue takes a lot of resources (with cross CPU interrupts) on ESP32. It's a huge amplification of the debouncing cost.
  4. Button pressed is only detected after multiple polling. So you have a high latency.

I think it'd be better if you used relaxing timers or counters instead:

Relaxing timer

  1. Set an interrupt on any edge of the button
  2. In the interrupt handler, you're checking if you are in the relax period or not
  3. If you are in the relax period, return and ignore the interrupt
  4. Else, start the relax period, and call the user's GPIO handler directly (or use a Queue if you need cross task here)
  5. Optional: The GPIO handler can store/maintain the state of the button

This typically react as fast as possible to the first button press (no latency) and is not sensitive to bounce frequency or task scheduling

Counters

  1. Set an interrupt on any edge of the button
  2. In the interrupt handler, you're checking if you are pressed or released. If pressed, increase counter. If released, decrease it.
  3. If the counter is above a given threshold, call the GPIO pressed counter.
  4. If the counter is below a given (negative) threshold, call the GPIO released counter.

This adds a bit of latency to the processing, but is a bit safer to EMI discharge in the GPIO input (where you get a 000010000 like event). You can combine the with the other method for robustness.

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.