1

This is probably simple but I'm banging my head against the wall for sometime now. I'm trying to split a simple program into multiple files so I can add to it. I'm trying to logically split it into parts. If anyone can give me some pointers as to my mistakes that'd be awesome.

Main.cpp

#include <Arduino.h>
#include "measure.h"
#include "LoRa.h"

void setup()
{
    Serial.begin(9600);  // STart serial for monitoring/debugging
    Serial2.begin(9600); // Start 2nd serial interface for use with EBYTE module
    Serial.println("Starting Reader");
    Serial.println(Transceiver.init()); // This init will set the pinModes for you
    Transceiver.PrintParameters();      // Display parameters of EBYTE (Can be changed. See example sketches)
}
//=================================================================
//======LOOP=======================================================
//=================================================================

void loop()
{
    measure();  // Take measurements
    delay(1000); // For testing. Will not exist in final
}

measure.cpp

// Takes various measurements, updates struct and sends to receiver

#include <Arduino.h>
#include "measure.h"
#include "MyData.h"
#include "LoRa.h"

unsigned long Last;
void measure()
{
    // measure some data and save to the structure
    MyData.Count++;
    MyData.Bits = analogRead(A0);
    MyData.Volts = MyData.Bits * (5.0 / 1024.0);

    // Send struct
    Transceiver.SendStruct(&MyData, sizeof(MyData));
    // Let us know something was sent
    Serial.print("Sending: ");
    Serial.println(MyData.Count);
}

measure.h

#ifndef MEASURE_H
#define MEASURE_H

#include <Arduino.h>
#include "LoRa.h"

void measure();
#endif

LoRa.cpp

// Somewhere to define/declare everything to do with the Ebyte E32 LoRa module
#include <Arduino.h>
#include "EBYTE.h"
#include "LoRa.h"

#define PIN_RX 16 // Serial2 RX (connect this to the EBYTE Tx pin)
#define PIN_TX 17 // Serial2 TX pin (connect this to the EBYTE Rx pin)
#define PIN_M0 4  // D4 on the board (possibly pin 24)
#define PIN_M1 22 // D2 on the board (possibly called pin 22)
#define PIN_AX 21 // D15 on the board (possibly called pin 21)

// create the transceiver object, passing in the serial and pins
EBYTE Transceiver(&Serial2, PIN_M0, PIN_M1, PIN_AX);

LoRa.h

#ifndef LORA_H
#define LORA_H

#include "Arduino.h"

#endif

MyData.h

#ifndef MYDATA_H
#define MYDATA_H

struct DATA
{
  unsigned long Count;
  int Bits;
  float Volts;
  float Temp;
} MyData;

#endif

ERRORS

src\main.cpp: In function 'void setup()':
src\main.cpp:45:20: error: 'Transceiver' was not declared in this scope
     Serial.println(Transceiver.init()); // This init will set the pinModes for you
                    ^
src\measure.cpp: In function 'void measure()':
src\measure.cpp:18:5: error: 'Transceiver' was not declared in this scope
     Transceiver.SendStruct(&MyData, sizeof(MyData));
     ^
*** [.pio\build\esp32doit-devkit-v1\src\measure.cpp.o] Error 1
*** [.pio\build\esp32doit-devkit-v1\src\main.cpp.o] Error 1

Thanks!!

Cam_ _D
  • 19
  • 1
  • @VLL: If I correctly understood, `Tranceiver` is expected to be created in LoRa.cpp as an `EBYTE` object. Unfortunately, the instruction only declares a function returning an EBYTE ([C++ most vexing parse](https://stackoverflow.com/q/1424510/3545273)). And additionaly LoRa.h should contain a declaration for the object to make it available in other compilation units. – Serge Ballesta Mar 16 '22 at 08:08
  • 1
    One thing to note is that splitting the `struct DATA` definition _and_ the definition of `MyData` into a header file doesn't do what you might think. Now, any cpp file that includes that file will instantiate its own local (static) object called `MyData`. – paddy Mar 16 '22 at 08:09
  • 2
    Regarding `Transceiver`, since it's a variable that you want to access from another translation unit, you must declare it as extern in your header (in this case in LoRa.h): `extern EBYTE Transceiver;` Otherwise it's implicitly static. To do this you'll also want to include include EBYTE.h in your LoRa header. – paddy Mar 16 '22 at 08:11
  • On some basic style notes, there is no reason to include the Arduino or LoRa headers in measure.h, because nothing in that header requries those interfaces. Similarly for your current version of LoRa.h which pointlessly includes "Arduino.h". That itself seems strange because you're using different search path rules than everywhere else (note the double quotes instead of angle brackets) – paddy Mar 16 '22 at 08:18
  • 1
    Does this answer your question? [How do I use extern to share variables between source files?](https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files) – gre_gor Mar 16 '22 at 15:42
  • @paddy - do you mind elaborating on the struct DATA, and how I can make that global as such? Thanks – Cam_ _D Mar 17 '22 at 03:22
  • 1
    @Cam__D same way you made `Transceiver` global. Declare `extern DATA MyData;` and define that in whichever source file you want to be holding it. Probably that's measure.cpp which appears to be the only thing using it. In light of that, why do you want this global in the first place? Nobody else uses it. – paddy Mar 17 '22 at 03:27
  • @paddy lets say I want to have a global struct. You say define it in a .cpp, declare it in the corresponding .h and then #include the .h in whatever other .cpp that needs to use it? Seems I can't get that to work :( – Cam_ _D Mar 18 '22 at 11:04
  • [EDIT] - I think I have it working with the struct in the .h and also declaring it there as extern. I then define it in the .cpp file. Is it not being defined in the .h tho? It compiles, so further testing required – Cam_ _D Mar 18 '22 at 11:38
  • The _struct_ (DATA) is defined in the header. The _instance_ of that struct (MyData) is declared in the header and defined in the cpp. By declaring it extern, this exports the symbol so that the linker knows how to go and find it when linking together the individually compiled cpp files. Without using extern for global variable declarations, the compiler will treat them as a definition and make them local to each cpp file that includes the header -- so you get multiple copies and it's not global at all. – paddy Mar 19 '22 at 01:43

1 Answers1

1

You are creating a Transceiver object in LoRa.cpp, but it hasn't been made accessible to your measure.cpp file. To reach an object that is in file scope in a different file, you add extern in the declaration:

extern EBYTE Transceiver;

Also, for the measure.cpp file to understand what kind of object Transceiver is (for example which methods it contains) you should include the EBYTE header in measure.cpp:

#include "EBYTE.h"

An example using the EBYTE code.

For example:

#include <Arduino.h>
#include "EBYTE.h"
#include "measure.h"
#include "MyData.h"
#include "LoRa.h"

unsigned long Last;
extern EBYTE Transceiver;

void measure()
{
mmixLinus
  • 1,646
  • 2
  • 11
  • 16