Skip to content

Simple task walk through

Michael Miller edited this page Mar 25, 2016 · 2 revisions

or, How to blink a LED without using delay()

NOTE: There is a BlinkUsingCustomTask.ino as an example that demonstrates another approach. You may want to review that version as well.

First, lets look at the standard example Blink.ino; I modified it lightly to have different delays so its easier to reference them but that was the only change.

void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(2000);              // wait for two seconds
}

To convert this, the first to think about is removing the delays(). Basically, we have stuff that happens before the wait for a second. Then we have stuff that happens before the wait for two seconds. Then it loops. If we break it down that way, we get...

#include <Task.h>
TaskManager taskManager;

class TaskBlinkLedOn : public Task {
public:
    TaskBlinkLedOn(Task* taskOff) : // pass any custom arguments you need
        Task(1000), // the time from the first delay
        _taskOff(taskOff)
    { };

private:
    Task* _taskOff;

    virtual bool OnStart() {
        digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
        return true; // nothing we did would cause us not to start, so return true
    }

    virtual void OnUpdate(uint32_t deltaTime) {
        // if we don't stop this task, this method will continue to get called every
        // second
        taskManager.StopTask(this); 
        // now start the task to blink the LED off
        taskManager.StartTask(_taskOff);
    }
};

class TaskBlinkLedOff : public Task {
public:
    TaskBlinkLedOff(Task* taskOn) : // pass any custom arguments you need
        Task(2000), // the time from the second delay
        _taskOn(taskOn)
    { };

private:
    Task* _taskOn;

    virtual bool OnStart() {
        digitalWrite(13, LOW);   // turn the LED off (LOW is the voltage level)
        return true; // nothing we did would cause us not to start, so return true
    }

    virtual void OnUpdate(uint32_t deltaTime) {
        // if we don't stop this task, this method will continue to get called every
        // two seconds
        taskManager.StopTask(this); 
        // now start the task to blink the LED on
        taskManager.StartTask(_taskOn);
    }
};

// due to needing to cross reference, we need to forward declare one
extern TaskBlinkLedOn  taskBlinkOn;

TaskBlinkLedOff taskBlinkOff(&taskBlinkOn);
TaskBlinkLedOn  taskBlinkOn(&taskBlinkOff);

void setup() {
    // initialize digital pin 13 as an output.
    pinMode(13, OUTPUT);
    taskManager.StartTask(&taskBlinkOn); // start the blinkon task
}

void loop() {
    taskManager.Loop();
}

Its a little more verbose, but now you don't have a delay, and further it can be easily copied into other sketches. Well, maybe not yet easy, but lets work on that next.

To clean up the code a little, lets move the Led stuff into another file. You can create a new file or "tab" by selecting "New Tab" in the tab menu and enter a name for the new tab. Do that now and name it BlinkLed.h; the .h at the end is required.

In this new file, lets create a new wrapper class for the two tasks we just created to make it easier to abstract the work. Move the two already created task classes to the top and include those also, but I have omitted them for brevity.

const uint8_t LedPin = 13;
...
// insert the task classes from above, replace the 13 with the constant LedPin while you are at it
...

class BlinkLed {
public:
  BlinkLed() :
    _taskOn(&_taskOff), // no need for the forward reference stuff as they are now members in this class
    _taskOff(&_taskOn)
  { }
  
  void begin() {
    pinMode(LedPin, OUTPUT);
  }

  void startBlinking() {
    taskManager.StartTask(&_taskOn); // start the blinkon task
  }

  void stopBlinking() {
    taskManager.StopTask(&_taskOn);
    taskManager.StopTask(&_taskOff);
  }

private:
  TaskBlinkLedOn _taskOn;
  TaskBlinkLedOff _taskOff;
};

Now the main sketch is simplified to just the following...

#include <Task.h>
TaskManager taskManager;

#include "BlinkingLed.h"

BlinkLed blinkLed;

void setup() {
    blinkLed.begin();
    blinkLed.startBlinking();    
}

void loop() {
    taskManager.Loop();
}

Now you can copy the BlinkingLed.h to any other sketches you want to use it on.
To make it more versatile, you may want to be able to adjust the timing on the blink on the fly. This is easily done by adding the following public method to the new BlinkLed class

  void setBlinkSpeed(uint16_t onTime, uint16_t offTime) {
    _taskOn.setTimeInterval(onTime);
    _taskOff.setTimeInterval(offTime);
  }

and now you can just call this setBlinkSpeed() to adjust the timing on the blinking, so a fast blink means one thing versus a normal slow blink.

The next step would be to create a library with the BlinkingLed.h which means any fixes to it would get used by your other sketches; but that is beyond the scope of this walkthrough.

Clone this wiki locally