Wilfried Klaas 40cb208ec2 initial commit in git, version 0.9 | 6 năm trước cách đây | |
---|---|---|
.. | ||
Examples | 6 năm trước cách đây | |
LICENSE | 6 năm trước cách đây | |
README.md | 6 năm trước cách đây | |
avdweb_Switch.cpp | 6 năm trước cách đây | |
avdweb_Switch.h | 6 năm trước cách đây | |
keywords.txt | 6 năm trước cách đây | |
library.properties | 6 năm trước cách đây |
Arduino library for debouncing switches and buttons. Supports detecting longPress and doubleClick. Supports defining callback functions.
Available at: https://github.com/avandalen/avdweb_Switch
Switches and push buttons need debouncing. It is straightforward to do this with software, using this library.
For a complete description see: http://www.avdweb.nl/arduino/hardware-interfacing/simple-switch-debouncer.html
Declare each switch or button, by indicanting its GPIO number:
Switch buttonGND = Switch(4); // GPIO 4
The library sets GPIO in input mode with an internal pull-up resistor by default. The constructor accepts several arguments including the particular input mode (e.g. without pull-up), whether voltage level high must be interpreted as on or off (argument polarity
must indicate the pushed voltage level), and the duration of the time periods that define the behaviour.
All switches have to be repeatedly polled individually to update the status. This is usually done in the loop()
function.
buttonGND.poll();
After refreshing the status, it can be checked with get functions. For example:
if(buttonGND.pushed()) Serial.print("pushed");
Any event occurs based on the deglitched and debounced pin signal. See below for details on this function of the library that happens transparently.
Each possible event (each switch-status) has its own get function:
It returns "true" if the pin voltage level changed, no matter the direction (from low to high or from high to low).
It returns "true" if the pin voltage agrees with the one defined by polarity
(which is LOW by default). Use only for toggle switches. It returns "true" as long as the switch is in the "on" position. The polarity of the switch in the "on" position has to be filled in correctly. There is no off() function, this is simply !on().
It returns "true" if a button was pushed (switched towards the on position). Use only for push buttons. Note that this provides instant response and can be used as "single-click" if "double-click" and "long-press" are not watched events. "Pushed" occurs simultaneously with "double-click" and "long-press".
It returns "true" if a push button was released (switched towards the off position), this will however rarely be used.
It returns "true" if a push button is pressed longer than 300ms (by default). Note that a longPress() always will be preceded by pushed() from the first push.
It returns "true" if a push button is double clicked within 250ms (by default). Note that a doubleClick() always will be preceded by pushed() from the first push.
The anteceding pushed() event can't be avoided, because to restrict the pushed() function to single clicks it would have to wait for a possible second click, which would introduce an annoying delay. So, the action on doubleClick() has to undo the previous action on pushed().
It returns "true" if a push button is clicked once and the requirements for doubleClick and longPress are not met. The event thus occur several miliseconds after the actual push, because it depends on the other events not happening after the push. Use this if three different interactions are needed in combination with doubleClick and longPress. Note that a singleClick() always will be preceded by pushed(). Use pushed() instead if immediate response is required and there is no interest in monitoring doubleClick and longPress.
See the example in the library for a complete working program.
Sudden short changes in the microcontroler power supply may create inexistent switched() events if the pin is polled in that instant. Deglitching is achieved because the software will not believe that a voltage change has happened (a swithed event) until the voltage remains in the new level for a minimum period. A voltage change will be ignored if it returns to the original level before that period.
Due to the elastic properties of the metals in the contacts they bounce away from each other after the initial contact creating false switched() events after an initial true switch, until the voltage stabilizes in the new level. Debouncing forces a refractary period after an initial switch, during which any voltage level change is ignored.
Callbacks can be used, instead of needing to check with an if
statement whether the relevant event has occurred after calling switch.poll()
.
With a callback registered, Switch will run the defined function when the conditions are met at the time poll()
is called. Calling poll()
periodically is the only requirement.
First, define a function with the action you want to perform, with no return type (void) and one argument, a pointer to some reference (or use nullptr if you don't need it.):
void foo(void* ref) {
//your code;
}
... and then call one of the "set callback" methods in the setup()
function, like so:
void setup() {
... // Other setup code
...
int reference;
switch.setPushedCallback(&foo, &reference);
...
}
The available callback setting functions are setPushedCallback()
, setReleasedCallback()
, setLongPressCallback()
, setDoubleClickCallback()
, and setSingleClickCallback()
which allow defining the functions that will be called on such events. If using a toggle switch and not a push button, the "pushed" event will be of interest when the switch is turned on, and "released" when it is turned off.
If the conditions for more than one event occur simultaneously and there are callback functions registered for them, they will be executed in the order of the functions above.
See the example in the library for a complete working program.
The poll instruction must be called at least 50 times per second, i.e. every 20ms; it takes about 20us in Arduino.
The button states are saved till the next poll. Then all previous button states will be cleared, so the button states must be read every poll interval, after calling the poll function.
Reading a button several times within a poll interval gives the same value, so reading doesn't clear the button state.
Polling buttons has a high priority and should be done often. Slow functions such as Serial.print() may disrupt the timing.
Polling could be done in a function triggered by a timed interrupt. Remember to keep the subsequent button actions short as you would do with any code in interrupts.
For Arduino see here how to use an ISR for polling the buttons:
#include <Arduino.h>
#include "avdweb_Switch.h"
#include <FrequencyTimer2.h>
Switch speedUpBtn(1);
Switch speedDownBtn(2);
Switch buttonLeft(3);
Switch buttonRight(4);
void setup(void)
{ Serial.begin(9600);
FrequencyTimer2::setPeriod(1000);
FrequencyTimer2::setOnOverflow(timer2ISR);
}
void loop(void)
{ printAll(); // run slow functions in loop()
}
void timer2ISR()
{ pollAll(); // polling buttons has priority
buttonActions();
}
// you should implement pollAll(), buttonActions(), and printAll()
For ESP8266 use the Ticker library.
With the Switch library, you can use all button events at the same time with the same button. For example pushed(), released(), doubleClick() and longPress(). To see an example of what can be achieved with several button events in order to perform different functions, run Windows Explorer: a single click selects a file and a double click opens it.
A long-press generates first a pushed event and after 300ms (by default) the longPress event. This is not a shortcoming but a logical consequence. We can, of course, not always wait 300ms to see if a push might be a long push.
The same happens with doubleClick, which also generates two pushed() events. When doubleClick is used, ignore the second pushed() result or don't call pushed(). When doubleClick is not needed, simply don't call doubleClick().
If these three events must be used toghether the best strategy is to stick to their get functions and avoid using pushed().
There is nothing needed beyond the switches, just connect the switches between the ground and a digital pin.
This is technically speaking the best solution and it is taken by the library as default. An external pull-up resistor is not needed but allowed.
For switches connected to the Arduino power supply, the settings are: polarity = HIGH and pinmode = INPUT, which disables the internal pull-up resistor. Note that we need external pull-down resistors of about 10k here.
Post questions on the Arduino board and let me know, I will reply there.
Post issues on the github repository.
Normally, just debouncing is used. But debouncing doesn't make the software insensitive to noise pulses, which could lead to dangerous situations: if there is a poll() at the moment of a noise pulse, the software can detect an activated switch. To prevent this, a deglitch function is added now: during a "deglitchPeriod", all input values have to be equal.
The software debounce algorithm is based on the following assumptions; the 50ms (by default) is the so-called debounce period:
If the above assumptions are met, the software debounce algorithm can be quite simple: a switch event is only accepted when the elapsed time since the last switch event is larger than the debounce period.
A debounce period of 50ms is a safe value; it doesn't hurt the reaction time, and will handle even bad switches.
See the following pseudocode:
if((current_deglitched != previous_debounced) & ((current_ms - last_switchedTime) >= debouncePeriod)) current_debounced = current_deglitched;
// otherwise current_debounced stays the same as previous_debounced
Several discrete signals (updated at poll times) are created. The raw signal is deglitched, the later debounced, and that one in turn is processed to generate a signal for each one of the events.
..........................................DEGLITCHING..............................
________________ _
on | | | | _
| | | | | |
| |_| |___| |__
analog off_____|_____________________________|____________________________
________________ _ _
input _____| |_| |___| |_______________________________
poll ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
equal 0 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
deglitchPeriod <--------><-- <-- <- <--------><--------><--------
___________________________
deglitched _________________| |__________________
deglitchTime ^ ^ ^ ^ ^ ^ ^
..........................................DEBOUNCING.............................
debouncePeriod <-------------------------------->
_________________________________
debounced _________________| |____________
_ _
_switched _________________| |_______________________________| |__________
switchedTime ^ ^
**********************************************************************************
........................................DOUBLE CLICK..............................
__________ ______
debounced ________| |_______| |_____________________________
poll ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
_ _
pushed _________| |________________| |__________________________________
pushedTime ^ ^
_ _
released ____________________| |____________| |___________________________
releasedTime ^ ^
doubleClickPeriod <------------------------------------->
_
_doubleClick ___________________________| |__________________________________
........................................LONG PRESS................................
___________________________
debounced ________| |___________________________
poll ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
longPressPeriod <--------------->
_ _
_switched _________| |_________________________| |________________________
__________
longPressDisable ___________________________| |_________________________
_
_longPress ___________________________| |__________________________________
........................................SINGLE CLICK..............................
__________ ______
debounced ________| |_______________________________| |_____
poll ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
longPressPeriod <--------------->
doubleClickPeriod <------------------------------------->
_ _ _ _
_switched _________| |_______| |_____________________________| |____| |___
_____
singleClickDisable______________________________________________| |__________
_
_singleClick _______________________________________________| |______________
See also: A Guide To Debouncing
Copyright (C) 2012 Albert van Dalen
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This document is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.