Do I need to create my own libraries?

AshPowers

Well-known member
Hi All,

I have a project using a T4 with a 2.8" TFT w/touch and it is heavily menu driven. The length of the code is stacking up really quick just to create the different screen layouts, touch position coordinates and handling, etc etc. I would like to clean up the code and stuff a lot of this screen code into separate files (libraries?). Or at least I *think* this would be a cleaner approach. Perhaps I have the terminology wrong?

It would be nice to have each of the different screen layouts stored as separate files and called only when needed by a ~single line of code in the main program. This way, when/if I want to change a particular screen appearance I can open the file associated with that screen and edit it. As it stands there is about 1500 lines of code in my main program of which about 90% of it is drawing lines, placing text, etc etc for each of the screen layouts. It is quite unwieldy...

Thanks!
-Ash
 
Why not just put the code in different Tabs? Click on that tiny downpointing triangle up there on the right side....
 
Just as you would do from your former only window.

Dont feel ashamed - i had the same Problem......
 
there is maybe 3 ways of doing this:
1. the "gonna be messy" one with code directly splitted in each tab.
2. the C variant with cpp class header file .h + cpp (functions) .cpp
3. the more like C# JAVA style, with everything in the header file just like a big class

I must say that I prefer the 3:rd, mostly because it generates less errors for beginners.

here is all of them:

1. main.ino
Code:
#include <Arduino.h>
#include "file1.h"
#include "file2.h"

void setup () { //setup code here }
void loop() { subtract(1, 2); add(1+2); }

1. file1.h
Code:
#include <Arduino.h>
void add(int a, int b) {return a+b;}

1. file2.h
Code:
#include <Arduino.h>
void subtract(int a, int b) {return a-b;}

2. main.ino
Code:
#include <Arduino.h>
#include "classA.h"

ClassA classA; // here the name should begin with lower case for easier read.

void setup () { //setup code here }
void loop() { classA.add(1+2); }

2. classA.h
Code:
#ifndef classA_h
#define classA_h
#include <Arduino.h>
class ClassA { // the class name don't need to be same as filename
  public:
    int result;
    void add(int a, int b);
}

2. classA.cpp
Code:
#include <Arduino.h>
#include "classA.h"
void ClassA::add(int a, int b) { result = a+b; return result; }

3. main.ino
Code:
#include <Arduino.h>
#include "classA.h"

ClassA classA; // here the name should begin with lower case for easier read.

void setup () { //setup code here }
void loop() { classA.add(1+2); }

3. classA.h
Code:
#ifndef classA_h
#define classA_h
#include <Arduino.h>
class ClassA { // the class name don't need to be same as filename
  public:
    int result;
    void add(int a, int b) { result = a+b; return result; }
}
 
And good luck with the graphics stuff, it more fun to create all that stuff yourself.
It more like a challenge.
And also you learn a lot.
 
Post #6 has ways that should be workable ...

But ...

> It can just be done by making a series of INO files that the builder combines transparently with its creation of prototypes so the user doesn't have to.

Or

> Main.INO can have normal .c or .cpp files in that folder and they get built separately and linked along with the INO - so normal c/cpp rules for prototypes apply in header files or whatever.
 
OK, I split my code out to several different tabs and it still worked just fine, no issues. However, after saving this project and then re-opening the IDE and the main .ino file, we have a problem. Each of the tabs I created were saved as separate .ino files and the compiler is crying at me that all of these subs were not declared within this scope.
I'm assuming that when this was saved, it treated each tab as a separate program (which is why it saved each of them to a separate .ino file).... and in doing so there is no longer any correlation between them to the main .ino file.

How do I correct this issue? Manicksan suggested a few ways to set this up and it sounds like the 3rd option is best suited for my level of experience and will satisfy my goal, however, I am now a bit lost in the woods on what the steps are to save these "tabs" as .h files and link the main .ino to all of them.

Thanks for all the help, guys!!
 
Close the IDE perhaps and inspect the folder. If the IDE made them in folder that is one way it does it perhaps.

AFAIK: if the other INOs are in the same folder the named folder INO is the main and the others are included.
 
I think the problem is that when your just create new tabs and dont give them a name with a file extension
.h .cpp .c .hpp (the ones that gets loaded when project is opened)
The ide converts them to .ino files automatically.
Can't really look at the arduino src code right now, but can verify it when I have done so.
 
And by the way the "main".ino is always the one with the same name as the folder. This is the rule of the IDE.
 
This is actually a great question. I too had tons of code for sliders, menus, etc. I created my own libs for lot's of the common UI stuff I use. Moving code to libraries did take some learning, but my code is much cleaner. I also post many of my libs on github to help alleviate pain others may endure.

If you are creating menus and such you feel you will use on future projects, i would recommend putting your stuff into a lib--otherwise you will be copying the added .ino files around.
 
I did not give them a file extension so I think that is where the problem came into play... What is the decision making process involved between naming them "*.h" or "*.cpp" files?
 
If you go for #3 you should use either .h or .hpp for clarity.
An make it easier for others to understand the code.

I looked at the source and found out that the extensions .hh and .s are also reopened in the IDE (but I don't know what s is used for, but hh is a alternative to hpp)
 
.s files are for ASM

If this ends up as a library working out the .h Header and .c/.cpp source file details with proper prototypes etc. now will make that transition easier.
 
What is the decision making process involved between naming them "*.h" or "*.cpp" files?

The simplest way is to name all your files with .ino extension. The Arduino IDE does special processing of all .ino files which automatically handles some of the finer details for you.

The more conventional C / C++ way is to put all (or most, except inline stuff) into the .cpp or .c or .s files, and put definitions of only things meant to be used from other files into the .h files.

For a trivial example, a definition of a function would go into a .h file. For example, you might create quadratic.h with this.

Code:
float quadratic(float x, float a, float b, float c);

The main idea is the .h defines the function, but doesn't have its actual code.

You would include this quadratic.h file in both your main program and in the quadratic.cpp file with the actual code. Even though it's not strictly necessary to also include it in quadratic.cpp, doing so allows the compiler to check that the definition really is the same as the actual code. This is the main rationale for the convention of .h files.

Then quadratic.cpp might look like this.

Code:
#include "quadratic.h"

float quadratic(float x, float a, float b, float c)
{
  return a * x * x + b * x + c;
}

This is a trivial example. Usually a .cpp file will have a collection of complex functions. Often times those functions use other code which isn't meant to be accessible outside of that .cpp file. Those aren't defined in the .h file, so other code in your project has no ability to use them. They are usually also created with "static", which means other files can't access them even if they "cheat" and create their own definitions. Most people consider making as much of the code static or other wise inaccessible as a good practice. The set of functions which are accessible is usually called an API (application programming interface) - though that term kind of carries a coronation that the collection of functions has some "large" functionality, not just a trivial equation like this example.


But if you're just organizing your own code, the first and simplest step is probably to just put everything into .ino files. You can always do more later.

Some people go a little overboard and end up putting a lot more work into all sorts of complex effort (eg, also defining lots of custom names & data types), sometimes much more total time than it can possibly ever save, and sometime even adding so much complexity that the end result is harder and more error prone to use than if they had just left everything all together. Don't fall into that trap. Keep it simple if you can. Best to just go with several .ino files and do the more complex way if you feel it's really needed. Often that point is when you're ready to reuse the code in another project, or publish it as a library for other people. Usually that's when the extra work for .cpp and .h files structured the conventional way is worthwhile.
 
just of curiosity I tried Pauls example of just having one additional .ino file

and it don't work

blink.ino
Code:
class Blink
{
  public:

    void begin() {
      pinMode(led, OUTPUT);
    }
    void update() {
      digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);               // wait for a second
      digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);               // wait for a second
    }
  private:
  int led = 13;
};

blinkExample.ino
Code:
#include "blink.ino"

Blink blink;
// the setup routine runs once when you press reset:
void setup() {
  // initialize the digital pin as an output.
  blink.begin();
}

// the loop routine runs over and over again forever:
void loop() {
  blink.update();
}

but if I change the file endings (both of the file and the include directive)
of blink.ino to (blink.h or blink.hpp) it works.

Also tried removing the include but same error.
 
When all are INO then do not use includes, as tried - because Arduino automatically does that combination.

"and it don't work" is lacking details to understand why it didn't work. What did the Verbose compile output show.
 
BTW using class makes naming a bit easier,
I am used to program in C where my names always end up like this (to separate names from different included files)

and think it's cleaner to have a dot instead of a _

Code:
    void Blink_begin() {
      pinMode(led, OUTPUT);
    }
    void Blink_update() {
      digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);               // wait for a second
      digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);               // wait for a second
    }
 
just of curiosity I tried Pauls example of just having one additional .ino file
and it don't work

The Arduino build system copies all *.inos into one huge *.cpp file which will be compiled. Depending on which file is copied on top this will work or not. You can have a look at the composed *.cpp file it is in the build folder. Here what your example generates:

Code:
include <Arduino.h>
#line 1 "C:\\Users\\lutz\\Documents\\Arduino\\sketch_dec19a\\sketch_dec19a.ino"

Blink blink;
// the setup routine runs once when you press reset:
#line 5 "C:\\Users\\lutz\\Documents\\Arduino\\sketch_dec19a\\sketch_dec19a.ino"
void setup();
#line 11 "C:\\Users\\lutz\\Documents\\Arduino\\sketch_dec19a\\sketch_dec19a.ino"
void loop();
#line 5 "C:\\Users\\lutz\\Documents\\Arduino\\sketch_dec19a\\sketch_dec19a.ino"
void setup() {
  // initialize the digital pin as an output.
  blink.begin();
}

// the loop routine runs over and over again forever:
void loop() {
  blink.update();
}

#line 1 "C:\\Users\\lutz\\Documents\\Arduino\\sketch_dec19a\\blink.ino"
class Blink
{
  public:

    void begin() {
      pinMode(led, OUTPUT);
    }
    void update() {
      digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);               // wait for a second
      digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);               // wait for a second
    }
  private:
  int led = 13;
};

This of course can not compile since it uses the class "Blink" before it is declared.

My personal recommendation: Just do regular *.cpp and *.h files and you will be fine.
Your c# style of declaring everything inline in the class is OK in principle but a soon as the classes get larger it quickly gets messy. If you place the declaration of your class in the header and the code in the corresponding *.cpp file you can quickly browse the class declaration to see the interface without the need to wade through all the code which should be an implementation detail anyway.
 
I wrote this before reading the post #22

It seems like when using additional ino files
class is not supported

even tried using forward declaration of the class:
class Blink;

but the it says
Code:
Blinkexample:3: error: aggregate 'Blink blink' has incomplete type and cannot be defined
 Blink blink;
       ^
aggregate 'Blink blink' has incomplete type and cannot be defined

the original error message was:
Code:
Blinkexample:2: error: 'Blink' does not name a type
 Blink blink;

but when I just created a simple function in the ino file
outside of the class it works
Code:
void helloWorld()
{
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);               // wait for a second
      digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);  
}

I believe it's a limitation of Arduino,
and it makes sense because for beginners they should not have to learn all that standard C/C++ stuff.
 
Good note @luni - the IDE parses for function prototypes - but classes and 'global' vars are 'in place' after copy (and before) and not given references.

Indeed for the post #1 - in the end a library would be best in multiple files - so *.cpp and *.h files now will make that easier.
 
Back
Top