How to write your own Arduino library?

Introduction

In a previous lesson we've met with  7 segment displays. Among everything else, we've learnd why's a library an useful thing. Now is the time to write our own. We will sort out this lesson in files, which need to be made, to make the library functional and transparent.

The thing we want, and will do are functions that write numbers from 0 to 9, function that will shut down all segments on the display and a function that will turn the dot on and off. Let's go...

Header file, is saved with .h extension, it's one of the two necessary files to make the library functional. Bareing in mind that Arduino doesn't do that by itself, here we will define everything that we use in a library. We create a class that we can call in later on in Arduino IDE with all variables and functions that we want to make available to the user  (public)  and those internal ones that we will use to make the library functional (private).

class

What is a class?If you haven't met with the term class by now, it's basically a group of all functions and variables for a certain object. For example, let's take a male human as an object. Every male has or hasn't got  certain caracteristics like IQ, height, mass, height or mustaches. Looking from the programmers point of view, IQ is a whole number variable  int,  height and mass can be float, and mustaches you either have, or you don't so it's gonna be boolean.

With all that behind us,  let's get back to creating of a library. Open up your favourite text editor and let's get in to it:

// creating a class that we will call in Arduino IDE
class Segment  
{
  // functions that user of the library works with
  public:
  // here we will set up a connection with Croduino/Arduino and display
  Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8);  
  void Broj(int n);  // function "broj" will have one parameter, number "n" which we want to show up
  void Tocka();  // function "tocka" will turn the dot on and off 
  void Ocisti();  // function "ocisti" turns off remaining segments
  // internal variables
  private:
  uint8_t _pin1;
  uint8_t _pin2;
  uint8_t _pin3;
  uint8_t _pin4;
  uint8_t _pin5;
  uint8_t _pin6;
  uint8_t _pin7;
  uint8_t _pin8;
  bool b;
};

Don't worry if you have some uncertainties, main part is located in source file  to which well get to in a second. Except for the above, Header file  has to have some more parts. It's surely needed to implement Arduino.h, which is automaticaly added when we compile the code, but not in the process of writing the library itself.

#include "Arduino.h"

This part greatly depends of version of Arduino IDE which the user has installed. So you need to pay much more attention to  this part, however this will be enough for now.

It's a custom to add a small piece of code in to the Header file that checks if the library has been added only once  to the sketch. It should look like this:

#ifndef Segment_h
#define Segment_h

 // part for code

#endif

Finally our Header looks like this:

/*
	Segment.h - Library for 7 segment display common cathode
	Created by e-radionica.com, 2016.
	*/

	#ifndef Segment_h
	#define Segment_h


 #include "Arduino.h"

	class Segment
	{
		public:
			Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8);
			void broj(int n);
			void tocka();
			void ocisti();
		private:
			uint8_t _pin1;
			uint8_t _pin2;
			uint8_t _pin3;
			uint8_t _pin4;
			uint8_t _pin5;
			uint8_t _pin6;
			uint8_t _pin7;
			uint8_t _pin8;
			bool b;
	};
#endif

Now we just need to save it. Let's make a new folder in, for  Windows OS, Documents - Arduino - Libraries and call it Segment, or pick your own name, it's optional. Arduino libraries are explained in detail  here. It's important that all signs in the name ar in ASCII standard. Save the written code in the created folder and add the extension .h,  so the name looks something like this Segment.h. Make sure that the name has no other extensions besides .h, like .txt and simmilar.

Source files

Source file is a part where we store all of our code/logic, and it's written in C++ language. Even tho we've already explained the logic we want to write, feel free to take a peak in  7 segment displays tutorial and remind yourself how to work with that. For starters we need to include Arduino.h and  Segment.h  which we  have just created. Again, ofcourse we write in a text editor.

#include "Arduino.h"
"include "Segment.h"

Great. It's time to write the logic for constructors created in  Header.

//CLASS  ::konstruktor (parametri) 
  Segment::Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8)
  {
	pinMode(pin1, OUTPUT);
	pinMode(pin2, OUTPUT);
	pinMode(pin3, OUTPUT);
	pinMode(pin4, OUTPUT);
	pinMode(pin5, OUTPUT);
	pinMode(pin6, OUTPUT);
	pinMode(pin7, OUTPUT);
	pinMode(pin8, OUTPUT);
	//
	_pin1 = pin1;
	_pin2 = pin2;
	_pin3 = pin3;
	_pin4 = pin4;
	_pin5 = pin5;
	_pin6 = pin6;
	_pin7 = pin7;
	_pin8 = pin8;
	//
	b = false;
  }

First constructor "Segment" is classified as Segment. He's being used to define on which pins of Croduino/Arduino are are pins from the 7 segment display being connected on. If the display is connected in the same way as in  7 segmentn display tutorial, this constructor in Arduino IDE will be called in like this:

/*
Konstruktor proizvoljno ime      pinovi displaya
                            (pin1, pin2, ...         )
                                 pinovi Croduina
---------------------------------------------------- */
Segment         segment     (  2,    3,   4,5,6,7,8,9);

pin is defined because we want to seperate private variables from those which the user of the libraries uses. So, if the user makes soem changes in public varijables it won't interfere with libraries functionability.

b = false; is used to turn on, or turn off the dot on the display. It's constructor will look like this:

void Segment::tocka()
{
	b = !b; // saves switched value
	digitalWrite(_pin8, b);  // it will turn on the dot if it's off and vice versa
} 

We've left with the constructor named broj. It's gonna take a number between 0 and 9 as a parameter and write it on the display. It looks like this:

void Segment::broj(int n)
{

  switch(n)
  {
    case 0:
	digitalWrite(_pin1, 0);
	digitalWrite(_pin2, 1);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 1);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

//... etc. we write it for every single number
   }
}

In Arduino IDE we call it in the following way:

// turn on number 0
segment.broj(0);

segment is an object that we created with help of Segment constructors couple of lines above
broj is a constructor that we've just created
0 is a number that we want to show on the screen

When we write all of the .cpp,  file looks like this:

/*
	Segment.cpp - Library for 7 segment display common cathode
	Created by e-radionica.com, 2016.
	*/

#include "Arduino.h"
#include "Segment.h"

Segment::Segment(uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4, uint8_t pin5, uint8_t pin6, uint8_t pin7, uint8_t pin8)
{
	pinMode(pin1, OUTPUT);
	pinMode(pin2, OUTPUT);
	pinMode(pin3, OUTPUT);
	pinMode(pin4, OUTPUT);
	pinMode(pin5, OUTPUT);
	pinMode(pin6, OUTPUT);
	pinMode(pin7, OUTPUT);
	pinMode(pin8, OUTPUT);
	//
	_pin1 = pin1;
	_pin2 = pin2;
	_pin3 = pin3;
	_pin4 = pin4;
	_pin5 = pin5;
	_pin6 = pin6;
	_pin7 = pin7;
	_pin8 = pin8;
	//
	b = false;
}

void Segment::broj(int n)
{

switch(n)
{
case 0:
	digitalWrite(_pin1, 0);
	digitalWrite(_pin2, 1);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 1);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 1:
	digitalWrite(_pin1, 0);
	digitalWrite(_pin2, 0);
	digitalWrite(_pin3, 0);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 0);
	digitalWrite(_pin6, 0);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 2:
	digitalWrite(_pin1, 1);
	digitalWrite(_pin2, 0);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 1);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 0);
	digitalWrite(_pin8, 0);
	break;

case 3:
	digitalWrite(_pin1, 1);
	digitalWrite(_pin2, 0);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 0);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 4:
	digitalWrite(_pin1, 1);
	digitalWrite(_pin2, 1);
	digitalWrite(_pin3, 0);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 0);
	digitalWrite(_pin6, 0);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 5:
	digitalWrite(_pin1, 1);
	digitalWrite(_pin2, 1);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 0);
	digitalWrite(_pin5, 0);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 6:
	digitalWrite(_pin1, 1);
	digitalWrite(_pin2, 1);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 0);
	digitalWrite(_pin5, 1);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 7:
	digitalWrite(_pin1, 0);
	digitalWrite(_pin2, 0);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 0);
	digitalWrite(_pin6, 0);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 8:
	digitalWrite(_pin1, 1);
	digitalWrite(_pin2, 1);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 1);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;

case 9:
	digitalWrite(_pin1, 1);
	digitalWrite(_pin2, 1);
	digitalWrite(_pin3, 1);
	digitalWrite(_pin4, 1);
	digitalWrite(_pin5, 0);
	digitalWrite(_pin6, 1);
	digitalWrite(_pin7, 1);
	digitalWrite(_pin8, 0);
	break;
}
}

void Segment::tocka()
{
	b = !b;
	digitalWrite(_pin8, b);
} 

void Segment::ocisti()
{
	digitalWrite(_pin1, 0);
	digitalWrite(_pin2, 0);
	digitalWrite(_pin3, 0);
	digitalWrite(_pin4, 0);
	digitalWrite(_pin5, 0);
	digitalWrite(_pin6, 0);
	digitalWrite(_pin7, 0);
	digitalWrite(_pin8, 0);
}

Only thing that remains is to save the file in the same way as Header. We save it in the same folder, but this time with .cpp extension.

Keywords

Keywords is a  .txt file which allows Arduino IDE to recognize keywords from our library and changes their colour in the editor to make it easier to work with. It would look something like this:

Segment KEYWORD1
broj 	KEYWORD2
ocisti	KEYWORD2
tocka	KEYWORD2

We save it in the same folder as previous two files with  .txt extension.

Arduino IDE and example of a code

If we want the example of libraries use to appear in Arduino IDE File-Examples we need to create a subfolder called examples. This is how it will look like in Windows OS:

Arduino IDE libraries

In subfolder examples we will save examples of libraries usage. You can write it in Arduino IDE software, and as an example we will write a countdown on the display.

//add the created library
#include "Segment.h"

//define the Croduino/Arduino pins according to the tutorial
Segment segment(2,3,4,5,6,7,8,9);

void setup() {
}

void loop() {
  // countdown in loop
  for(int i=9; i>=0; i--)
  {
    segment.broj(i); // call numbers from 9 to 0
    delay(1000);     // stop for 1 second
  }

  // in the end, blink couple of times
  for(int j=0; j<3; j++)
  {
    segment.ocisti();
    segment.tocka();
    delay(500);
    segment.broj(0);
    segment.tocka();
    delay(500);
  }
}

Save this code in examples folder. After that it is necessary to close and re-open the Arduino IDE so we could use the library.

We hope that we didn't complicate this simple procedure of making your own Arduino library. If you have any difficulties or upgrades for this tutorial, we're looking forward to your comments.

Leave a Reply