World Conquest Chronicles

World Conquest Chronicles

Robot Timer, v1.0.0

The library for implementing timers.

Major version. Implementing infinite timers. Support for handling overflowing the clock function.

Features

  • possibilities:
    • implementing infinite timers;
    • handling overflowing the clock function:
      • in case of overflow we use the average of the values obtained earlier;
  • types:
    • the ClockFunc type represents the clock function; it should return the current timestamp in seconds; the result is of the double type, so that the current timestamp can be fractional:
      • the clockForStdLibrary() function implements the ClockFunc type for the standard C++ library;
      • the clockForArduino() function implements the ClockFunc type for the Arduino environment;
    • the InfiniteTimer structure represents an infinite timer; the timer starts ticking from the moment it's created and continues to do so indefinitely; at the same time, the timer handles overflowing the clock function.

Examples

Blink on the cicada principle:

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

using namespace irenica_ideas::robot_timer;

constexpr auto LED_COUNT = 3;
constexpr auto LED_LOG_LENGTH = 7;
constexpr auto TOTAL_LED_LOG_LENGTH = LED_LOG_LENGTH * LED_COUNT
  + (LED_COUNT - 1) /* for commas */;
constexpr auto LED_VOLTAGE_LEVEL_LOG_FACTOR = 5;

uint8_t ledPins[LED_COUNT] = {11, 12, 13};
uint8_t ledVoltageLevels[LED_COUNT] = {LOW, LOW, LOW};
// use prime numbers for timer periods according to the cicada principle (see below)
// https://www.sitepoint.com/the-cicada-principle-and-why-it-matters-to-web-designers/
InfiniteTimer ledTimers[LED_COUNT] = {
  InfiniteTimer(0.29, clockForArduino),
  InfiniteTimer(0.37, clockForArduino),
  InfiniteTimer(0.53, clockForArduino)
};

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

  for (const auto& ledPin: ledPins) {
    pinMode(ledPin, OUTPUT);
  }
}

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

  char ledLogBuffer[TOTAL_LED_LOG_LENGTH + 1 /* for null terminator */ ] = {0};
  auto ledLogBufferOffset = 0;
  for (auto ledIndex = 0; ledIndex < LED_COUNT; ledIndex++) {
    // add a LED description for the Serial Plotter tool
    // in comma-separated "LED_<index>:<voltage-level>" format
    ledLogBufferOffset += snprintf(
      ledLogBuffer + ledLogBufferOffset,
      sizeof(ledLogBuffer) - ledLogBufferOffset,
      "LED_%d:%d",
      ledIndex,
      ledVoltageLevels[ledIndex] * LED_VOLTAGE_LEVEL_LOG_FACTOR
    );
    if (ledIndex != LED_COUNT - 1) {
      ledLogBuffer[ledLogBufferOffset++] = ',';
    }

    // check if the timer has ticked; any number of times per loop iteration
    if (!ledTimers[ledIndex].didItTick()) {
      continue;
    }

    ledVoltageLevels[ledIndex] = ledVoltageLevels[ledIndex] == LOW ? HIGH : LOW;
    digitalWrite(ledPins[ledIndex], ledVoltageLevels[ledIndex]);
  }

  Serial.println(ledLogBuffer);
}

Screenshots

Output of the Serial Plotter tool for blinking on the cicada principle: