Skip to main content
Fixed typo.
Source Link
Nick Gammon
  • 38.7k
  • 13
  • 67
  • 125

If you run with the "empty sketch" concept you still need to include libarieslibraries used elsewhere in the project, for example in your main .ino file:

If you run with the "empty sketch" concept you still need to include libaries used elsewhere in the project, for example in your main .ino file:

If you run with the "empty sketch" concept you still need to include libraries used elsewhere in the project, for example in your main .ino file:

Added an explanation about why "probably" you should keep separate .h and .cpp files
Source Link
Nick Gammon
  • 38.7k
  • 13
  • 67
  • 125

Why "probably"?

As my example shows you can put everything together in one file. For larger projects it is better to be more organized. Eventually you get to the stage in a medium to large-size project where you want to separate out things into "black boxes" - that is, a class that does one thing, does it well, is tested, and is self-contained (as far as possible).

If this class is then used in multiple other files in your project this is where the separate .h and .cpp files come into play.

  • The .h file declares the class - that is, it provides enough detail for other files to know what it does, what functions it has, and how they are called.

  • The .cpp file defines (implements) the class - that is, it actually provides the functions, and static class members, that make the class do its thing. Since you only want to implement it once, this is in a separate file.

  • The .h file is what gets included into other files. The .cpp file is compiled once by the IDE to implement the class functions.

Libraries

If you follow this paradigm, then you are ready to move the entire class (the .h and .cpp files) into a library very easily. Then it can be shared between multiple projects. All that is required is to make a folder (eg. myLibrary) and put the .h and .cpp files into it (eg. myLibrary.h and myLibrary.cpp) and then put this folder inside your libraries folder in the folder where your sketches are kept (the sketchbook folder).

Restart the IDE and it now knows about this library. This is really trivially simple, and now you can share this library over multiple projects. I do this a lot.

Why "probably"?

As my example shows you can put everything together in one file. For larger projects it is better to be more organized. Eventually you get to the stage in a medium to large-size project where you want to separate out things into "black boxes" - that is, a class that does one thing, does it well, is tested, and is self-contained (as far as possible).

If this class is then used in multiple other files in your project this is where the separate .h and .cpp files come into play.

  • The .h file declares the class - that is, it provides enough detail for other files to know what it does, what functions it has, and how they are called.

  • The .cpp file defines (implements) the class - that is, it actually provides the functions, and static class members, that make the class do its thing. Since you only want to implement it once, this is in a separate file.

  • The .h file is what gets included into other files. The .cpp file is compiled once by the IDE to implement the class functions.

Libraries

If you follow this paradigm, then you are ready to move the entire class (the .h and .cpp files) into a library very easily. Then it can be shared between multiple projects. All that is required is to make a folder (eg. myLibrary) and put the .h and .cpp files into it (eg. myLibrary.h and myLibrary.cpp) and then put this folder inside your libraries folder in the folder where your sketches are kept (the sketchbook folder).

Restart the IDE and it now knows about this library. This is really trivially simple, and now you can share this library over multiple projects. I do this a lot.

Source Link
Nick Gammon
  • 38.7k
  • 13
  • 67
  • 125

How the IDE organizes things

First thing, this is how the IDE organizes your "sketch":

  • The main .ino file is the one of the same name as the folder it is in. So, for foobar.ino in foobar folder - the main file is foobar.ino.
  • Any other .ino files in that folder are concatenated together, in alphabetic order, at the end of the main file (regardless of where the main file is, alphabetically).
  • This concatenated file becomes a .cpp file (eg. foobar.cpp) - it is placed in a temporary compilation folder.
  • The preprocessor "helpfully" generates function prototypes for functions it finds in that file.
  • The main file is scanned for #include <libraryname> directives. This triggers the IDE to also copy all relevant files from each (mentioned) library into the temporary folder, and generate instructions to compile them.
  • Any .c, .cpp or .asm files in the sketch folder are added to the build process as separate compilation units (that is, they are compiled in the usual way as separate files)
  • Any .h files are also copied into the temporary compilation folder, so they can be referred to by your .c or .cpp files.
  • The compiler adds into the build process standard files (like main.cpp)
  • The build process then compiles all the above files into object files.
  • If the compilation phase succeeds they are linked together along with the AVR standard libraries (eg. giving you strcpy etc.)

A side-effect of all this is that you can consider the main sketch (the .ino files) to be C++ to all intents and purposes. The function prototype generation however can lead to obscure error messages if you are not careful.


Avoiding the pre-processor quirks

The simplest way of avoiding these idiosyncrasies is to leave your main sketch blank (and not use any other .ino files). Then make another tab (a .cpp file) and put your stuff into it like this:

#include <Arduino.h>

// put your sketch here ...

void setup ()
  {

  }  // end of setup

void loop ()
  {

  }  // end of loop

Note that you need to include Arduino.h. The IDE does that automatically for the main sketch, but for other compilation units, you have to do it. Otherwise it won't know about things like String, the hardware registers, etc.


Avoiding the setup/main paradigm

You don't have to run with the setup/loop concept. For example, your .cpp file can be:

#include <Arduino.h>

int main ()
  {
  init ();  // initialize timers
  Serial.begin (115200);
  Serial.println ("Hello, world");
  Serial.flush (); // let serial printing finish
  }  // end of main

Force library inclusion

If you run with the "empty sketch" concept you still need to include libaries used elsewhere in the project, for example in your main .ino file:

#include <Wire.h>
#include <SPI.h>
#include <EEPROM.h>

This is because the IDE only scans the main file for library usage. Effectively you can consider the main file as a "project" file which nominates which external libraries are in use.


Naming issues

  • Don't name your main sketch "main.cpp" - the IDE includes its own main.cpp so you will have a duplicate if you do that.

  • Don't name your .cpp file with the same name as your main .ino file. Since the .ino file effectively becomes a .cpp file this also would give you a name clash.


Declaring a C++-style class in the same, single .ino file (have heard of, but never seen working - is that even possible?);

Yes, this compiles OK:

class foo {
  public:
};

foo bar;

void setup () { }
void loop () { }

However you are probably best off to follow normal practice: Put your declarations in .h files and your definitions (implementations) in .cpp (or .c) files.


A bit more detail here.