Object Timeslicer

A handy way to code interactions in a fairly complex environment is to use C++ objects. The idea is that each object has a setup() and a loop() method. In your setup, you call the setup method of each, and in your loop, you call the loop method of each. Each object in its loop method does whatever it has to do - potentially by calling methods on other objects to signal changes of state. These other objects potentially deal with the change right then, or they store something internally to be handled when their own loop() method gets called.

It can be a bit ugly to call your time-slice method on each object. One way to deal with this is to create a superclass with virtual setup() and loop() methods, and to initialize a table of pointers to these objects. Bu there is a neater way.

In the sketch below, the Runnable abstract class builds a linked list of all runnable objects using its constructor. The main setup() and loop() methods iterate through this list. Below that is the actual business end of this demo. The demo creates four objects. Three blinkers (on pins 8, 9, and 10) and an object that reads analog 0 and sets the blink rate of the blinker on pin 10 accordingly.

The objects are wired to their pins and to the other objects they interact with in their constructors. Note the use of C++ references to wire together the BlinkerSpeedShifter to the Blinker that it controls.

The result is a network of objects, each with a role and each with its own internal state and set of variables.

class Runnable {
  public:
    Runnable *nextRunnable;
    Runnable();
    virtual void setup() {}
    virtual void loop() {}
};

Runnable *firstRunnable = NULL;

Runnable::Runnable() {
  nextRunnable = firstRunnable;
  firstRunnable = this;
}

void setup() {
  for (Runnable *r = firstRunnable; r; r = r ->nextRunnable) {
    r->setup();
  }
}

void loop() {
  for (Runnable *r = firstRunnable; r; r = r ->nextRunnable) {
    r->loop();
  }
}

class Blinker : public Runnable {
    const int pin;
    unsigned long dur;
    unsigned long ms;
  public:

    Blinker(int pin, unsigned long dur) :
      pin(pin),
      dur(dur) {
    }

    void setup() {
      pinMode(pin, OUTPUT);
      ms = millis();
    }

    void loop() {
      if (millis() - ms > dur) {
        digitalWrite(pin, !digitalRead(pin));
        ms = millis();
      }
    }

    void setDuration(unsigned long newDur) {
      dur = newDur;
    }
};

class BlinkerSpeedShifter : public Runnable {
    const int analogPin;
    Blinker &blinker;

  public:
    BlinkerSpeedShifter(int analogPin, Blinker &blinker) :
      analogPin(analogPin),
      blinker(blinker) {
    }

    void loop() {
      blinker.setDuration(analogRead(analogPin));
    }
};

Blinker blinkers[] = {Blinker(8, 800), Blinker(9, 900), Blinker(10, 500)};

BlinkerSpeedShifter element_2_shifter(0, blinkers[2]);
 

Share