Go Down

Topic: Multiple variable definition error when compiling with .h and .cpp file tabs (Read 170 times) previous topic - next topic

cliquot22

I am trying to move some common functions into a .cpp and .h files in Arduino but I can't get it to compile correctly.  Even if I include the #ifndef protection, it says that there are multiple definitions of my variables.

Even in this simplest example, I get the error:
sketch\testing.cpp.o:(.bss.i+0x0): multiple definition of `i'

.ino file:
Code: [Select]
#include "testing.h"

void setup() {

}

void loop() {

}


Included testing.h file:
Code: [Select]
#ifndef TESTING_H
#define TESTING_H

int i;

#endif


and empty testing.cpp file:
Code: [Select]
#include "testing.h"



Why am I getting an error? 

AWOL

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

gfvalvo

If you're really trying to define a global variable in the .cpp file, do this:

.ino file:
Code: [Select]
#include "testing.h"

void setup() {}

void loop() {}


testing.h:
Code: [Select]
#ifndef TESTING_H
#define TESTING_H

extern int i;

#endif


testing.cpp:
Code: [Select]
#include "testing.h"

int i;

cliquot22

That is not the behavior I was expecting so I'll have to consider if this is the right approach for me.  How would I normally define variables that are global but only within my .cpp file functions?  

I am actually trying to more wifi communications to a file that I can copy from one project to another easily.  That way I only have to call a wifiInit(WIFI_LED_PIN) and check for wifiConnected.  All the work would be done within my wifiConnect.cpp file.  

So there are some variables that are only useful internal to the cpp functions such as a timer for checking the connection.  Do these variables have to be extern global variables or is there a better way?  

wifiConnect.h file
Code: [Select]
#ifndef WIFI_CONNECT_H
#define WIFI_CONNECT_H

#include "secrets.h"
#include <ESP8266WiFi.h>
#include <SimpleTimer.h>

#define NUM_SSID 3  // maximum number of SSID to try
char ssid[NUM_SSID][30];   // array of 3 wifi connections
char password[NUM_SSID][30];
boolean wifiConnected = false;
int wifiLedPin;

SimpleTimer wifiTimer;
int wifiSSIDTimer;      // timer for switching between SSID while trying to connect
int wifiCheckTimer;   // timer for checking for wifi connection
long wifiCheckInvl = 500; //check 30 times before switching SSID
long wifiConnectedInvl = 16000;


// Public:
/* call for initialization
 *  input: wifi LED pin number
 */
void wifiInit(int wifi_pin);

/* call every loop at least until wifiConnected=true */
void wifiTimerRun();

// Private:
void wifiStart();
void wifiCheck();

#endif


wifiConnect.cpp
Code: [Select]
#include "wifi_connect.h"

/* initialize wifi
 *    input: pin number for wifi LED indicator
 */
void wifiInit(int wifi_pin) {
  // load wifi SSID and Passwords to try
  strcpy(ssid[0], ssid1);
  strcpy(ssid[1], ssid2);
  strcpy(ssid[2], ssid3);
  strcpy(password[0], password1);
  strcpy(password[1], password2);
  strcpy(password[2], password3);

  pinMode(wifi_pin, OUTPUT);
  digitalWrite(wifi_pin, HIGH);
  wifiLedPin = wifi_pin;
  
  wifiTimer.init();

  // start wifi connection timer
  wifiStart();
}

/* periodic wifi checking
 *  Call this routine every loop
 */
void wifiTimerRun() {
  wifiTimer.run();
}


/* check for a wifi connection
 *  Cycle through access points and passwords
 *  Wait some time before checking if connection is successful by starting a new timer
 *  
 *  init true on first call to wifiStart
 */
void wifiStart() {
  static int init = true;
  if (init) {
    // timer started on first call
    wifiSSIDTimer = wifiTimer.setInterval(wifiConnectedInvl, wifiStart);
    init = false;
  }
  
  static int count = 0;
  count++;
  if (count >= NUM_SSID) {
    count = 0;
  } else if (strcmp(ssid[count],"") == 0) {
    // no ssid value, loop around to start
    count = 0;
  }
  
  Serial.printf("Attempting to connect to wifi %d: %s\n", count, ssid[count]);
    
  // Wifi setup
  WiFi.begin(ssid[count], password[count]);
  wifiCheckTimer = wifiTimer.setTimer(wifiCheckInvl, wifiCheck, 30);
}

/* check if wifi is connected
 *  Could take 15 seconds or more (30 tries)
 */
void wifiCheck() {
  static int ledBlink = 0;
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("\nWifi connected, IP address: ");
    Serial.println(WiFi.localIP());
    digitalWrite(wifiLedPin, LOW);
    wifiConnected = true;
    wifiTimer.deleteTimer(wifiSSIDTimer);
    wifiTimer.deleteTimer(wifiCheckTimer);
  } else {
    if (ledBlink == 1) {
      digitalWrite(wifiLedPin, HIGH);  // turn on board red LED
      ledBlink = 0;
    } else {
      digitalWrite(wifiLedPin, LOW);
      ledBlink = 1;
    }
  }
}

cliquot22

I figured it out.  I just moved the variables into the .cpp file instead of in the header file.  That seems to work.

wifiConnect.h
Code: [Select]
#ifndef WIFI_CONNECT_H
#define WIFI_CONNECT_H

#include "secrets.h"
#include <ESP8266WiFi.h>
#include <SimpleTimer.h>

extern boolean wifiConnected;

// Public:
/* call for initialization
 *  input: wifi LED pin number
 */
void wifiInit(int wifi_pin);

/* call every loop at least until wifiConnected=true */
void wifiTimerRun();

// Private:
void wifiStart();
void wifiCheck();

#endif


wifiConnect.cpp
Code: [Select]
#include "wifi_connect.h"

#define NUM_SSID 3  // maximum number of SSID to try
char ssid[NUM_SSID][30];   // array of 3 wifi connections
char password[NUM_SSID][30];
boolean wifiConnected = false;
int wifiLedPin;

SimpleTimer wifiTimer;
int wifiSSIDTimer;      // timer for switching between SSID while trying to connect
int wifiCheckTimer;   // timer for checking for wifi connection
long wifiCheckInvl = 500; //check 30 times before switching SSID
long wifiConnectedInvl = 16000;


/* initialize wifi
 *    input: pin number for wifi LED indicator
 */
void wifiInit(int wifi_pin) {
  // load wifi SSID and Passwords to try
  strcpy(ssid[0], ssid1);
  strcpy(ssid[1], ssid2);
  strcpy(ssid[2], ssid3);
  strcpy(password[0], password1);
  strcpy(password[1], password2);
  strcpy(password[2], password3);

  pinMode(wifi_pin, OUTPUT);
  digitalWrite(wifi_pin, HIGH);
  wifiLedPin = wifi_pin;
  
  wifiTimer.init();

  // start wifi connection timer
  wifiStart();
}

/* periodic wifi checking
 *  Call this routine every loop
 */
void wifiTimerRun() {
  wifiTimer.run();
}


/* check for a wifi connection
 *  Cycle through access points and passwords
 *  Wait some time before checking if connection is successful by starting a new timer
 *  
 *  init true on first call to wifiStart
 */
void wifiStart() {
  static int init = true;
  if (init) {
    // timer started on first call
    wifiSSIDTimer = wifiTimer.setInterval(wifiConnectedInvl, wifiStart);
    init = false;
  }
  
  static int count = 0;
  count++;
  if (count >= NUM_SSID) {
    count = 0;
  } else if (strcmp(ssid[count],"") == 0) {
    // no ssid value, loop around to start
    count = 0;
  }
  
  Serial.printf("Attempting to connect to wifi %d: %s\n", count, ssid[count]);
    
  // Wifi setup
  WiFi.begin(ssid[count], password[count]);
  wifiCheckTimer = wifiTimer.setTimer(wifiCheckInvl, wifiCheck, 30);
}

/* check if wifi is connected
 *  Could take 15 seconds or more (30 tries)
 */
void wifiCheck() {
  static int ledBlink = 0;
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("\nWifi connected, IP address: ");
    Serial.println(WiFi.localIP());
    digitalWrite(wifiLedPin, LOW);
    wifiConnected = true;
    wifiTimer.deleteTimer(wifiSSIDTimer);
    wifiTimer.deleteTimer(wifiCheckTimer);
  } else {
    if (ledBlink == 1) {
      digitalWrite(wifiLedPin, HIGH);  // turn on board red LED
      ledBlink = 0;
    } else {
      digitalWrite(wifiLedPin, LOW);
      ledBlink = 1;
    }
  }
}

gfvalvo

The xxx.h file should only contain DECLARATIONS of classes, variables, and function prototypes that are DEFINED in your xxx.cpp file AND are needed by OTHER files to use the features of your xxx.cpp file. Global variables and functions that you want to keep confined to xxx.cpp should be DEFINED / DECLARED in that file with the 'static' key word. The example below includes only variables and functions since it doesn't look like you're using classes:

testing.h:
Code: [Select]
#ifndef TESTING_H
#define TESTING_H

// The variables DECLARED here will be avaiable to every file that includes 'testing.h'
extern int globalInt;
extern bool globalBool;

// // The functions DECLARED here will be available to every file that includes 'testing.h'
void globalFunction1(void);
int globalFunction2(int);

#endif


testing.cpp:
Code: [Select]
#include <Arduino.h>
#include "testing.h"

// DEFINE the global variables here. Avaiable to every file that includes 'testing.h'.
int globalInt;
bool globalBool;

// DEFINE secrete global variables here. Only visible in this file.
static int secreteInt;
static bool secreteBool;

// DECLARE secrete functions here.  Only visible in this file.
static void secreteFunction1(void);
static int secreteFunction2(int);

// DEFINE global functions here.  Avaiable to every file that includes 'testing.h'.
void globalFunction1() {
  secreteFunction1();
}

int globalFunction2(int x) {
  return secreteFunction2(x) + secreteInt;
}


// DEFINE secrete functions here.  Only visible in this file.
static void secreteFunction1() {
  secreteBool = !secreteBool;
}

static int secreteFunction2(int x) {
  return x;
}


.ino file:
Code: [Select]
#include "testing.h"
void setup() {
  int localInt;
  bool localBool;

  // Access the global variables
  localInt = globalInt;
  localBool = globalBool;

  /// Call the global functions
  globalFunction1();
  localInt = globalFunction2(54);
}

void loop() {}



cliquot22


Go Up