Multi-tasking and OOP...

So, if you have the code you need to do a Welder on one Arduino and you have the code to do another project on another Arduino, like turning the bathroom light on and off every 3 minutes, how do you combine them into one project to run on a single Arduino? If you put all your code into the same loop() function, one project's after the other, like in:

void loop() {
  // simple welder
  digitalWrite( welderPin, HIGH );
  delay( random( 100 ) );
  digitalWrite( welderPin, LOW );
  delay( random( 100 ) );

  // simple bathroom light
  digitalWrite( bathroomLEDPin, HIGH );
  delay( 1000 * 60 * 3 );
  digitalWrite( bathroomLEDPin, LOW );
  delay( 1000 * 60 * 3 );
}


you will notice that your welder flashes something random, but only once every 6 minutes! That is because it takes the loop() to repeat just a little bit longer than 6 minutes. And the problem with this, is simply the delay() function preventing anything else from happening. So venture over for a few pages to read if you are curious to learn this from the professionals, or just stick around here and bite it out!

The easiest solution to this problem is to use the millis() function to tell you how many milliseconds have gone by since you turned the Arduino on. With a disclaimer, that about every 50 days, this counter overflows and starts at 0 again, but we don't leave our layouts on for more than one night, right? So ignore that then. The idea is, that if I need to turn something on or off every 3 minutes, I could simply ask as often as I want, "did 3 minutes go by yet?" And if it did, I can then do my change or update like turning the LED from ON to OFF or vice versa, then write down the current time and start asking again: "are we there yet"! :)

So, here we go:

// the number of the LED pin (notice that #define does not use an '=' between ledPin and 13,
//   think of #define as a search and replace that finds every 'ledPin' and swaps it with '13')

#define ledPin 13

// since 3 * 60 * 1000 is 180000ms for 3 minutes
#define UPDATEAFTER 180000 

unsigned long lastMillis;
unsigned long nowMillis;

int bathroomLit = LOW;

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);

  // capture the time now to initialize lastMillis
  lastMillis = millis();
} // setup()

void loop() { // referred to later as CODE #001
  nowMillis = millis();   // how many milliseconds since power up
  if ( ( nowMillis - lastMillis ) > UPDATEAFTER ) {
    // code to change LED, if HIGH: output LOW, else output HIGH, and also keep track of it in bathroomLit
    if ( bathroomLit == HIGH ) {

      bathroomLit = LOW;
      digitalWrite( ledPin,
bathroomLit );
    } else {

      bathroomLit = HIGH;
      digitalWrite( ledPin,
bathroomLit );
    } // if, else Lit

    lastMillis = now
Millis; // save the current time, so we can use that to find when UPDATEAFTER has expired next time
  } // if UPDATEAFTER
} // loop()

Still following? Well, we only have the bathroom light in here now, but you can already see that there is no delay() method used, so the processor is not going to get stuck somewhere waiting for time to go by! Also take note very early here, that this is not the way to time the landing of a space probe on Mars while blinking the indicator lights on the re-entry module! You should use separate CPUs on that mission! But if we are off here by 1, 5 or 10 microseconds turning the bathroom light on, we might just survive!!!

Now, if you want a different ON and OFF time for your light, please head over to the Adafruit link, they have the example ready! You simply check of the ON time has expired while the light is ON and if the OFF time has expired when the light is OFF.

Instead of filling in the welder code in below the "if ( ( nowMillis - lastMillis ) > UPDATEAFTER ) { }" to check if some random time has expired since lastMillis to blink the welder again (you could try that for homework), we are going to show an easier way to implement this with some other benefits. It is called OOP, Object Oriented Programming. And don't worry, if you have moved a servo motor with an Arduino, you have already used this technology:

#include <Servo.h> 
 
Servo myServo;  // create servo object

void setup() { 
  myServo.attach( 9 );  // attaches the servo on pin 9, executing an object's method to set some data and a few more things
} // setup()
 
void loop() { 
  myServo.write( 90 ); // using another object method move the servo motor, by changing the pulses sent to it,
                       // things happening behind the scenes that we don't care about
} // loop()

myServo is an object instantiated from the Servo class, big words, but still true! The easy way to think about objects in OOP are that they are data things that have their own methods (or functions), so, for example, instead of saying digitalWrite( ledPin, HIGH ); we could create a Class LED with an On() method and when we instantiate an LED object with something like "LED myLED = LED( 9 );", all we need to do in the future is to call myLED.on() to turn the LED on, and we then simply don't care how it is turned on! Just like you don't need to know how myServo moved to some position 90 by calling "write();".

Unrelated note, if you ever get an error verifying or compiling the code saying something like: "Cannot run program "C:\Program Files (x86)\Arduino/hardware/tools/gcc-arm-none-eabi-4.8.3-2014q1/bin/arm-none-eabi-g++": CreateProcess error=2, The system cannot find the file specified"...first thing to check is which board do you have set as your target, should be Uno or Nano, if you are a beginner like me. ]

To get you getting used to OOP, we will implement the same bathroom LED code as above first:

class LEDCycler {
  int ledPin;               // which pin is used for this LED object
  unsigned long updateTime; // we are using a variable this time, so you could change it in code later if you like
                            // versus the #define'd UPDATEAFTER used in the loop's code to compare when to change,
                            // or to have more than 1 LEDCycler with different update times

  unsigned long lastMillis; // last time LED was updated
  int ledLit;               // keeps track of lit or not, so we can toggle it
 
  public:
    // the constructor is run when the object is created
    LEDCycler( int pin, unsigned long time ) {
      ledPin = pin;       // set the pin for this guy
      pinMode( ledPin, OUTPUT ); // make him an output
 
      updateTime = time;  // how often to update   
      ledLit = LOW;       // start out low!
      lastMillis = 0;     // of course, starting with something known
    } // constructor
  
    void Toggle() {
      if ( ledLit == LOW ) ledLit = HIGH; else ledLit = LOW;   // swap lit states
      digitalWrite( ledPin, ledLit );                          // one statement to write whichever way it is set
    } // Toggle
  
    void Update() {
      unsigned long nowMillis = millis();
      if ( ( nowMillis - lastMillis ) > updateTime ) {
        Toggle();               // call my own method to change my state
        lastMillis = nowMillis; // reset the count
      } // if updateTime
    } // Update

}; // Class LEDCycler


LEDCycler myBathroomLED( 13, 180000 );

void setup() {
  // waau, nothing here
} // setup()

void loop() {
  myBathroomLED.Update();   // and only one line here!!
} // loop()


So, before we add the Welder, what do you think would happen if we change the bottom 9 lines to add:

LEDCycler myBathroomLED( 13, 180000 );
LEDCycler myDinningroomLight( 10, 3*180000 );
LEDCycler myStreetLight( 13, 12*180000 );

void setup() {
  // waau, still nothing here
} // setup()

void loop() {
  myBathroomLED.Update(); 
  myDinningroomLight.Update(); 
  myStreetLight
.Update(); 
} // loop()

See the magic? No need to write two extra sections of code to evaluate millis() for each LED like shown at CODE #001 above. One of the big benefits of OOP is the re-usability of code, if you follow the guide here to split and save your LEDCycler class into the LEDCycler.h and LEDCycler.cpp files, now you would have a library you could use just like from Servo.h:

#include <LEDCycler.h>

LEDCycler myBathroomLED( 13, 180000 );
LEDCycler myDinningroomLight( 10, 3*180000 );
LEDCycler myStreetLight( 13, 12*180000 );

void setup() {
  // nothing here
} // setup()

void loop() {
  myBathroomLED.Update(); 
  myDinningroomLight.Update(); 
  myStreetLight
.Update();
} // loop()

And now you can imagine creating a Class On() and Off() method, so you could use
myBathroomLED.On();   or  myBathroomLED.Off();  now anywhere.

And what if you want the light to flicker as it turns on or off, or fade in and fade out, you simply modify the code in the Class one time and all three lights will do the same fade in and out! But you might not want the bathroom and dinning room light to be fading, so you create a new Class, FadingLEDCycler that is based on LEDCycler and has all its features called inheritance, you just add what you need or overwrite what needs to change (the On and Off to fade) and now you have

#include <LEDCycler.h>
#include <FadingLEDCycler.h> // where the class starts with
                // class FadingLEDCycler : public LEDCycler {
                //   public:
                //   int fadeTime;
                //   FadingLEDCycler( int pin, unsigned long time, int fTime ) : LEDCycler (pin, time) {
// constructor
                             //
to inherit everything from LEDCycler

LEDCycler myBathroomLED( 13, 180000 );
LEDCycler myDinningroomLight( 10, 3*180000 );
FadingLEDCycler myStreetLight( 13, 12*180000, 3000 ); // where 3000 would specify the milliseconds it takes to fade in or out

void setup() {
  // nothing here
} // setup()

void loop() {
  myBathroomLED.Update(); 
  myDinningroomLight.Update(); 
  myStreetLight
.Update();
} // loop()

Ok, lets add the Welder class as promised:

class Welder {
  int ledPin;                            // which pin is used for this LED object

  public:
  int nextRandomWait;
  unsigned long lastMillis;          // last time LED was updated
  int ledLit;                            // keeps track of lit or not, so we can toggle it

  // the constructor is run when the object is created
  Welder( int pin ) {
    ledPin = pin;                       // set the pin for this guy
    pinMode( ledPin, OUTPUT );   // make him an output
   
ledLit = LOW;                      // start out low!
    lastMillis = 0;                      // of course, starting with something known
    GenerateNextRandomWait();  // predetermine the wait
 
// constructor

  void Toggle() {
    if ( ledLit == LOW ) ledLit = HIGH; else ledLit = LOW; // swap lit states
    digitalWrite( ledPin, ledLit ); // one statement to write whichever way it is set
  } // Toggle

  void GenerateNextRandomWait() {
    nextRandomWait = random( 0, 100 ); // generate a random number including 0 to 99
  } // GenerateNextRandom

  void Update() {
    unsigned long nowMillis = millis();
    if ( ( nowMillis - lastMillis ) > nextRandomWait ) {
      Toggle();                           // call my own method to change my state
      GenerateNextRandomWait(); // a new random before the next toggle!
     
lastMillis = nowMillis;           // reset the count
   
// if updateTime
  } // Update
}; // Class Welder

Welder myWelder( 9 ); // create a Welder object using output pin 9

void setup() {
  // nothing here
// setup()

void
loop() {
   myWelder.Update();
// loop()


and when you have all this typed in and turned into a Welder library, remember to add the bathroomLED back to your main program shown below:
(you could also just paste the code for the two classes into the same Sketch with the setup() and loop()
and remove the #include's)


#include <LEDCycler.h>
#include <Welder.h>

LEDCycler myBathroomLED( 13, 40000 );   // create a LEDCycler object using output pin 13
Welder myWelder( 9 );                  // create a   Welder  object using output pin  9

void setup() {
  // nothing here
} // setup()

void loop() {
  myWelder.Update(); 

  myBathroomLED.Update();
} // loop();


Amazing how much shorter, faster and more efficient the process is creating and re-using this code is now! And the good news is, if you were planning a future career in software development, almost all the modern languages use or can use OOP: C++, Java, C#, Objective C, Python, Perl, etc., etc.! So your newly acquired skill has potential!!!

Things to do:
  - Make the Bathroom light on and off cycle different.
  - Let the Arc Welder stop for a few random moments to move the piece being worked on,
  -   and make sure the light is off when the welder takes a break!

(or see the file attached below, but try it first yourself, you have time!)

ċ
MultitaskBathroomAndWelder2.ino
(6k)
Gert (TxAdmin) Muller,
Jul 14, 2015, 9:11 AM
Comments