arduino up-arrow arduino Arduino page
Dual arduinos in control panel hdr

What is object oriented programming (or OOP) and why should I care?



In traditional programming there are data and functions. The functions do computations on the data. Simple huh?

In object oriented programming some data and functions are grouped together into an object. Objects are of a CLASS. A class can be instantiated to create class instances, or objects. An object is created in much the same way as a variable would.

Let's consider a timer. In a non-orbject oriented program there are variables

Program 1 - Flashing a LED using a simple timer
   
    unsigned long  timerPeriod;
    unsigned long  timerStartTime;
   
    uint8_t  ledPin;
    uint8_t  ledState;
  
    void setup(void) {
      ledPin = 13; // the built in led pin on a Pro-Mini 
      pinMode( ledPin, OUTPUT);
      ledState = 0;
      digitalWrite( ledPin, ledState );
      timerStartTime = millis();   // start of time period is current time in milliseconds
      timerPeriod = 500;           // 500 milli-second time period duration
    }
    
    void loop(void) {
      unsigned long crntTime;
      
      crntTime = millis(); // get current time
      
      //
      // If our timer's duration has elapsed since we started this timing cycle
      // change the state of our led
      //
      if (crntTime-timerStartTime >= timerPeriod) {
        ledState ^= 1;  // change led state from on to off (or off to on)
        digitalWrite( ledPin, ledState );
        timerStartTime = crntTime;
      }
    }
    
    

Program 1 doesn't look very compilcated at all. What's wrong with it and why should we learn object oriented programming?

Well, nothing really. However, let your imagination run wild. Suppose you have five or six (or sixteen) timers all running at once. Wanna bet that you didn't make a cut and paste error somewhere resuling in using the wrong variables for a timer or led state?

Well, you say. I could alway put the timer and led variables in an array.

That's true, but you still have that arithmetic expression out in the open taking up code space. And are you going to have sixteen LEDs all doing the exact same thing? So you'll need different code for each timer depending on its purpose.

What if we could hide the internals of the timer's operation? That would greatly simplify reading the loop() function as there wouldn't be anywhere near as many lines of code there in loop().

Program 2 - Flashing a LED using a timer object
    
    //
    // Create a class for our timing needs
    //
    class myTimer
    {
      public:
        myTimer(void);
        void start( unsigned long d );  // start timing with duration d
        boolean done( void );           // returns true if timer has completed  
      private:
        unsigned long startTime;        // start time (from millis())
        unsigned long timerDuration;    // timer duration in milliseconds
        boolean active;                 // true while timer is running
    };
    
    //
    // Constructor function inializes class member variables
    //
    myTimer::myTimer(void) {
      startTime = millis();
      timerDuration = 0;
      active = false;
    }
   
    //
    // start function sets duration and makes timer active
    //
    void myTimer::start( unsigned long d ) {
      timerDuration = d;
      startTime = millis();
      active = true;
    }
    
    //
    // done function returns true if the timer has completed
    //
    boolean myTimer::done( void ) {
      unsigned long crntTime;
      
      if (active) {
        crntTime = millis();
        if (crntTime - startTime >= timerDuration) {
          active = false;
          return true;
        }
      }
      return false;    // timer not done
    }
    
    
    myTimer  timer1;  // instantiate a timer object
    
    uint8_t  ledPin;
    uint8_t  ledState;
    
    void setup(void) {
      ledPin = 13; // the built in led pin on a Pro-Mini 
      pinMode( ledPin, OUTPUT);
      ledState = 0;
      digitalWrite( ledPin, ledState );
      timer1.start( 500 );
    }
    
    void loop(void) {
      if (timer1.done()) {    // has the timer finished?
        timer1.start( 500 );  // restart the timer
        ledState ^= 1;  // change led state
        digitalWrite( ledPin, ledState );
      }
    }
    

It may look like a lot of extra code got added in the myTimer class, but it can be moved out of your Arduino sketch file (.ino) into it's own files and reused in other sketches. The myTimer class also hides details - the somewhat cryptic computation to see if our time is up and the inernal variables are hidden. All that needs to be seen in your sketch is the myTimer instantiation and the calls to timer.start() and timer.done().

the class definition was included in the sketch file to make it easier to see what's going on without needing to hop around between files while you're trying to figure out this class definition stuff. Normally myTimer would be placed in two files:

  • myTimer.h - class header where class member functions and data are defined.
  • myTimer.cpp - class body where class member functions are implemented.

Some classes are large - hundreds or thousands of lines of source code. Keeping the .h and .cpp files separate for each class helps code maintainability.

Oh yeah, there is still an issue: we haven't eliminated the need to keep track of which timer is associated with which led. Let's do that in our next example.

Program 3 - Flashing four leds using timer and led classes
    
    //
    // Use the timer class from example 2 to create a led flashing class
    //
    #include <myTimer.h>
    
    //
    // Create a class for our led needs
    //
    class myLed
    {
      public:
        myLed( uint8_t pin, unsigned long ontime, unsigned long offtime );
        void Update(void);        // led state machine
      private:
        uint8_t  ledPin;          // arduino pin # for our led
        uint8_t  ledState;        // current led state
        myTimer  ledTimer;        // timer duration in milliseconds
        unsigned long onTime;
        unsigned long offTime;
    };
    
    //
    // Constructor function inializes class member variables
    //
    myLed::myLed( uint8_t pin, unsigned long ontime, unsigned long offtime ) {
      ledPin = pin;
      ledState = 0;
      onTime = ontime;
      offTime = offtime;
      pinMode( ledPin, OUTPUT );
      digitalWrite( ledPin, ledState );
      ledTimer.start( offTime );
    }
   
    //
    // start function sets duration and makes timer active
    //
    void myLed::Update( void ) {
      if (ledTimer.done()) {
        if (ledState) {
          ledTimer.start( offTime );
        }
        else {
          ledTimer.start( onTime );
        }
        ledState ^= 1;   // change led state
        digitalWrite( ledPin, ledState );
      }
    }
    
    //
    // Instantiate four object instances of our new myLed class
    //
    myLed  led1( 10, 500, 100 );  // led on pin 10, 500ms on, 100ms off
    myLed  led2( 11, 1000, 1000 );  // led on pin 10, 1 sec on, 1 sec off
    myLed  led3( 12, 100, 1000 );  // led on pin 10, 100ms on, 1 sec off
    myLed  led4( 13, 1000, 100 );  // led on pin 10, 1 sec on, 100ms off
    
    //
    // Setup of led and timer objects occurs in their constructors
    // so setup() is empty!
    //
    void setup(void) {
    }
    
    void loop(void) {
      led1.Update();   // make led1 flash
      led2.Update();   // make led2 flash
      led3.Update();   // make led3 flash
      led4.Update();   // make led4 flash
    }
    

Assume we're using the myTimer class from example 1 (myTimer class source code omitted to keep this example simpler). We define a myLed class that turns an led on and off with separate durations for the on and off phases. An instance of myTimer times the led on and off durations

We've instantiated four instances of myLed with different timings attaching them to arduino pins 10 to 13. These need to be "kicked" so they'll check done() on their timers to figure out when to change the led state. Other than that, NO other code needed in the loop() function to run the leds. If the myLed class was contained in separate files with a #include <myLed.h>, this sketch would be very short!

Yes, one could do something similar using structures to hold the led and timer data, then pass the structures to a initLed() and updateLed() functions. But now you have the possibility of passing the wrong structure. The OOP methodology tends to be cleaner.

Arduino's can be programmed using C++ language syntax. Like many OOP languages, it supports class inheritance. You have a basic myLed class. It would be easy to create other led classes that inherit myLed and extend it with additional functionality. Say an arcwedler class, or a rotating beacon class, or fluorescent light class that flashes when the lights are turned on and then settles down to steady lighting.

Another example would be a base class Vehicle which tracks speed, direction, color, passengers, remaining fuel, and pollution. Other classes such as Truck, Bus, and Car inherit Vehicle to avoid duplicating the code for that functionality.

For now however, unless you're already a C++ geek/guru, lets stick to simpler stuff and take a few steps into OOP-land on the Arduino.