1

I am now programming for two Arduinos. One is used as Tx and the other is Rx. Of course they are programmed by different codes, but they share some same .h files I programmed(let's say 'share.h'), which are not libraries and shouldn't be put in Arduino's 'library' folder.

So I put 'share.h' and main.ino in one folder, and the ino is like:

#include "share.h"
#define TX
#ifdef TX
void setup(){...something for Tx...}
void loop(){...}
#else
void setup(){...something for Rx...}
void loop(){...}
#endif

The shortage is that every time I want to update my code to the two unos, I have to: first change the board port to 40(the Tx uno) in ide, add the #define line, and upload. Then I have to change port to 42(the Rx one), comment the #define line and upload. So inconvenient!

So do you have any good ideas? Much appreciation!

8
  • So, you want a common file, but you don't want to put it in a common file location? Jul 11, 2015 at 12:44
  • Are you on a real operating system, or are you using Windows?
    – Majenko
    Jul 11, 2015 at 12:53
  • @Majenko Sorry but can't quite follow you. What's a real operating system? I'm using windows 7.
    – ch271828n
    Jul 11, 2015 at 12:59
  • 1
    Then you're not using a real operating system and I can't suggest a way to do it in the Arduino IDE. If you were using a real operating system like Linux or OS X then you could create a symbolic link so that the share.h file was shared between two locations. Instead you can't because windows doesn't provide that most basic of facilities.
    – Majenko
    Jul 11, 2015 at 13:00
  • @Ignacio Vazquez-Abrams Er you can say it is, and there may be other ways.
    – ch271828n
    Jul 11, 2015 at 13:02

6 Answers 6

2

Ok, first of all you have to answer this question:

How can I tell the compiler what program it should compile?

The first (and easiest) solution is to have the preprocessor to this job. It's just a matter of writing two /...

Personally, instead of wrapping everything in an ifdef, I would have done something like

#include "share.h"
#define TX
#ifdef TX
#define setup_tx() setup()
#define loop_tx() loop()
#else
#define setup_rx() setup()
#define loop_rx() loop()
#endif

void setup_tx(){...}
void loop_tx(){...}

void setup_rx(){...}
void loop_rx(){...}

This way I could put the two different setup/loop pairs in two different files (e.g. tx.ino and rx.ino). Moreover the ifdef block can be moved in an h file.

NOTE: I'm not sure wheter the function redefinition works well, because I never tried it. If it doesn't work you can try doing the opposite (i.e. #define setup() setup_tx() and so on) or, in the end, make single-line functions (i.e. void setup(){setup_tx();} and so on).

Another solution can be applied if the processors are different. For instance if you have an Arduino UNO as transmitter and an Arduino Mega 2560 as a receiver, you could write:

#ifdef __AVR_ATmega2560__
- receiver functions
#else
- transmitter functions
#endif

But this would require you to switch processor along with the port.

The third solution is to place the shared h file in an include directory. You can do this by using a common include dir:

The include path includes the sketch's directory, the target directory (/hardware/core//) and the avr include directory (/hardware/tools/avr/avr/include/), as well as any library directories (in /hardware/libraries/) which contain a header file which is included by the main sketch file.

(See here)

You can also pass the -Idir option to avr-gcc to include also dir in the include dirs list, but this requires you to change the boards.txt file.

The last solution I can think at is to compile both programs, load the same files on both arduinos and then choose at runtime what is the correct program to use by assinging a pin to the "choice of program" function.

For instance you assing pin 8 to this function. On the TX board you connect pin 8 to VCC, while on the RX board you connect it to GND. Then the program is:

#include "share.h"

// Loop function callback (to speed things up)
typedef void (*loopfunction)();
loopfunction currentloop;

const int RXTX_PIN = 8;

void setup()
{
    pinMode(RXTX_PIN,INPUT);
    if (digitalRead(RXTX_PIN))
    {
        setup_tx();
        currentloop = loop_tx;
    }
    else
    {
        setup_rx();
        currentloop = loop_rx;
    }
}

void loop()
{
    currentloop();
}

void setup_tx(){...}
void loop_tx(){...}

void setup_rx(){...}
void loop_rx(){...}

IMHO the best solution is the first one, i.e. the define one. But... You should choose the best for your particular problem.

Bye

1
  • Thanks. But I find another way. See it in my own answer. :) On account of your hard work by commenting such a long answer, I choose your answer as the "accepted answer".
    – ch271828n
    Jul 12, 2015 at 3:38
2

I confronted this exact issue a little while back when writing some sketches that hard shared information. In particular github.com/nickgammon/arduino_sketches

Whilst another IDE may help, I wanted to make my sketches usable by people with the default IDE.

There are a few (annoying) issues here:

  • You can't use relative folders as suggested in another answer, because the IDE copies your current sketch folder to a temporary folder and compiles from there. It won't copy other nearby folders that happen to be mentioned in .h files.

  • You can make soft links (in Linux anyway) as suggested, however that makes it hard to do Git control on them. My first attempt had the link (only) appear in GitHub, which meant that the links didn't compile, once you downloaded them (via the .zip file option in GitHub).

  • I switched to hard links, but then had another issue. If you edit a file in the IDE, and save it, evidently this becomes a new file, and so the files in other folders, which are now hard-linked, have the older version and not the newer version.


The best solution I could come up with (and I am open to suggestions) was to have a "master" sketch - which has the "real" files you want to include. The other folders have links to them. However if you change the master folder you have to recreate the hard links. I wrote a shell script to do that, but it is still an ugly solution. However since it is a manual process anyway, under Windows you could simply make a copy of the files, when you change the master one.

The other (simpler) alternative would be to make a library, and then simply change the files in that library. That gives you better Git management. The only thing is that you have to edit the library, and then go and test the sketch. It's not that bad.

And I found that after I added the h as library, no matter how I change the content of the h, the first version is always used in ide.

That shouldn't happen unless the IDE doesn't expect the library to change in-between compiles. If that is the case, even the library idea has flaws.

7
  • Since it is unavailable to use ./../share.h, I think I may use absolute path. I can define the absolute path of the lib in a .h, and anyone else using my program only need to change this.
    – ch271828n
    Jul 12, 2015 at 1:28
  • Yes, presuming they have the exact same folder setup as you do. Better not put your name for the home folder, for example. Better hope that they have the sketchbook folder in the same place you have. There are a lot of things that can go wrong there.
    – Nick Gammon
    Jul 12, 2015 at 2:19
  • Thanks. And I find another way. See it in my own answer. :)
    – ch271828n
    Jul 12, 2015 at 3:39
  • @NickGammon Your first point there about relative paths is making a wrong assumption. It's not because the IDE copies the files. You assume that a relative path is only from the "build" location, but it isn't. It's taken from each of the given include paths (-I...) in turn until it's found. The build location happens to be one of those paths, as are a myriad of others (including all the library paths and system include locations). If the IDE included the sketch folder in the list of includes then you could use relative paths even with it copying files to the build area. By the way, it ...
    – Majenko
    Jul 12, 2015 at 10:48
  • 1
    Anyway, I tried the idea out of using the ../whatever/foo.h idea and it didn't work, so my assumption wasn't exactly wrong.
    – Nick Gammon
    Jul 12, 2015 at 12:07
1

Because you're using Windows there is no easy way of doing what you want to do.

If you were on Linux or OS X you would be able to create a symbolic link so that your shared file can exist in more than one location:

$ ln -s /path/to/real/share.h share.h

On Windows there is then just two options that I can think of:

  1. Turn your shared file into a library. I don't know why you are so adverse to this, since it is by far the simplest option. Just create a folder "MyProjectShared" in your libraries folder, then name you shared header "MyProjectShared.h" within that folder. Then #include <MyProjectShared.h>. Of course, choose a sensible name not MyProjectShared.

  2. Change to a different IDE that will allow you to add include locations. One example is my UECIDE which allows you to add the line:

    #pragma parameter board.flags=-IC:/Path/To/Other/Includes

to the top of your sketch, which adds another location to find header files while compiling.

Another thought has just occurred to me. If the two sketches are side by side in a folder (say Arduino/Sketch1 and Arduino/Sketch2) then you may be able to use a relative path.

In Sketch2, do:

#include "../Sketch1/share.h"
12
  • Thx. I don't use library because I use git for my code. If there are a lot of folders dispersing in my computer, it is hard to track them in git(maybe there is a way to approach it?). And I found that after I added the h as library, no matter how I change the content of the h, the first version is always used in ide... I will try the idea tomorrow.
    – ch271828n
    Jul 11, 2015 at 13:14
  • @Turtle I have just had another thought - take a look at my edit.
    – Majenko
    Jul 11, 2015 at 13:19
  • I remembered that Arduino ide doesn't support sub folder. Anyway I will have a try tomorrow.
    – ch271828n
    Jul 11, 2015 at 13:21
  • @Turtle It doesn't need to - two separate sketches, as long as they are in the same place, you should be able to use a relative path.
    – Majenko
    Jul 11, 2015 at 13:21
  • My esthetic preference would be to put share.h in .. instead of in Sketch1, so the include looks like #include "../share.h" Jul 11, 2015 at 17:17
1

You can feed the compiler a command-line switch, -D<define_name>, so for your TX you could have a project that has -DTX and for the RX -DRX.

Then you can share the code between the two projects and you don't need to change the code when you're compiling.

1
  • But how to do this in arduino ide?
    – ch271828n
    Jul 12, 2015 at 3:17
1

Thanks to everybody, now I get a better solution. It is changing the build path to our working directory, and then we can use relative path!

Here are the deatiled steps:

  1. Click IDE's File-Preferences and find where it storages preferences.txt. Mine is at C:\Users\Administrator\AppData\Roaming\Arduino15\preferences.txt
  2. In the txt file add this line: build.path=D:\MyProject\ArduinoBuild. This means let Arduino put the temp files in this directory, such as the .h waiting to compile.
  3. Because the .h Arduino automatically generated from our .ino is in ArduinoBuild directory, you can now use #include "./../Share/SomeShare.h" in order to include the D:\MyProject\Share\SomeShare.h

Here is the same question asked in another stackexchange board: Here

2
  • If your answer worked, select it as the correct answer.
    – Ian M
    Jul 12, 2015 at 3:54
  • @lan M It says i can only do it tomorrow.
    – ch271828n
    Jul 12, 2015 at 4:10
0

You could also use:


in transmitter.ino
#define TX 1
#include "share.h"

in receiver.ino
#define RX 1
#include "share.h"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.