Hi, I'm having an issue including the Arduino.h file in a custom library I am trying to make. This is my first one and i'm a little lost on how to fix it up. It does not appear to be on my include path, but I have also looked at the standard Arduino libraries and cannot seem to find how they include this as well. Thanks for the help
How should others know what you have to correct if you don't give sufficient information?
Post the paths where you have installed your arduino-IDE and the paths where you saved your own library.
Post your custom library and the demo-code that includes this custom library
best regards Stefan
Aren't you developing your library with the Arduino IDE?!? The IDE knows where to find the Arduino.h file.
Oh that was my mistake, I have been using VS code as my text editor I was unsure how to start library building in the ardiuno IDE
well it is simply writing text. Or is there something special about a library?
best regards Stefan
When you are first starting out developing a library you can start with a simple demonstration sketch that shows what you want the library to do. Let's make a library that blinks an LED at a specified rate. We can start with something like File->Examples->02.Digital->BlinkWithoutDelay (I am removing most of the comments for compactness.)
const int ledPin = LED_BUILTIN;
int ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 1000;
void setup()
{
pinMode(ledPin, OUTPUT);
}
void loop()
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
The next step is to move the part you want the library to do into one or more functions. This sketch will do exactly the same thing as before but with very little in setup() and loop() and most code in a function:
const int ledPin = LED_BUILTIN;
int ledState = LOW;
unsigned long previousMillis = 0;
void setup()
{
pinMode(ledPin, OUTPUT);
}
void blink(unsigned long interval)
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
void loop()
{
blink(1000);
}
Now comes the 'library' split. You start by creating a new tab. At the right end of the bar just above the sketch is a little triangle in a square. Click on that and select "New Tab". Name the new tab "BlinkLib.cpp". Now cut the 'blink' function out of the main tab and paste it into the new tab.
If you try to Verify your sketch now you will find some errors. The first is:
BlinkLib.cpp:3:33: error: 'millis' was not declared in this scope
unsigned long currentMillis = millis();
^~~~~~
This is because, unlike the '.ino' files, the '.cpp' files don't automatically get
#include <Arduino.h>
inserted at compile time. Add that line to the top of BlinkLib.cpp and do another Verify.
The next error is:
BlinkLib.cpp:6:23: error: 'previousMillis' was not declared in this scope
if (currentMillis - previousMillis >= interval)
^~~~~~~~~~~~~~
This is because that global variable declaration didn't get moved to the library. In this case, only the library needs it so move the declaration to the top of BlinkLib.cpp. While you're at it, move 'ledState' and 'interval', too. Then try another Verify.
Now you get the error:
sketch_jan05a:13:3: error: 'blink' was not declared in this scope
blink(1000);
^~~~~
That's because the main sketch no longer contains a declaration for the blink() function. This is a good time to create another tab to share declarations between the library and the sketch. Create a new tab named BlinkLib.h (h for 'header'). In that new tab, put the line:
void blink(unsigned long);
Then in the main sketch, add the line:
#include "BlinkLib.h"
This will allow the main sketch to see a declaration of "blink()".
That leads you to the next error:
BlinkLib.cpp:21:18: error: 'ledPin' was not declared in this scope
digitalWrite(ledPin, ledState);
^~~~~~
We used 'ledPin' in setup() so we left the declaration there, but now BlinkLib.cpp needs the declaration. We need a way for setup() to set the pin mode so we create another function in BlinkLib.cpp:
void setPin(int pin)
{
ledPin = pin;
pinMode(ledPin, OUTPUT);
}
Put the declaration of setPin() into BlinkLib.h so the sketch can use it:
void setPin(int);
Move the declaration of 'ledPin' into BlinkLib.cpp. Now you can have setup() call setPin().
All-together you have:
Main Sketch:
#include "BlinkLib.h"
void setup()
{
setPin(LED_BUILTIN);
}
void loop()
{
blink(1000);
}
Library header:
void blink(unsigned long);
void setPin(int);
Library source:
#include <Arduino.h>
#include "BlinkLib.h"
int ledState = LOW;
unsigned long previousMillis = 0;
int ledPin = LED_BUILTIN;
void setPin(int pin)
{
ledPin = pin;
pinMode(ledPin, OUTPUT);
}
void blink(unsigned long interval)
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
Your library is complete! Now you can move the files out of the sketch directory and into a library folder. In your sketchbook directory (see Preferences if you don't know where that is) find (or create) a subdirectory names 'libraries'. That is where all your third-party (not built-in) libraries are kept. In the 'libraries' directory, create a directory named BlinkLib and move BlinkLib.h and BlinkLib.cpp to there.
Now you can delete those two tabs from your sketch and the sketch will still Verify! The compiler will find the BlinkLib directory and make those files part of the Verify process.
Now you can turn your sketch into a library example. Move the .ino file to libraries/BlinkLib/examples/test/test.ino. It will show up in the IDE under: File->Examples->BlinkLib->test
Ah, but there is one small problem. Now you want to blink multiple LEDs at different rates! There is only one "ledPin" variable so if you call "setPin()" a second time, the first pin number is replaced by the second pin number, and blink() will only blink the second pin. The "ledState" and "previousMillis" globals are also shared.
To fix that, we are going to 'encapsulate' the functionality of the library into an 'object'. You can then make multiple 'instances' of the object, each with its own variables.
Let's create an object class named 'Blinker'. This goes into BlinkLib.h in place of the shared function prototypes.
class Blinker
{
public:
Blinker(const byte pin); // "Constructor" called when the object is defined
void blink(const unsigned long interval);
private:
const byte ledPin;
int ledState;
unsigned long previousMillis;
};
Now we can change the test sketch to blink two LEDs:
#include "BlinkLib.h"
Blinker blinker(LED_BUILTIN); // Blink the built-in LED
Blinker blinker2(9); // Blink the LED on Pin 9
void setup()
{
}
void loop()
{
blinker.blink(1000);
blinker2.blink(750);
}
We can try to Verify the test sketch but we have not defined the functions ("member functions" or "methods") declared in the class yet. We get undefined reference errors for Blinker::Blinker() (the constructor) and Blinker::blink() (the function that does stuff!). The second one is easy to fix because we just have to change the declaration of 'blink' from:
void blink(unsigned long interval)
to
void Blinker::blink(unsigned long interval)
That tells the compiler that we are not defining just a function, but a function that is a member ("member function" or "method") of the object class "Blinker". Nothing else about 'blink()' has to be changed because the blink() "method" is perfectly happy to use the "member variables" of its class in place of the old globals. We can remove the globals and the setPin() function from BlinkLib.cpp because they are no longer used:
#include <Arduino.h>
#include "BlinkLib.h"
void Blinker::blink(unsigned long interval)
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
Now that "Blinker::blink()" is taken care of, we need to define Blinker::Blinker(). This is the "constructor": the function automatically called when an object of this class (an "instance") is created ("instantiated"). It is a good place to do some initialization. We can put this function in BlinkLib.cpp:
Blinker::Blinker(const byte pin)
{
ledPin = pin;
ledState = LOW;
previousMillis = 0;
pinMode(ledPin, OUTPUT);
previousMillis = millis();
}
The only problem is, "ledPin" is declared with the keyword 'const' so it can't be assigned a value inside the constructor. It has to be given a value BEFORE the body of the constructor so we have to use some special syntax:
Blinker::Blinker(const byte pin) : ledPin(pin)
{
ledState = LOW;
previousMillis = 0;
pinMode(ledPin, OUTPUT);
previousMillis = millis();
}
Yay! The sketch compiles without any errors or warnings!
Except for one thing. A thing the compiler can't warn you about because it doesn't know. The Arduino library isn't initialized until just before your setup() function is called. That is AFTER all of the global variables are initialized. That includes calling the constructor of every global object instance. In other words, your object class can't safely call any Arduino functions (like "pinMode()" or "millis()") in the constructor! You may have wondered why some Arduino library objects have a 'begin()' method that you have to call from setup(). That's why.
To make our object safe to use we add a 'begin()' method (the name is just an Arduino convention) and call the Arduino functions from there.
void Blinker::begin()
{
pinMode(ledPin, OUTPUT);
previousMillis = millis();
}
That goes in BlinkLib.cpp and we call it in setup().
We have to add the "void begin();" declaration to the class (in BlinkLib.h) and we're ready to go!
All-together you have:
Main Sketch:
#include "BlinkLib.h"
Blinker blinker(LED_BUILTIN); // Blink the built-in LED
Blinker blinker2(9); // Blink the LED on Pin 9
void setup()
{
blinker.begin();
blinker2.begin();
}
void loop()
{
blinker.blink(1000);
blinker2.blink(750);
}
Library header:
[code]
class Blinker
{
public:
Blinker(const byte pin); // "Constructor" called when the object is defined
void begin(); // A function to call to do initialization
void blink(const unsigned long interval);
private:
const byte ledPin;
int ledState;
unsigned long previousMillis;
};
[/class]
Library source:
#include <Arduino.h>
#include "BlinkLib.h"
Blinker::Blinker(const byte pin) : ledPin(pin)
{
ledState = LOW;
previousMillis = 0;
}
void Blinker::begin()
{
pinMode(ledPin, OUTPUT);
previousMillis = millis();
}
void Blinker::blink(unsigned long interval)
{
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.