Remove .ino file, setup() and loop() functions

Do you have use a .ino file with setup() and loop() functions.

I would much prefer to use a main.cpp file with a main() function and handle the setup and while(1) loop myself.

Yes you have to use that - they are the entry points to your application - main() is buried in system firmware - the firmware is much more than just the application.

What is it you want to achieve with main that you can’t achieve with setup/loop?

Nothing really, i’m just not a fan of the Arduino like notation.

Plus I don’t like having to declare variables/objects at the top of the .ino file so they can be instantiated in setup() and called in loop().

It’s not really an issue, I was just asking because I thought I had seen someone doing it somewhere on the forums.

Thanks for getting back so quick.

The application is a dynamically linked module with setup and loop as the main entry points. If you want to create a main() function then you’d have to code everything yourself - bare-metal programming.

Not sure I follow about objects being declared at the top of the file and instantiated in setup() - they are instantiated at the point of declaration if they are global instances. You don’t have to use an ino file - you can make it a .cpp file and forgo the preprocessor. You’ll then have to include “application.h” manually and use forward declarations/function prototypes where needed.

I mean the below, but maybe i’m misunderstanding the correct way to instantiate and use objects.

#include "application.h"
#include "neopixel.h"

Adafruit_NeoPixel* _strip = NULL;

void setup()
{
    _strip = new Adafruit_NeoPixel(1, A0, WS2811);
    _strip->begin();
    _strip->setBrightness(64);
}

void loop()
{
    _strip->setPixelColor(0, 255, 255, 255);
    _strip->show();
}

compared with:

#include "application.h"
#include "neopixel.h"

int main()
{
    Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, A0, WS2811);

    while(1)
    {
        _strip->setPixelColor(0, 255, 255, 255);
        _strip->show();
    }
}

If I understand your second point correctly, I can use a main.cpp and main.h file instead of main.ino but I would still need to use setup() and loop()?

Obviously :wink:
The programmer whos code you quoted chose to do it that way, but you can also instantiate an object like this

 Adafruit_NeoPixel strip(1, A0, WS2811);  // this would also be the "better" form in your own sample

That has nothing to do with Arduino, .ino, setup() or loop().

And about the while(1) you’d be using alternatively you’d also need to do all the cloud house keeping that is otherwise done between iterations of loop().

Just for illustration the current setup works like this (obviously ignoring FreeRTOS and other internals)

#include "application.h"
#include "neopixel.h"

Adafruit_NeoPixel strip(1, A0, WS2811);

void setup();
void loop();

int main()
{
    setup(); 

    while(1)
    {
        doSystemStuff();  // let's imagine this is declared in application.h 
        loop();           // do user stuff
        doOtherStuff();   // let's imagine this is declared in application.h
    }
}

void setup() { ... }
void loop() {
    strip.setPixelColor(0, 255, 255, 255);
    strip.show();
}

What’s wrong with this?

@joe4465, in your example you instantiate _strip as a global pointer then create the object in setup(). You can simply create the object globally in the first place, without the pointer though both will work.

What @mdma was referring to with .INO files is that you can use .CPP files instead, as long as you include “application.h” since .INO files go through the pre-processor. However, you CANNOT define main.cpp and main.h files since they are part of the system firmware. If you wish to do so, you can build locally and modify the existing main files but to the detriment of compatibility with future firmware releases.

1 Like

OK fine, thanks for the input.

Is there any limitation to creating the object globally before setup()? Mainly are the objects created in the order they are written and can I access the hardware i.e. call digitalWrite(pin, LOW); in the constructor or do I need a begin() function (similar to the Neopixel lib).

If a begin() function is needed then surely it is better to have a global pointer and create the object in setup as it ensures the object is fully ready before it is used, removing the risk of functions being called on an object that is not yet fully setup. Although thinking about it this would mean its possible to call functions on a NULL pointer which is also not ideal.

If you just want code to run at initialization time, rather than setup() time, we have the STARTUP() macro.

You can of course create a global instance of a class and have code run in the constructor - that’s what the startup macro does behind the scenes.

There’s no magic here when compiling a .cpp file - it’s all C++, and all the usual conventions hold for a regular C++ module.

1 Like