Ok, let’s give this a try…
After some googling I found this. It is based on the implementation of an arduino-capable VS-extension. First cite, no offense :
In a nutshell:
- If you don’t want to learn about C++ declarations and header files, stay with .INO files
- If you have a more complex sketch with many separate source files that use classes and methods from each other, you will have more control and overview if you use “classic” C++ .CPP and .H files
Nevertheless based on the implementation choosen in this extension you could mimic the standard Arduino-IDE behaviour by edediting files like this:
- rename your “main”-file with the
setup
andloop
functions to*.cpp
and add#include "Arduino.h"
at the very top of this file - rename all other
*.ino
-files that are part of your project to*.h
- At the end of your “main”-
*.cpp
-file write#include "foo.h"
,#include "bar.h"
, etc. for every*.h
-file you have wherefoo
andbar
are the actual names of the needed files - create function prototypes in a seperate file. To do this create a new file called
prototypes.h
and add a prototype for each function defined in one of your other*.h
-files there. - include the created
prototypes.h
(#include "prototypes.h"
) at the top of your “main”-*.cpp
-file right below#include "Arduino.h"
Now you are ready to go…
Example:
main.ino
:
void setup() {
;
}
void loop() {
;
}
library.ino
:
int add(int a, int b) {
return (a+b);
}
Those get turned into
main.cpp
:
#include "Arduino.h"
#include "prototypes.h"
void setup() {
;
}
void loop() {
;
}
#include "library.h"
library.h
:
int add(int a, int b) {
return (a+b);
}
prototypes.h
:
int add(int a, int b); // This is a function prototype - basically the function-head without a {}-block ended by a semicolon, you need one of those for each function you want to use
I really want to point out that this style isn’t particulary beautiful… no, it really is bad, very bad as it could cause a lot of errors… but it seems this is the “easy” way to convert a *.ino
-project quickly.
- Why does this work?
#include
is a so called preprocessor directive. Before you code gets translated to something your Arduino can work with (by a compiler and a linker), the preprocessor does some simple stuff (like text replacement). By telling the preprocessor toinclude
something (everything in your source-code beginning with an#
is a preprocessor directive) you basically tell him to simply copy/insert the text from the included file at that point. The file created is simply a text-file with all the included files copied together into one… - Why do you need those strange function prototypes?
The compiler translating your sourcecode works top-to-bottom. When you include the*.h
at the end of your “main”-file the moment you might call the functionadd()
in yourloop
the compiler doesn’t know there is aadd()
-function defined; you get an error. To prevent that you have a prototype at the top so the compiler knows that somewhere there is a definition of that function and he doesn’t care about it anymore, no matter where the actuall definition is.
void add(int a, int b); // A function prototype or declaration to "please the compiler"
void add(int a, int) { // The actual function definition with the logic
return (a+b);
}
- Why not just
#include
all those*.h
-files at the top of my “main” so I don’t need prototypes?
Well, idk, this is a bad style in eather way, I just stuck with the explenation given here. Just make sure you include other files AFTER theArduino.h
so all following files inserted “have access” to it.
In the end I still recommend:
Just do it the proper way and learn splitting into multi-file projects the “normal” C/C++ style; it’s not even that big of a step from what I just wrote… You can not just place functions in other files but global variables and classes too, not to mention that it provides a way clearer structure for large projects, maybe even projects with multiple people.