Skip to main content

In the Arduino world, some of the nomenclature is a bit odd for those of us who used to make a living as programmers. Their idea of a library seems different than the way I had to deal with them. But in the sense that a library is a source for reusable code, I can't disagree with their thinking.

When you write a program with the Arduino IDE (Integrated Development Environment), and you want to print something to the serial monitor, you use the Serial library. This library is used so often that you don't even have to declare it as an included file; it's built in.

If you browse through the Arduinolibraries, you will see a bunch of them. They can handle I2C communication, servo motor control, Wifi, SD cards, stepper motors, and a lot of specialized ones to support a particular type of hardware (shields). These libraries are all "open source" meaning you can look at how they work, change them if you like, and they all come free of charge when you download the Arduino IDE.

In this post, I will be showing you how to create a library from within the Arduino IDE. It's not difficult but I didn't know how it was done until I learned it from someone else. I hope I can pass that information along to you as well.

What we will be doing is creating what C++ calls a class. This is an essential part of object oriented programming. It allows us to create objects that have attributes not unlike real-world objects. Later, we will examine class hierarchy; the idea that a class can inherit the attributes and behaviours from a parent class.

The details about what we will be doing will come once we understand the mechanics of how to do it. For now, I will use an LED (light emitting diode) as the basis for our examples.

An Arduino board has a number of Digital Input/Output pins that can be wired to an LED so that it can be turned on and off from a program (sketch). Some of these pins can output what's called pulse width modulation (PWM) signals that can be used to affect the brightness of an LED.

We will start with the simplest form of an LED and it's functioning. One that can be turned on and off without using pulse width modulation. Let's name our class "PlainLed". To create our class we will develop 2 files. A header file called "PlainLed.h" (all header files end with the ".h") and an implementation file called "PlainLed.cpp" (cpp stands for C plus plus).

To create these files from within the Arduino IDE, you will find a small drop down icon in the top right corner of the screen.

I use a dark theme for my Arduino IDE. Click on this pull down icon to reveal a dialog box that includes the "New Tab" item as the first entry in the list.

Click on "New Tab" to open a dialog that appears in the lower right corner of the screen. This is where we will enter the name of the header file that we want to create.

After you enter the name, click on "OK" to create the file. When this is done, you will see the new file in the tabs at the top of the page.

The new file is open and you can enter your header file text.

Next we want to create the C++ implementation file "PlainLed.cpp". The process is basically the same. Click on the icon in the upper right corner, click on "New Tab" and enter the name of the file to be created.

Click OK and the new file will be shown in the tabs at the top of the IDE.

Then enter the implementation file text.

That's the procedure for creating our library. Next time we'll get into the details of the "PlainLed" class and write a test program to see how to use it. Questions and comments are welcome.

  -- Leo

 

Attachments

Images (8)
  • mceclip1
  • mceclip2
  • mceclip3
  • mceclip4
  • mceclip5
  • mceclip6
  • mceclip7
  • mceclip8
Last edited by Consolidated Leo
Original Post

Replies sorted oldest to newest

Leo

Thanks for doing this tutorial.  The Arduino can provide an inexpensive implementation for many systems that enhance our layouts including signaling, building interior light control, animation, switch motor control, etc.

Geoff Bunza did an article in Railroad Model Hobbyist which included an introduction to the Arduino world as well as dozens of light, sound, and servo projects, all with downloadable code.  

Bob

 

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

It seems that, in my last post, some of the character sequences that I used turned into gremlins (emoticons). Colons and parenthesis will do that as I have learned. Also, when I cut and paste my program text into the edit screen, it looses the indentations. The format is still valid (minus the gremlins). Indentation is only significant to programmers, not the machine. The attached versions of the code remain unaltered and are available for anyone who wants to play with them.

So now, we're ready to look at a test program for our "PlainLed" class. Before I began this exercise, I started by creating a NEW sketch in the Arduino IDE called "PlainLedTest". In your local file directory it will show up as a file with the extension ".ino" (identifies an Arduino sketch).

Each sketch created by the Arduino IDE will create a new file folder in the local directory. The "path" to that directory, on my Windows machine is Libraries - Documents - Arduino. There you will find all of the folders for your sketches. Here's what the "PlainLedTest" folder contains:

Manually moving files around in these directories is not advisable; I do it all the time. But use caution or you could lose all your work.

I've already written the test program which you can examine on your own. I suspect that the group of people who remain viewers of this thread are well versed in the language by now. However, if you need help with anything, I promise not to embarrass you or myself in any way.   There are no bad questions. My email address should be available on my profile page.

I will not attempt to cut and paste the test program here. It will be in the attachments below. However I will put up some pieces that will explain how it works.

The test phases include:

1. LED on for 2 seconds.
2. LED off for 2 seconds.
3. Toggle the LED on for 3 seconds.
4. Check that LED is on and toggle off, 3 seconds.
5. Check that LED is off and toggle on, 4 seconds.
6. Turn off LED, 4 seconds.

When all phases have been completed, the sequence repeats using the
next LED.

The test circuit includes 3 LEDs with current limiting resistors connected to pins 9, 10, and 11. These are PWM output pins which will be useful when we add fading capabilities later on. Here's a diagram:

 

The LEDs are connected Anodes to the color connections and Cathodes all going to Common. You all know what the Nano looks like.

 

I've set it up on a breadboard with wires going to resistors and 2 sets of LEDs both green, yellow, and red. This test is run using the LEDs that I have mounted on an independent prototype board.

Our program demonstrates that turning an LED on and off can be way more complicated than that old blink program. But we have also seen the basics of building any type of class and creating any type of object.

Next time we will extend our PlainLed class to use the pulse width modulation capabilities of the Arduino to set the intensity of the LEDs. Can you say PulseLed?

  -- Leo

Attachments

Images (4)
  • mceclip0
  • mceclip0
  • mceclip0
  • mceclip1
Files (1)
Last edited by Consolidated Leo

Just a quick clarification. When speaking about operations in a class, I tend to use the terms "function" and "method" interchangeably. The term "method" originates from my years of programming in Java. The C++ language does not use "method" to describe anything. Functions defined within a class are generally referred to as "member functions".

I will try to steer away from the "method" terminology in future documentation. You may still find it in some of the code I have already posted. Arduino code is not Java.

The programming community often tends to mix up terms for things as closely similar as class functions in C++ and class methods in Java. You may find it in other literature or discussions about classes. Don't be confused. I've got that covered.

Now that we have a working version of the PlainLed class, we can add new capabilities to extend the feature set of an LED connected to an Arduino. We want to make use of the variable intensity brightness of an LED matched up with the PWM output pins of the Arduino. This will allow us to create a fading effect when the LED is turned on or off.

Recall that a PlainLed will work with any of the Digital I/O pins of the Arduino. I think that even the Analog pins can be used with "digitalWrite" once they've been setup for output mode. But now we will be using the PWM outputs with the LEDs. The Arduino Nano has 6 individual pins that are setup to operate in this manner. We will be using pins 9, 10, and 11 for our tests.

We will create a new class called "PulseLed" that builds upon what we have already done. It will be a derived class of PlainLed. In this new relationship, PlainLed is the base or parent class and PulseLed is the derived or child class.

A derived class inherits all of the functionality of the base class. However, some of the base functionality can be overridden by the derived class. In other words, we can change the behavior of the "on" and "off" routines to achieve the desired fading effect.

To do this we need to declare new versions of the public functions that we wish to change. For our PulseLed class these include "on", "off", and "toggle". The base class versions used "digitalWrite" to turn the LEDs on and off. For our new class, we will be using "analogWrite" instead.

PulseLed will include new functions as well. These include "setMax", "setFading", "setUpTime", "setDownTime", and "update". Their usage is explained in the C++ implementation file "PulseLed.cpp" (see the attachments below). These new functions allow us to change settings that affect the class. We can specify how long it takes to fade up or fade down, set the value to use for full intensity brightness, and control if the fading feature should be enabled or disabled.

Here's the class header file for PulseLed:

/*
PulseLed.h - Pulse Width Modulation LED Class Header File
*/

#ifndef PulseLed_h     // one time wrapper
#define PulseLed_h    // wrapper definition

#include <Arduino.h>
#include "PlainLed.h"

#define DIVISIONS 25     // number of divisions of fading

class PulseLed : public PlainLed {
private:
byte _max = 250;                   // maximum intesity (0-255)
bool _enabled = true;          // true if fading is enabled
int _upTime = 500;               // fade up time in milliseconds
int _downTime = 500;         // fade down time in milliseconds
byte _upTimeInc = 20;        // fade up time increment ms.
byte _downTimeInc = 20;   // fade down time increment ms.
byte _valueInc = 10;            // fade value increment
byte _value = 0;                   // fade value
bool _fading = false;           // true while fading
bool _fadeUp = true;          // true if fading up
unsigned long _timer = 0; // millisecond timer

// private functions
void turnOn ();
void turnOff ();
void changeFade ();

public:
void setMax (byte max);                  // set max intensity value
void setFading (bool enabled);      // set fading enabled
void setUpTime (int upTime);        // set fade up time ms.
void setDownTime (int downTime);   // set fade down time ms.
void on ();                                           // turn the LED on
void off ();                                          // turn the LED off
void toggle ();                                   // change state of LED
void update ();                                 // time based update
};

#endif // end wrapper

Not a whole lot has changed from what we have seen before. There is still the preprocessor wrapper around the content. We have a class definition with private and public sections. There are member variables all declared "private" this time. There are "public" function prototypes for the operations that can be called on objects of this class. But there are some important differences.

The first is that the PlainLed header file is included. Without that, we could not declare that our new class is derived from the base class. This is done in the class declaration with:

class PulseLed : public PlainLed {

There are some utility private functions declared that are only available within the class itself. Everything else is pretty easy to comprehend.

Moving on to the implementation, there are a couple of things to mention. The "update" function is used to change the PWM value when the LED is fading up or down. It is intended to be used within the real-time processing "loop" on a somewhat frequent basis. Without it, no fading can occur. Keep in mind the relative timing differences between milliseconds (LED fade time) and microseconds (processor execution time).

All of the functionality of the base class is still available. Even with an object declared from PulseLed, the functions that are overridden can be referenced using the syntax myLed.PlainLed:: on();

Our new class does not include a "begin" function. That's because it already exists in the base class. Also retained from the base class (PlainLed) are "isOn" and "isOff". Remember that the "begin" function is used to associate our objects with a particular Arduino output pin.

Recall also that in PlainLed.h, we declared the member variables "_pin" and "_isOn" as protected. That allows the implementation of our derived PulseLed class to make use of these variables directly. If they had been set as private, we would have no access. If they were public, anyone could change them and that's bad policy.

Finally, a test program was developed that looks much like the test program for the PlainLed class. In this test, of course the green, yellow, and red LEDs are now declared as PulseLed objects. The "setup" is the same. The "loop" now includes switching the fading feature on and off after all the LEDs have been run through the test phases.

The circuit is exactly the same as before.

Pretty cool !!!  But wait, there's more.

Next time we'll get the LEDs to flash with a new class derived from the PulseLed class. Should be fun!

  -- Leo

Attachments

Last edited by Consolidated Leo
rtr12 posted:
...  the pics above say 'no image found' and no pic showing. However the videos are showing just fine. More gremlins!!

Oh gee! Thanks for the heads-up. I think I know what I did wrong with the images. I'm going to try to fix them. For me, they show up fine.

If I try to fix them, they will look the same to me as they do now. Can I count on you to tell me if they have been fixed? I'll put up a post when I have finished.

I remember seeing your name before somewhere but can't remember just now. Anyway thanks!

  -- Leo

Once you've developed a library that you may want to use in other programs, the build process just needs to know where to find the associated files. There are two ways to do this.

You can copy the header and implementation files directly into the directory associated with a new sketch. Once they are in that directory, they will show up in the IDE in the tabs at the top of the screen. You will have complete access to them and will be able to edit them if you wish. However, it's not considered good policy to edit libraries once they have been used elsewhere. You may want to improve the library or add something new but then you'll have to redistribute the newer version to all of your old sketches.

This is the way I did it for the development of the PulseLed class library. I first created a new sketch called "PulseLedTest" and then closed the IDE. Next I used Windows Explorer (file browsing application in Windows) to find the newly created sketch directory. I then copied the files "PlainLed.h" and "PlainLed.cpp" into the new directory.

You may remember that we saw this before and looked at how sketches are created in what is called the sketchbook directory. You can check the IDE preferences to find out where the sketchbook directory resides:

Generally, it follows the path: Libraries - Documents - Arduino. The easy way to get there from the IDE is to use the menu items "SKETCH" - "SHOW SKETCH FOLDER". That will take you to the folder of the currently open sketch. If you navigate back one level, that's the sketchbook. You will see a list of directories each with the name of the sketches that you have worked on:

Notice among these sketches are "PlainLedTest" and "PulseLedTest" which we have worked on recently. Also, there is a directory called "libraries" which we want to look at next.

I mentioned that moving library files around into new sketch directories is not a good idea. It eventually becomes a management nightmare with different versions of the same files all over the place.

Enter the "libraries" directory. This is the place to put user developed libraries. For our PlainLed class, we would first create a new folder in the "libraries" directory called, you guessed it, PlainLed. Then you copy the files "PlainLed.h" and "PlainLed.cpp" into that directory. Follow the same procedure for PulseLed and we're done:

Click on the PlainLed folder and you'll see our class header and implementation files:

The Arduino IDE build process will be able to find these files without breaking a sweat. And downloading a newer version of the IDE will not alter the user directory space. You no longer have to keep versions of these files in the same directory as your sketch. You just reference them in your program using:

#include "PlainLed.h"

Remember to update your "libraries" files any time you make a change or improvement. Once they have been in general use, you want to try to keep alterations "backward compatible". That means that you should not change anything that does not agree with what has already been used. Otherwise, you could break some working code.

To develop a flashing capability for our LEDs, we will again build on what we have already done. We will create a new class derived from PulseLed called "FlashLed". Because FlashLed will make use of PulseLed, and PulseLed will make use of PlainLed, the build process requires access to these libraries. Now that they are safely stored away within our user libraries folder, we can work on FlashLed independently.

Attachments

Images (4)
  • mceclip0
  • mceclip1
  • mceclip2
  • mceclip3

RTR12: (I still don't know your real name) I believe that what I did was delete some of the pictures in the list of attachments. I didn't want the attachment area to be cluttered when I put up the program files. Since the pictures were still visible to me, I figured it was okay.

I'm thinking that it has to do with the web browser cache for recently viewed images. When it sees the link in the post from the forum, it finds it in the cached files and shows them to me. But they're not really on the forum's server because I deleted them.

I'm really pretty impressed with what you can do with editing on this forum. Most of the time I just copy and paste pictures that I edit with MS Paint. Screen shots come from Control/Print-Screen. That puts the screen shot on the clipboard. Just open paint and do a "paste" to get your screen shot. Then edit at will.

Pestering is not the right term for commenting on the forum. We, the curious, want to know what the heck is going on. Sometimes we ask questions. I would say that you aim just above your natural level of understanding in order to improve your knowledge. What else is a forum for?

Keep the faith, brother!

  -- Leo

I've been working on the last part of this lesson and am busy tracking down some things that are problematic. You see, even a veteran programmer can have trouble with software.

We are always trying to juggle several screens around at the same time. One with the Arduino IDE. Another looking up documentation on some library functions. One playing songs from the 70's, and here's one, oh never mind about that.

It's a lot of this and that with much experimentation and rebuilding. Eventually, it all comes together and you have what you want. Don't be discouraged if you don't get things to work after the 20th try. Break it down. Take it apart. Isolate where you think the problems exist and test, test, test. That's how it's done. As I said before, you need to harden yourself against failure. It comes with the territory.

As I was working on the new FlashLed class, I realized that the way I was building this "Flash an LED" class was independent of the 2 classes that were developed earlier. What I planned was to have them organized like this:

But FlashLed just uses the "on" and "off" functions with some timing code to create the "flashing" effect. Both PlainLed and PulseLed have their own versions of these routines. And with some changes to the PlainLed class to include some dummy operations that do nothing, the same code for FlashLed could be used to blink a PlainLed. The view of class hierarchy then becomes:

BlinkLed introduces a new class that works in the same way as FlashLed but is dependent only on PlainLed (one that turns on and off but doesn't fade) to operate. This is useful if you want to do without the fading features of PulseLed but still want independent flashing.

This indicates that we have designed this set of classes with a proper isolation of features. We can mix and match these to create the type of object that is desired.

Soon I will finish the FlashLed class and make it available for your perusal. It will include a test program as before but restructured to demonstrate the newer features. Until then, go do some programming.

  -- Leo

 

Attachments

Images (2)
  • mceclip0
  • mceclip1

To finish up with this lesson, we will add a flashing LED feature on top of the PulseLed class. This will provide both flashing and fading capabilities in a class called "FlashLed". Note that because the PulseLed class can disable fading, the flashing feature will work either way; with fading or without.

Let's look at the header file for the FlashLed class.

/*
FlashLed.h - Flash LED Class Header File
*/

#ifndef FlashLed_h      // one time wrapper
#define FlashLed_h    // wrapper definition

#include <Arduino.h>
#include "PulseLed.h"

#define BASECLASS PulseLed

class FlashLed : public BASECLASS {
private:
bool _flashing = false;          // true when LED is flashing
int _onTime = 1000;              // flash on time in milliseconds
int _offTime = 1000;             // flash off time in milliseconds
unsigned long _timer = 0;   // millisecond timer
int _cycles = 0;                       // flash cycles counter
int _count = 0;                        // flash request count

public:
void setOnTime (int onTime);
void setOffTime (int offTime);
void on ();
void off ();
void toggle ();
void flash ();
void flash (int count);
void update ();
};

#endif         // end wrapper

You will notice that we again put a wrapper around the class definition. We include the standard system "Arduino.h" file and our own "PulseLed.h". Then we define a BASECLASS that the preprocessor will substitute both here and in the implementation file. Change the name of the base class and you have a different thing. Maybe you want to flash regular light bulbs. We've planned ahead for that possibility.

As I mentioned earlier, with a few changes to our PlainLed class, we could use that underlying functionality with this new flashing class to create a flasher that would work with LEDs that are not connected to the PWM pins of the Arduino. In other words, we would be able to flash regular LEDs but without the fading capability.

So BASECLASS will steer our FlashLed to use the proper functions for "on", "off", and "toggle" operations. Even though we define these functions for this class, the BASECLASS functions are called upon to do the actual work. You will see this in the implementation file.

Next is the class definition:

class FlashLed : public BASECLASS {

FlashLed is derived from the BASECLASS that has been defined as the PulseLed class.

Following this are member variables that are used to control the flashing capability. There is an on time and an off time that define the flash cycle in terms of milliseconds. These are initialized to values of 1 second on and 1 second off. There's a timer value that will mark the start of the flashing cycle. There's also a cycle counter for use with the "flash(count)" function.

There are corresponding functions to set the on time and off time of the flash cycle. Then come the familiar "on", "off", and "toggle" functions. Using any of these operations will stop any flashing of the LED. The "flash" function starts the flash cycle which will run continuously until stopped with "on", "off" or "toggle". To cause the LED to flash a specified number of times, use "flash(count)".

The "update" function works in the same way as the "update" function for the PulseLed class. This is where changes occur based on timing.

The new class files are included in the attachments below. Comments and questions may be submitted as you have the freedom to decide what should be done in a particular situation. My email is also available in my profile. The test program and video should be up shortly.

  -- Leo

Attachments

Last edited by Consolidated Leo

Here's the FlashLedTest program (sketch) built from the FlashLed class and using the classes from the user "libraries" directory for PlainLed and PulseLed. I changed the test program somewhat this time to treat the LEDs as more of a group. But remember that they are each acting independently of one another.

The test sequence runs as follows:

1. Green on for 2 seconds.
2. Green off, yellow on for 2 seconds.
3. Yellow off, red on for 2 seconds.
4. Red off, green flash for 4 seconds.
5. Green off, yellow flash for 4 seconds.
6. Yellow off, red flash for 4 seconds.
7. Red off, faster flash time, green flash for 3 seconds.
8. Yellow flash for 3 seconds.
9. Red flash for 3 seconds.
10. Green off for 3 seconds.
11. Yellow off for 3 seconds.
12. Red off for 3 seconds.
13. Set fade longer than flash time, green flash 3 times.
14. Yellow flash 3 times in 4 seconds.
15. Red flash 3 times in 4 seconds.
16. Turn on all LEDs 2 seconds.
17. Turn off all LEDs 2 seconds.

This sequence repeats with fading disabled every other time.

And here's the video demonstration:

That about wraps up this lesson on Arduino libraries. I hope this will be a useful resource for those in the forum who have ideas about using microprocessors on their layouts. Good luck with all that you attempt. I'm hoping to try a few things myself and will keep everyone appraised of how that goes.

  -- Leo

Attachments

One thing that I skipped over has to do with "setter/getter" functions.

It is good practice, to include in a class, functions that allow access to values that can be modified by the program. If you can set the pin number to be associated with a PlainLed, you should also be able to retrieve that value. If you can set the fade up time for a PulseLed, you should also be able to read it back.

In general these functions are referred to as "setters" and "getters". They are used to "set" a value or to "get" a value from a class. The format is easy. To change a class variable called "XXX", you use the form "setXXX". To retrieve the same variable, use "getXXX". For variables that return a true/false value, it is normal to use the form "isXXX".

The classes that we developed in this lesson made use of the "setter" functions but we skipped over the "getter" functions. I have updated these classes to include the getter functions as well; if only for completeness. These new functions along with their corresponding setter functions are outlined below:

PlainLed:
    void begin (byte pin);
    byte getPin ();

PulseLed:
    void setMax (byte max);
    byte getMax ();

    void setFading (bool enable);
    bool isFading ();

    void setUpTime (int upTime);
    int getUpTime ();

    void setDownTime (int downTime);
    int getDownTime ();

FlashLed:
    void setOnTime (int onTime);
    int getOnTime ();

    void setOffTime (int offTime);
    int getOffTime ();

Please note that the "begin" function is an Arduino convention for initialization but that it serves the same purpose as a setter function.

I've included the updated versions of these classes in the attachments. There are other improvements that could be made to these classes but the most important thing to understand at this point is the general concepts involved in creating an Arduino library. As always, questions and comments are welcome. Thanks!

  -- Leo

Attachments

Last edited by Consolidated Leo

I'm still here and on the case! My grandson bought a remote controlled 'crawler truck' kit and wanted to come over here and put it together. We have been on it for 4 days, it's up and running, but the body still needs paint and assembly. We are resuming tomorrow.  Directions said 2-3 hours, I'd love to see that!!

Anyway, I have some catching up and study to do, I'm slightly behind in my lessons! My real name is Thomas (Tom) Frye and I am in Lenexa, KS. Been in the K.C. area all my life except for a year or two here and there when I was a kid (early '60s). Lived in Tucson, AZ and West Palm Beach, FL. Was in WPB when President Kennedy was assassinated (they had an estate in Palm Beach, were very popular there). I am now retired. I have done some programming in Quick Basic and MS Prof. Basic back in the DOS days, late '80s early '90s. I never kept up when Windows started taking over so I am lost with C++ and other languages, nifty user screens, etc.  I can hack out a thing or two in the Arduino IDE, but nothing overly complicated.

I really want to study all this a while, but my grandson is out of school again Monday so I am still tied up for a while yet. I don't think we will be completely done with his 'crawler' by then, but maybe close? The old brain has trouble switching it's full attention from crawlers to Arduino code. Don't work as well as it used to. May be something to do with teaching old dogs new tricks?? And grandpa gets tired much easier and faster than his grandson.   

I'm sure I will really enjoy all this when I can devote some more time to it. 

Tom: I didn't think that Ready-to-run was your real name. I'm glad you're interested in the Arduino stuff. I've got to say that this platform offers a lot of possibilities for DIY projects related to model railroading.

I've tried in the past to get a handle on the hardware and software for the various microprocessors that have come down the pike. I've got an AVR development board around somewhere but was unable to do much with it. I just couldn't find out what I needed to know even with the Internet.

The Arduino is the first microprocessor platform that has put the pieces together in such a way that it all made sense to me. I'm not an Electrical Engineer by a long shot but have always been interested in electronics since, at a young age, I tried to power a bulb from a flashlight with wires stuck into an AC outlet. Luckily, my father stopped me before I got shocked. He tried to explain to me what I was doing wrong. But I needed to know more.

So I ended up with a Computer Science degree from the University of Pittsburgh. I took a job near Cleveland, OH working on programs for CT scanners. Later I joined my brothers to form a software development company. We struggled with that for about 30 years but I thought that we always put out good work. I have since retired with some health issues. Now I've got the time for hobbies. Too many hobbies!

Anyway, I'm glad that you're spending time with your grandson. That's time well spent. As long as the forum doesn't fall apart, you can get back to this anytime. Good luck with that truck!

  -- Leo

That was actually ready-to-retire, but I guess it fits here as ready to run! I also had some health issues and the retire part came a bit early. I got put out to pasture early, also due to health issues. Grandson has ball practice until this afternoon. I really do enjoy spending time with him, it's a lot of fun and kids are great. And I do understand about too many hobbies. I have hobby projects backed up that will last me for years!

I started out trying to learn electronics myself, but had an opportunity came along that I couldn't pass up so I ended up in construction. The last 15 years or so I worked was with some electronic devices, just installing them. Learned how to hook everything up and what it did, but not much about the circuits, components or programming. I am trying to catch up here and there is a lot of good folks here that are good at teaching! It's great that they are willing to take the time and be patient while I try to catch up. As yo are doing with your library tutorial here! Great fun and it keeps me off the streets!

Thanks, Tom! Maybe we can learn more together through the forum. My only hope is that, with the proper presentation of the subject matter, people will find the topic of microprocessors a bit less intimidating.

I have plans to use multiple Arduino's to run signaling systems on a conventional layout with control blocks that will allow the trains to run themselves when desired. That means that the microprocessors have to communicate with each other to indicate block occupancy and signal aspects.

I don't have a great budget for doing any of this so the cheap stuff from Asia is on my agenda. I've had excellent results with the things that I've ordered from overseas so far and that's what I'm counting on.

I just recently put an order in for some relay modules; 16 relays on 4 boards with opto-isolation for just $10. Arduino Nano's go for about $2.50 with free shipping. That's such a great deal I'll be going for more of those soon.

Even the larger Arduino boards are very reasonably priced. I've got a Mega 2560 that cost about $10. It's got the headers already in place and has lots of pins. I tried it with a simple loop of track running power through a relay module. It worked great.

I hope to continue the Arduino lessons with some of these projects. Maybe it will catch on with some of the other retired folks. I know soldering can be tough for those of us with poor eyesight but it doesn't have to be perfect; just serviceable. I won't be using any surface mount components for anything.

  -- Leo

Add Reply

Post
×
×
×
×
Link copied to your clipboard.
×
×