DebounceSwitchRK
|
Library for switch debouncing for Particle devices
Different types of buttons (momentary push button or toggle), active high or low, with or without pull resistors, are specified using the DebounceSwitchStyle
parameter to addSwitch().
Constant | Purpose |
---|---|
PRESS_LOW | Momentary switch to GND with an external pull-up |
PRESS_HIGH | Momentary switch to 3V3 with an external pull-down |
PRESS_LOW_PULLUP | Momentary switch to GND, along with using the MCU internal pull-up resistor |
PRESS_HIGH_PULLDOWN | Momentary switch to 3V3, along with using the MCU internal pull-up resistor |
TOGGLE | Toggle (on/off) switch that drives the input to GND or 3V3 |
TOGGLE_PULLDOWN | Toggle switch that connects the input to 3V3 in one position and disconnected in the other |
TOGGLE_PULLUP | Toggle switch that connects the input to GND in one position and disconnected in the other |
If you are designing a new circuit, the best option is to have your switch connect the GPIO to GND (not 3V3) and use on the of the MCU pull-up modes. So PRESS_LOW_PULLUP
for a momentary push-button switch or TOGGLE_PULLUP
for a toggle switch.
This library uses a thread and a callback approach. Even if the GPIO are polled (as is typically the case for hardware GPIO connected to the MCU), you will be notified of debounced press and tap events using a callback.
The callback has this prototype:
It's also possible to make the callback a class member function of a class you've created.
The callback is called from a worker thread with a small (1024 byte) stack, so you should avoid doing operations which block or use a lot of stack space.
Returning as quickly as possible without blocking is the best. If you must block, make sure you don't block more than 5 milliseconds total or the debouncing of the buttons and performance will be affected.
If you are using GPIO connected to another chip, you can provide a pollCallback to poll the GPIO values. For example, if you have an MCP23008 I2C GPIO expander, you can connect buttons to that.
The poolCallback has this prototype:
Note that the pollCallback returns a bool for the state of the GPIO (false = LOW, true = HIGH).
It's also possible to make the pollCallback a class member function of a class you've created.
If you are using an external GPIO you need to manage the pull resistors in your own code, so you'd use one of switch types PRESS_LOW
, PRESS_HIGH
, or TOGGLE
.
In some cases, it's inefficient to poll the switch. Polling happens every 5 milliseconds by default, which is fine for GPIO connected directly to the MCU. However, if the GPIO is on an I2C expander, it's still well within the capabilities of I2C, but it can be made more efficient.
The MCP23008 supports interrupt mode. When the external GPIO changes state, it sets an output that is read by a hardware GPIO on the MCU. This allows the MCU to determine if a change has occurred on the expander without having to do an I2C transaction; instead if can just read a hardware GPIO.
The MCP23008-RK library supports this mode, and allows for a callback to be called when the external GPIO state changes. This callback can then use the notify mode of the DebounceSwitchRK library to tell the debouncer what the current state of the switch signal is.
See the example in more-tests/02-mcp23008-interrupts:
There are a number of configurable parameters. They can be set globally, for future calls to addSwitch(), per-switch, if desired.
For example:
This changes the default, then adds a switch. If you change the default again, the existing switch will not be changed, but future calls to addSwitch() will be affected.
The same methods also work for on the DebounceSwitchState object, so you can set the parameters per-switch.
This is the simplest model for GPIO connected switches. Of note:
Be sure to call this from global setup(). It's required!
This is how you add a switch to be handled. You can add multiple switches in this manner.
The parameters of interest are:
D3
The pin the switch is connected toDebounceSwitchStyle::PRESS_LOW_PULLUP
The switch is a momentary (push-button) switch and connects the GPIO to GND (active low). It uses the MCU's hardware pull-up to handle the case where the switch is open (not connected) to bring the signal HIGH.switchCallback
The function below.This is the callback function:
The callback is called from a worker thread with a small (1024 byte) stack, so you should avoid doing operations which block or use a lot of stack space. This example just logs things to debug USB serial using Log.info
.
Note that there is no code needed from loop(). This means that if your code is blocking loop, it won't adversely affect the handling of buttons.
The callback can be a C++11 lambda function:
This is the actual lambda part:
This declared a function in-line to be called when the event occurs. The function has this prototype:
It's important to remember the callback part is execute later, not inline with the rest of the code.
The []
part is the lambda capture, which allows local variables and this
(for C++ class instances) to be captured for use within the lambda function. In this case, there is nothing to capture.