World Conquest Chronicles

World Conquest Chronicles

Robot Button, v1.0.0

The library for implementing buttons.

Major version. Implementing individual buttons. Support for bypassing contact bounce.

Features

  • possibilities:
    • implementing individual buttons:
      • a delayed polling approach is used to bypass contact bounce;
      • a delay between polls is realized without blocking the main cycle (via the Robot Timer library);
  • structures:
    • the TimerControlledButton structure represents an individual button; it uses a built-in non-blocking timer to bypass contact bounce.

Examples

Button modes:

#include <TimerControlledButton.h>
#include <ClockFunc.h>
#include <stdint.h>

using namespace irenica_ideas::robot_button;
using namespace irenica_ideas::robot_timer;

constexpr auto BUTTON_PIN = 12;
// the Arduino documentation recommends 50 ms as the debounce time:
// https://docs.arduino.cc/built-in-examples/digital/Debounce/
constexpr auto BUTTON_UPDATE_PERIOD = 0.05;
constexpr auto BUTTON_LOG_LENGTH = 56;
constexpr auto BUTTON_LOG_FACTOR_FOR_RAW_INPUT = 2;
constexpr auto BUTTON_LOG_FACTOR_FOR_STATE = 3;
constexpr auto BUTTON_LOG_FACTOR_FOR_PRESSING = 4;
constexpr auto BUTTON_LOG_FACTOR_FOR_RELEASING = 5;

auto button = TimerControlledButton(
  BUTTON_PIN,
  BUTTON_UPDATE_PERIOD,
  clockForArduino
);

void setup() {
  Serial.begin(9600);

  button.initialize();
}

void loop() {
  // update the button; only once per loop iteration
  button.update();

  char buttonLogBuffer[BUTTON_LOG_LENGTH + 1 /* for null terminator */ ] = {0};
  snprintf(
    buttonLogBuffer,
    sizeof(buttonLogBuffer),
    "digitalRead:%d,isPressed:%d,didItPressed:%d,didItReleased:%d",
    // raw input; due using a pull-up resistor the button logic is inverted, see:
    // https://docs.arduino.cc/tutorials/generic/digital-input-pullup
    (digitalRead(BUTTON_PIN) == LOW) * BUTTON_LOG_FACTOR_FOR_RAW_INPUT,
    // check if the button is pressed; any number of times per loop iteration
    button.isPressed() * BUTTON_LOG_FACTOR_FOR_STATE,
    // check if the button has been pressed; any number of times per loop iteration
    button.didItPressed() * BUTTON_LOG_FACTOR_FOR_PRESSING,
    // check if the button has been released; any number of times per loop iteration
    button.didItReleased() * BUTTON_LOG_FACTOR_FOR_RELEASING
  );

  Serial.println(buttonLogBuffer);
}

Different types of buttons:

#include <TimerControlledButton.h>
#include <ClockFunc.h>
#include <stdint.h>

using namespace irenica_ideas::robot_button;
using namespace irenica_ideas::robot_timer;

constexpr auto LED_COUNT = 3;
constexpr auto LED_TRIGGERED_BY_STATE = 0;
constexpr auto LED_TRIGGERED_BY_PRESSING = 1;
constexpr auto LED_TRIGGERED_BY_RELEASING = 2;
// the Arduino documentation recommends 50 ms as the debounce time:
// https://docs.arduino.cc/built-in-examples/digital/Debounce/
constexpr auto BUTTON_UPDATE_PERIOD = 0.05;

uint8_t ledPins[LED_COUNT] = {8, 9, 10};
uint8_t buttonPins[LED_COUNT] = {11, 12, 13};

uint8_t ledVoltageLevels[LED_COUNT] = {LOW, LOW, LOW};
TimerControlledButton buttons[LED_COUNT] = {
  TimerControlledButton(
    buttonPins[LED_TRIGGERED_BY_STATE],
    BUTTON_UPDATE_PERIOD,
    clockForArduino
  ),
  TimerControlledButton(
    buttonPins[LED_TRIGGERED_BY_PRESSING],
    BUTTON_UPDATE_PERIOD,
    clockForArduino
  ),
  TimerControlledButton(
    buttonPins[LED_TRIGGERED_BY_RELEASING],
    BUTTON_UPDATE_PERIOD,
    clockForArduino
  )
};

void setup() {
  for (auto ledIndex = 0; ledIndex < LED_COUNT; ledIndex++) {
    pinMode(ledPins[ledIndex], OUTPUT);
    buttons[ledIndex].initialize();
  }
}

void loop() {
  // update all the buttons; only once per loop iteration
  for (auto& button: buttons) {
    button.update();
  }

  // check if the button is pressed; any number of times per loop iteration
  ledVoltageLevels[LED_TRIGGERED_BY_STATE] =
    buttons[LED_TRIGGERED_BY_STATE].isPressed() ? HIGH : LOW;

  // check if the button has been pressed; any number of times per loop iteration
  if (buttons[LED_TRIGGERED_BY_PRESSING].didItPressed()) {
    ledVoltageLevels[LED_TRIGGERED_BY_PRESSING] =
      ledVoltageLevels[LED_TRIGGERED_BY_PRESSING] == LOW ? HIGH : LOW;
  }

  // check if the button has been released; any number of times per loop iteration
  if (buttons[LED_TRIGGERED_BY_RELEASING].didItReleased()) {
    ledVoltageLevels[LED_TRIGGERED_BY_RELEASING] =
      ledVoltageLevels[LED_TRIGGERED_BY_RELEASING] == LOW ? HIGH : LOW;
  }

  for (auto ledIndex = 0; ledIndex < LED_COUNT; ledIndex++) {
    digitalWrite(ledPins[ledIndex], ledVoltageLevels[ledIndex]);
  }
}

Screenshots

Output of the Serial Plotter tool for the button modes: