acid-drop/lib/AceButton/examples/Stopwatch/Stopwatch.ino
2024-05-23 18:42:03 -04:00

155 lines
5.3 KiB
C++

/*
* A demo app that calculates the ammount of time taken by the
* AceButton::check() method. It acts like a stopwatch, supporting the following
* operations:
*
* - press: start the stopwatch
* - press: stop the stopwatch, printing out the result
* - long press: reset the stopwatch, allowing press to start the process again
*
* Each 'long press' alternates between enableAllEvents() and disableAllEvents()
* so that we can compare the timing of check() when all events are off (except
* Pressed and Released) and when all events are on.
*/
#include <AceButton.h>
using namespace ace_button;
// The pin number attached to the button.
const uint8_t BUTTON_PIN = 2;
// Create one button.
AceButton button;
// counters to determine the duration of a single call to AceButton::check()
uint16_t innerLoopCounter = 0;
uint16_t outerLoopCounter = 0;
unsigned long startMillis = 0;
unsigned long stopMillis = 0;
// states of the stopwatch
const uint8_t STOPWATCH_INIT = 0;
const uint8_t STOPWATCH_STARTED = 1;
const uint8_t STOPWATCH_STOPPED = 2;
// implements a finite state machine (FSM)
uint8_t stopwatchState = STOPWATCH_INIT;
bool allEventsEnabled = false;
void handleEvent(AceButton*, uint8_t, uint8_t);
void setup() {
delay(1000); // some boards reboot twice
Serial.begin(115200);
while (! Serial); // Wait until Serial is ready - Leonardo/Micro
Serial.println(F("setup(): begin"));
// Button uses the built-in pull up register.
pinMode(BUTTON_PIN, INPUT_PULLUP);
button.init(BUTTON_PIN);
// Configure the ButtonConfig with the event handler and enable LongPress.
// SupressAfterLongPress is optional since we don't do anything if we get it.
ButtonConfig* buttonConfig = button.getButtonConfig();
buttonConfig->setEventHandler(handleEvent);
buttonConfig->setFeature(ButtonConfig::kFeatureLongPress);
buttonConfig->setLongPressDelay(2000);
Serial.println(F("setup(): stopwatch ready"));
}
void loop() {
// We split the loop into an inner loop and an outer loop. The inner loop
// allows us to measure the speed of button.check() without the overhead of
// the outer loop. However, we must allow the outer loop() method to return
// periodically to allow the microcontroller to its own stuff. This is
// especially true on an ESP8266 board, where a Watch Dog Timer will
// soft-reset the board if loop() doesn't return every few seconds.
do {
// button.check() Should be called every 20ms or faster for the default
// debouncing time of ~50ms.
button.check();
// increment loop counter
if (stopwatchState == STOPWATCH_STARTED) {
innerLoopCounter++;
}
} while (innerLoopCounter);
// Each time the innerLoopCounter rolls over (65536), increment the outer loop
// counter, and return from loop(), to prevent WDT errors on ESP8266.
outerLoopCounter++;
}
// The event handler for the button.
void handleEvent(AceButton* /* button */, uint8_t eventType,
uint8_t /* buttonState */) {
unsigned long now = millis();
switch (eventType) {
case AceButton::kEventPressed:
if (stopwatchState == STOPWATCH_INIT) {
// enable or disable higher level events, to get different performance
// numbers
if (allEventsEnabled) {
enableAllEvents();
} else {
disableAllEvents();
}
Serial.println(F("handleEvent(): stopwatch started"));
startMillis = now;
innerLoopCounter = 0;
outerLoopCounter = 0;
stopwatchState = STOPWATCH_STARTED;
} else if (stopwatchState == STOPWATCH_STARTED) {
stopMillis = now;
stopwatchState = STOPWATCH_STOPPED;
unsigned long duration = stopMillis - startMillis;
uint32_t loopCounter = ((uint32_t) outerLoopCounter << 16) +
innerLoopCounter;
float microsPerLoop = duration * 1000.0f / loopCounter;
// reenable all events after stopping
enableAllEvents();
Serial.println(F("handleEvent(): stopwatch stopped"));
Serial.print(F("handleEvent(): duration (ms): "));
Serial.print(duration);
Serial.print(F("; loopCount: "));
Serial.print(loopCounter);
Serial.print(F("; micros/loop: "));
Serial.println(microsPerLoop);
// Setting 0 allows the loop() function to return periodically.
innerLoopCounter = 0;
}
break;
case AceButton::kEventLongPressed:
if (stopwatchState == STOPWATCH_STOPPED) {
stopwatchState = STOPWATCH_INIT;
Serial.println(F("handleEvent(): stopwatch reset"));
allEventsEnabled = !allEventsEnabled;
}
break;
}
}
void enableAllEvents() {
Serial.println(F("enabling high level events"));
button.getButtonConfig()->setFeature(ButtonConfig::kFeatureClick);
button.getButtonConfig()->setFeature(ButtonConfig::kFeatureDoubleClick);
button.getButtonConfig()->setFeature(ButtonConfig::kFeatureLongPress);
button.getButtonConfig()->setFeature(ButtonConfig::kFeatureRepeatPress);
}
void disableAllEvents() {
Serial.println(F("disabling high level events"));
button.getButtonConfig()->clearFeature(ButtonConfig::kFeatureClick);
button.getButtonConfig()->clearFeature(ButtonConfig::kFeatureDoubleClick);
button.getButtonConfig()->clearFeature(ButtonConfig::kFeatureLongPress);
button.getButtonConfig()->clearFeature(ButtonConfig::kFeatureRepeatPress);
}