Arduino IDE and library files, beginner friendly.

For beginners, you make variables and functions that use them and those can pile up and get long.

With C++ classes you can group variables and functions together under a name, like a variable, even make arrays like variables. They let you package data and code apart from the pile.

The C++ class object you probably first used is named Serial and has functions like begin() and print(). On the Arduino Mega2560 you also get Serial1, Serial2 and Serial3. Each one has data to run one of the 4 serial ports on that board and all the Serial Library functions. There is one class that 4 objects were made from.

I have a simple demo to get beginners started on classes, a led control class using the pin 13 led.

But first, about where the files go. I know where library files should go. That's the problem I ran into with the Arduino IDE. Arduino IDE will let me open tabs to edit .h and .cpp files in but try as I might, the saves always went to the sketch folder. So my answer is that while I am working on a library, keep it in the sketch folder. It's easier. That means any examples I provide meant to be open for users to learn from also have to be in the sketch folder.

So where is your sketch folder? Go to saveAs an IDE sketch, browse and find out but you don't have to know. In the IDE at the top of the edit window is a green bar. Once you have the project saved, at the right side of the green bar is a v button. It gives a popup menu. Pick New Tab and it will ask for a file name, make one for mylib.h and one for mylib.cpp then copy and paste from this post to the proper tabs. When you save those they will go to the sketch folder.

This is an example to show a simple roll your own library with just the basic first steps.
It makes one led object, led 13, and toggles it on/off every time that loop() counts 5 million.
The user is invited to connect other resistor+led to other pins and try things out.
Maybe even try adding values and functions to the led class. It's in the sketch folder, you can only break the sketch.

Updated 8/10/15, thanks PaulS! Karma to you!

// mylib demo 

#include "mylib.h" // in "", the library is in the sketch folder

led myled13( 13 );

void setup( void )
{
  Serial.begin( 115200 );
  Serial.println( "\nserial connected..." );
  myled13.start(); // must call to set pin mode
  myled13.turnON();
}

void loop( void )
{
  static long counter = 0;
  
  if ( counter++ > 499999L )
  {
    counter = 0;
    myled13.toggle();
  }
}
// mylib.h demonstration of editing a library in the Arduino IDE

#ifndef mylib_h
#define mylib_h

class led
{
  private:
    unsigned char  pin;
    unsigned char  state;
  public:
    led( unsigned char );
    void start( ); // must run in setup to set pin mode
    void turnON( );
    void turnOFF( );
    void toggle( );
    void setLed( unsigned char );
};

#endif
// mylib cpp

#include "Arduino.h"
#include "mylib.h"

led::led( unsigned char p )
{
  pin = p;
  state = 0;
};

void led::start( )
{
  digitalWrite( pin, LOW );
  pinMode( pin, OUTPUT ); 
};

void led::turnON( )
{
  state = 1;
  digitalWrite( pin, state );
};

void led::turnOFF( )
{
  state = 0;
  digitalWrite( pin, state );
};

void led::toggle( )
{
  state = state ^ 1; // XOR 1 reverses 0 and 1
  digitalWrite( pin, state );
}

void led::setLed( unsigned char s )
{
  state = s;
  digitalWrite( pin, state );
};

Neat. Thanks for sharing.

I have bookmarked it.

Personally I like the idea of simply having the library files in my project directory. It avoids problems when a centrally stored library is "improved"

...R

That is an advantage, we get to address the common or the custom support files. But then once you have a good base class, the way to customize it is inherit and morph by adding the new and overloading what's to change as a new class leaving the base class unchanged.

I'd like to see more beginners who have the C basics down start wrapping data and code into class objects. Coding basic objects has enough benefit just organizing code and reducing the number of details that need to be considered at the same time including the classic problem "where did I use that global already?" that it's worth a step or two up the learning curve.

#ifndef mylib_h
#define mylib_h

Guards usually use the name of the class, which should match the name of the file.

led::led( unsigned char p )

Why does this function take an unsigned char? Something wrong with byte or uint8_t?

(Yes, I know that they are all the same size. It just looks strange. Someone will inevitably try to call the function with '2', to use pin #2).

  digitalWrite( p, LOW );
  pinMode( p, OUTPUT );

Diddling with the hardware in the constructor is a bad idea. Has init() been called before your constructor? If you can't answer that DEFINITIVELY, don't diddle with the hardware in the constructor.

  return;

In a constructor? I've never seen a constructor with a return statement. What else would the constructor do when it reached the end?

In the header file, public stuff usually appears before private stuff.

PaulS:

#ifndef mylib_h

#define mylib_h



Guards usually use the name of the class, which should match the name of the file.

I'm not averse to putting more than one class in a library is why.

led::led( unsigned char p )

Why does this function take an unsigned char? Something wrong with byte or uint8_t?

(Yes, I know that they are all the same size. It just looks strange. Someone will inevitably try to call the function with '2', to use pin #2).

Because the compiler wouldn't let me use byte.
Why would trying to use pin 2 be a problem? That is intended.

 digitalWrite( p, LOW );

pinMode( p, OUTPUT );



Diddling with the hardware in the constructor is a bad idea. Has init() been called before your constructor? If you can't answer that DEFINITIVELY, don't diddle with the hardware in the constructor.

DOH! Noted, will add a start function to run in setup.

But note that as was the pin mode did set. Default mode is INPUT and the led lights up.

 return;

In a constructor? I've never seen a constructor with a return statement. What else would the constructor do when it reached the end?

Is it a problem? I should take it out as unnecessary but is it a problem?

In the header file, public stuff usually appears before private stuff.

I learned to put the data members on top then the functions. But I'm just getting back into classes after over a decade away, fashion is pretty far down on my list of concerns.

I'm not averse to putting more than one class in a library is why.

You really should be. Keeping track of where a class is defined SHOULD be easy - its in the file with the same name.

Because the compiler wouldn't let me use byte.

#include <Arduino.h>

Why would trying to use pin 2 be a problem?

It's not. But, using pin '2' is. The ASCII value for '2' is 50. On a 328-based Arduino, that pin doesn't exist. Since the argument type is char, someone IS going to try to use '2' where they mean 2, and not understand why it doesn't work. YMMV.

but is it a problem?

No. Just looks strange.

fashion is pretty far down on my list of concerns.

Fashion and convention are not the same thing. In the end, it doesn't matter, but when I look at a class, I want to see what I can do with it first. I don't care about the stuff I can't use.