Organize your Arduino code with header and class files



Ok, so you made your awesome Arduino widget, but now you're looking at the code trying to find the spot where you made it do that cool thing, and you can't find it! There's just too much going on in the sketch file!

Well my friend, it might be time for you to start organizing your code using classes and class files. 

What are C++ classes?

A class is basically a description of the variables and actions that something in your application might be interested in. For instance, if you were making a application involving vehicles, you might make a class that holds the speed the vehicle is currently traveling, and might have actions like drive and stop.  

Something like this:

class vehicle{
    private:
    int CurrentSpeed;
    public:
    void drive(int speed){
        //increase the speed
        CurrentSpeed = speed;
    }
    void stop(){
        // decrease the speed
        while(CurrentSpeed>0){
        CurrentSpeed--;
    }
};

The class is just a description. In order to use it, you need an instance of that class - which you might call 'an object'. 

vehicle car; // makes an instance of 'vehicle' called 'car'

Now, you can call the methods on your new car object like this

car.drive(55); // set the CurrentSpeed of the car to 55

In your Arduino code, you're probably not talking about cars - but you might be using sensors. A class you might create in your Arduino code might be for a temperature sensor.

class tempSensor{
    private:
    double LastReading;
    double CurrentReading;
    public:
    
    double read(){
    LastReading = CurrentReading;
    CurrentReading = SensorDeviceAccessor.read();    
    return CurrentReading;
    }
    
    double getLastReading(){
        return LastReading;
    }
  };

You could just create classes, stick them at the top of your sketch and start using them, but there's another level of organize you can do - you can create files. 

With C++, it's considered good practice to use header files with your classes. It's not 100% necessary and there are ways around it, but it make it much easier if you do. 

What is a header file?

In C++, the header file lists all of the variables and functions that your class will use, and defines them as public or private. It also provides you with a way to include that class in other places by using #include header_name.h 
If you've used any of the examples in the Arduino IDE, such as the 'blink' example, you've already used header files although you might be unaware since they are automatically included by the compiler. For instance "arduino.h" is imported by default with the Arduino IDE. The inclusion of that file makes it possible for the code to use the variables 'LED_BUILTIN' and 'HIGH'. 

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

Normally, you'd see 
#include "arduino.h"
at the top of the file if there was a header file being used, but in this particular case, they've hid it from you to make it easier for newer people who are seeing C++ for the first time. 

The reason it can do this is because it knows in advance where all of these files are stored. By default, there are many headers you can view located (on a windows system) at:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino


If you're using another OS, or you've changed the default install location of your Arduino IDE, those files are located in a similar folder relative to your install. 

What is a class file?

A C++ class file goes with a header file. It ends in .cpp, and it holds all of the code that your class will actually do. In a nutshell, the header defines what your class will do, the .cpp file holds the code that actually does it, and the 2 together make the entire class. 



How do I make my own?

All you have to do is click the little 'down arrow' on your Arduino IDE and choose 'New Tab', then give it a name and click 'OK' , I'll call mine 'myClass.h'.







If you followed that, you should now see 2 tabs in your IDE, the first one is the name of your sketch, the 2nd should say 'myClass.h'.
If you see this 
 
in your file name, it means you haven't saved your new file yet. Click file->save or CTRL+s to save your new file. 

Now that you've created the file, we'll need to define our header. 
The most simple header you can create is just the name of the class, with an empty body. You should use the same name of your file as the name of your class, although it's not required. It's just good practice. 
Using my previous example that means my simplest header will be:

class myClass {};

What you might notice is the ; at the end. That's required here, because this is basically the same as a C++ struct variable. 

Now, we can start defining things inside our new header. 
There are 2 places you can put your variables and methods - private, and public. 

class myClass {
  private:
    
  public:
   
  };

Anything you define in the private: area will only be available inside of the instance of your class. Anything in the public area will be available both inside and outside of your class. 

For ease of use, let's just make a String called name in the private area. 
You'll need to include Arduino.h to use this string in your class. 
Your class should look like this now:
.
#include "Arduino.h"
class myClass {
  private:
    String name;
  public:
   
  };
Then, let's make a constructor that will be called when we create an instance of our class. Well add an 'input' to the constructor which will allow us to pass in a 'name' when we create it. 




One of the most common things you might do in a class is define a 'constructor' and a 'destructor'. The constructor is called when you create an instance of the class, and the destructor is called when the class is destroyed. 

The constructor looks like this:
   myClass(String);

Notice that String just lives there by itself. We don't need to give it any variable yet, we'll do that in the next step. All we need to do here is tell the computer that when we create an instance of myClass, we'll also be passing in a String. 

The destructor looks like this:
   ~myClass();
The tilde character here means 'onDestroy', so the computer knows that if this class is destroyed, it should call this destructor so we can free up any resources we may have been using in our class.

Now, your header file should look like this:
#include "Arduino.h"
class myClass 
{
  private:
    String name;
  public:
   myClass(String);
   ~myClass();
 };

We will also want our class to actually do something. We're just going to print the name we passed in, so we'll have to give ourselves a way to get the name back out of the class. That looks like this:

#include "Arduino.h"
class myClass 
{
  private:
    String name;
  public:
   String getName();
   myClass(String);
   ~myClass();
 };



If you try to #include this in your sketch, you'll get an error. This is because you've told the computer what your class looks like, but you haven't actually made the code yet. 
To do that, you need to make a new tab named 'myClass.cpp' in the same way you made the header file earlier. The .h file holds all of the declarations of what your class will do, the .cpp file holds all of the code that actually does it. 

Once you create that file, the next step is to include your header file. 
#include "myClass.h"

You'll also define your constructor and destructor. This time though, we'll give a name to the string that that we'll pass in. 

#include "myClass.h" 
String myClass::getName(){
  return name;
}
myClass::myClass(String x)
{
  name=x;
}

myClass::~myClass(){}



Notice the namespace that looks like  "myClass::"
This is required so that the compiler knows that these variables and methods are in your header, and not in the default libraries. 

That 'String x" just defined a variable named x that is only available inside the constructor method. In order to actually do anything useful with it, we'll want to save it into our private 'name' variable. We'll pass in 'x', and store it in the variable called 'name';

We don't actually have anything to 'delete' in this example - but it's always a good idea to include the destructor. If you have any memory uses that need to be deleted, that's where you'd do it. 


Now that you've made your class definition, you can create 'an instance' of it in your arduino sketch.

To do that, you'd #include your header file, then use your class just like you'd use an int or a String, just remember that you have to pass in a name because your constructor expects one. We're going to define 2 different instances of our class, one that holds the name 'Bob' and the other holds the name 'Mary'.

#include "myClass.h"
myClass myClassInstance("Bob");
myClass mySecondClassInstance("Mary");


The whole sketch should look like this now:

#include "myClass.h"
myClass myClassInstance("Bob");
myClass mySecondClassInstance("Mary");
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);// for debugging
}

void loop() {
  // put your main code here, to run repeatedly:
   Serial.println(myClassInstance.getName()); // prints "Bob"
   Serial.println(mySecondClassInstance.getName()); // prints "Mary"
  
}

Upload the sketch to your Arduino, then open your serial monitor. You should see output similar to this:









Good Luck and Happy Coding!
-Tom
















 

Comments

Popular posts from this blog

Using GIT with Arduino

Programming Arduino with Regular Expressions