Skip to main content

Reply to "Arduino Lesson: How to Create a Library"

Now that we know how to create new files in the Arduino IDE, let's take a look at what goes into making a class.

We know that there are 2 files involved; the header file, and the C++ implementation file. The header file describes the data and functions (or methods) that we will create for the class. The C++ implementation file contains the code that performs the operations for the class. For our example, the "PlainLed" class, these 2 files are named "PlainLed.h" and "PlainLed.cpp".

Let's take a look at the header file first.

/*
* PlainLed.h - Plain LED Class Header File
*/

#ifndef PlainLed_h      // one time wrapper
#define PlainLed_h    // define wrapper

#include <Arduino.h>

class PlainLed {
protected:                  // data also used by derived classes
byte _pin = 0;             // Digital I/O pin number
bool _isOn = false;    // true when LED is on

public:
void begin (byte pin);    // initialization
void on ();                        // turn LED on
void off ();                        // turn LED off
void toggle ();                 // change state of LED
bool isOn ();                    // true if LED is on
bool isOff ();                    // true if LED is off
};

#endif         // end wrapper

First, notice the lines:

    #ifndef PlainLed_h
    #define PlainLed_h
    ...
    #endif

These are preprocessor directives that are used to build a wrapper around the class definition. It ensures that the class will be included in other files only one time even though other included files may also have references to the same header file.

It says "if the symbol PlainLed_h is not defined" then include the lines which follow up to the corresponding "#endif". Then, immediately following the conditional (#ifndef) is the definition (#define) for the symbol "PlainLed_h".

It's a good idea to use the name of the header file as the wrapper definition symbol to avoid conflicts with other possible definitions. But you can't use a "." (period or dot) character in a preprocessor definition. So the "_" (underscore) is used instead. Upper and lower case is significant so watch it!

Next we include the Arduino header file that contains some definitions that are not normally available. Notice the use of the angle brackets (< and > surrounding the file name. This simply tells the preprocessor to look for this file in a place where system files reside rather than in the local file directory.

    #include <Arduino.h>

The class definition comes next and begins with the keyword "class" followed by the name of the class.
The opening curly brace "{" surrounds the whole definition and ends with a closing curly brace "}". Notice too that a class is similar to a C++ data structure and is therefore required to end with a semi-colon. The editor won't add it automatically so be sure to put it in yourself. Otherwise your program build will fail.

class PlainLed {
protected:                  // data also used by derived classes
byte _pin = 0;             // Digital I/O pin number
bool _isOn = false;    // true when LED is on

public:
void begin (byte pin);    // initialization
void on ();                        // turn LED on
void off ();                        // turn LED off
void toggle ();                 // change state of LED 
bool isOn ();                    // true if LED is on
bool isOff ();                    // true if LED is off
};

The class definition has several sections that begin with one of the keywords "public", "private" or "protected". Items that appear in the public section are available to any part of a program that uses this class. The private section hides data and functions for use by the class only. Most classes will have both public and private sections.

If you intend to extend your class by building a derived or child class, the use of the protected section can be beneficial. It gives any derived class special access to the functions and variables defined in that manner. At the same time these items remain hidden from other parts of your program.

In our PlainLed class, we start by defining two variables in a protected section because they will be useful for extending our class later on. The first variable is the pin number, a byte value (less than 256). The second is a boolean variable that maintains the status of the LED; either on or off. Note also that these variables are given initial default values that will be given to them when an object is created.

The names of class variables in Arduino land begin with an underscore character by convention. This falls under the heading of "best practices". You should follow this rule; it helps to avoid confusion with function parameter names in the implementation code. The rest of the name is up to you.

The public section which follows provides declarations of the function prototypes or methods that can be used with this class. We have a "begin" function that includes the number for the pin that is driving the LED. Then a group of operation functions to turn the LED "on", turn it "off", or "toggle" the LED from it's current state. Finally we can find out if the LED "isOn" or "isOff". Pretty simple.

The C++ implementaion file looks like this:

/*
PlainLed.cpp - Plain LED Class Implementation

This class can be used with an LED connected to any of the digital I/O
pins. They do not have to use the PWM outputs.
*/

#include "PlainLed.h"

/*
begin - Initialization

void begin (byte pin)

This method is generally run within "setup" to initialize the LED and
associate it with the specified output pin. The "pinmode" method is then
called to establish the pin as an OUTPUT.
*/
void PlainLed::begin (byte pin) {
_pin = pin;
pinMode(_pin, OUTPUT);
}

/*
on - Turn the LED On

void on ()

Turns the LED on using "digitalWrite".
*/
void PlainLed:n () {
digitalWrite(_pin, HIGH);
_isOn = true;
}

/*
off - Turn the LED Off

void off ()

Turns the LED off using "digitalWrite".
*/
void PlainLed:ff () {
digitalWrite(_pin, LOW);
_isOn = false;
}

/*
toggle - Change the State of the LED

void toggle ()

If the LED is on, it is turned off. If the LED is off, it is
turned on.
*/
void PlainLed::toggle () {
if (_isOn) {
off();
} else {
on();
}
}

/*
isOn - Test that LED is On

bool isOn ()

Returns true if the LED is on. Otherwise, false is returned.
*/
bool PlainLed::isOn () {
return _isOn;
}

/*
isOff - Test that LED is Off

bool isOff ()

Returns true if the LED is off. Otherwise, false is returned.
*/
bool PlainLed::isOff () {
return ! _isOn;
}

The implementation is self explanatory. Notice that all of the functions have the name of the class before the function name separated by two colons (:. These are not global functions. They are accessible only by an object of the named class. For example:

PlainLed myLed;   // myLed is a PlainLed object
...
myLed.begin(13);  // associate myLed with pin 13
myLed.on();           // turn on the LED

The longer these posts get the farther back I have to go to reach the BOLD button. So I'll stop for now. You can find reusable versions of these files in the attachments below. Next time we will look at a test program for our PlainLed class. Again, questions or comments are submitted at your own risk.

Peace be with you.

  -- Leo

 

Attachments

OGR Publishing, Inc., 1310 Eastside Centre Ct, Suite 6, Mountain Home, AR 72653
800-980-OGRR (6477)
www.ogaugerr.com

×
×
×
×
×