#include and functions

The code in my applications is getting kind of large so i split it in to several function.h files but not sure if the way i have structured these are quite the right way as including the function.h has to be done in a specific order.

Essentially I have somethign like the following..

#include "WebServer.h"
#include "Wireless.h"
#include "pidRoutine.h"
#include "Sensors.h"
#include "Tickers.h"

At compile time I would have thought that the functions inside the XXX.h files would be available globally so if there was a function in Tickers.h it could be called by WebServer.h however this does not seem to be the case.

In my case i have a function in Tickers.h called stopTickers() that is supposed to stop all of the tickers.
There is also a function in Tickers.h called startTickers() that runs functions in Sensors.h and pidRoutine.h

If I put Tickers.h at the bottom like I have above then i get an error at compile time "'stopTickers' was not declared in this scope"

and if I put it before WebServer.h i get an error "'updateTemperature' was not declared in this scope"
because it cant see the UpdateTemperature() in sensors.h

How do you create and declare a function that is essentially global? Another issue is there are #defines included in the includes and adding a #include "Tickers.h" to the other XXX.h files would end up redefining the declares's and I am not sure but think it would end up bloating the code.

Well that may not be the correct way to do it but I created a prototype.h file and created a prototype of all the functions. then put that at the beginning of the includes.

It seems to work but still not sure if this is the correct way to do things.

Function prototypes (declarations) go in header files, function implementations (definitions) go in implementation files.

If you need functions from another file, you include the header file where those functions are declared.

For example:

#include "A.h"
#include "B.h"

void setup() {
  Serial.begin(115200); 
  someFunctionOfA();
  complicatedFunctionOfB(3);
}

void loop() {}
#pragma once // Important if you include header files from other header files

void someFunctionOfA();
void anotherFunctionOfA(int);
#include <Arduino.h>
#include "A.h" // Only required if you defined types or classes in A.h that you need here

void someFunctionOfA() {
  Serial.println(__PRETTY_FUNCTION__);
}

void anotherFunctionOfA(int number) {
  Serial.print(__PRETTY_FUNCTION__);
  Serial.print(": The number is ");
  Serial.println(number);
}
#pragma once

void complicatedFunctionOfB(int);
#include <Arduino.h>
#include "B.h" // Only required if you defined types or classes in B.h that you need here
#include "A.h"

void complicatedFunctionOfB(int number) {
  Serial.print(__PRETTY_FUNCTION__);
  Serial.print(": The number is ");
  Serial.println(number);
  anotherFunctionOfA(number + 3);
}
void someFunctionOfA()
void complicatedFunctionOfB(int): The number is 3
void anotherFunctionOfA(int): The number is 6

If you use Arduino Core classes or types in your function signatures, you’ll have to include Arduino.h in your header files, rather than your implementation files.

Pieter

Thanks @PieterP

That makes a lot more sense now :slight_smile:

If i have already included Arduino.h in the Main.ino do i need to re include it in the A.cpp also?

PieterP:

#include <Arduino.h>

#include “A.h” // Only required if you defined types or classes in A.h that you need here

void someFunctionOfA() {
 Serial.println(PRETTY_FUNCTION);
}

void anotherFunctionOfA(int number) {
 Serial.print(PRETTY_FUNCTION);
 Serial.print(": The number is ");
 Serial.println(number);
}

vangalvin:
If i have already included Arduino.h in the Main.ino do i need to re include it in the A.cpp also?

Yes. Each .cpp file is a different translation unit, it is compiled separately. It doesn’t matter if you included it in a different implementation file, you need it in the current one as well.

Note that you don’t have to include Arduino.h in your ino file explicitly, the Arduino IDE will do that for you.

You may find these useful:

I will have to have a good read of them, this is my first large application that I have tried to split up to make it easier to manage.

Im still having a few issues and not sure where I am going wrong.
I am getting ‘server’ was not declared in this scope.

#include <ESP8266WebServer.h>  //since this is in the .h file do i need it here?

void setup() {
  Serial.begin(115200);
  wifiWebSetup();
}

void loop() {
  server.handleClient();
}
#pragma once                               //Important if you include header files from other header files
#include "config.h"
#include <ESP8266WebServer.h>

void handleOther();
void wifiWebSetup();
#include "htmlServer.h"

ESP8266WebServer server(80);                       //port 80


void handleOther() {   
  //handle HTML stuff here
}

void wifiWebSetup(){
  server.on("/handle", handleOther);
}

You should declare everything you use in other files in your header files.
This can be tricky when using global variables (server is a global variable).

By default, when you write ESP8266WebServer server;, this is a declaration and a definition. This definition cannot be in the header file. This is because if you were to include the header file from 2 separate implementation files, it would violate the One Definition Rule, and you’ll get a linker error.

The solution is to declare it in the header file, without defining it, and telling the compiler that the definition will be found somewhere else. This is called external linkage.

#pragma once

#include "config.h"
#include <ESP8266WebServer.h>

extern ESP8266WebServer server;

void handleOther();
void wifiWebSetup();
#include "htmlServer.h"

ESP8266WebServer server(80);                       //port 80


void handleOther() {   
  //handle HTML stuff here
}

void wifiWebSetup(){
  server.on("/handle", handleOther);
}

vangalvin:

#include <ESP8266WebServer.h>  //since this is in the .h file do i need it here?

No, you don’t need it. But it might help readers (including your future self) to understand what libraries you are using, especially if there are multiple layers of includes in between.
It does no harm to include it twice, because the #pragma once will make sure that the compiler only sees it once.

Ahh, Thank you :slight_smile:

That part seems to all be working now, the only issue I seem to have is that the .cpp has two functions in it and one function cant seem to see the other.

When setting up the wireless client i have a sub function that checks that the signal is above -83 because I found an issue in the ESP8266 where if the signal is below that and you try to send data to the client it triggers a WDT and restarts the system.

#pragma once

void startWiFiClient(const char *apid, const char *appass);
bool CheckSignal(String ESSID, int minRSSI);
#include "wifi.h"
void configWiFi(){
  WiFi.mode(WIFI_AP_STA);    //Set the WiFi Mode to AP and Station
  WiFi.persistent(false);
}
void startWiFiClient(const char *apid, const char *appass){
  //Check the signal level of the client
  if(CheckPossibility(apid, -83)){
     //connection routine in here
    }
    //print function to tell user we are connected
  }else{
    //print function to tell user the signal is too low
  }
}

bool CheckSignal(String ESSID, int minRSSI){
  //code to check signal lever of the AP here
  //sets RSSIok to true if the signal is above minRSSI or false if below minRSSI
  return RSSIok;  //return True or False
}

I get the error 'CheckPossibility' was not declared in this scope, Do i need to add that as an
extern function as well? I wold have thought that since it is in the same .cpp it would be
available to the start function?

[/quote]

Well found the issue, And it works. I really should have a routine that does "Check Spelling" !!!!

That you guys for your help on this, its defiantly helped me clean up my coding a little and make the code a lot easier to understand and follow.

Now we are getting to the tricky stuff. (well tricky for me)

I assume that if i declare a VAR in the .h file the and the .h is included in the .ino then I can check the value of the var directly in the .h?

I am getting "multiple definition of `getDHT'"

#pragma once                               //Important if you include header files from other header files
#include "DHTesp.h"                      //Library for the DHT sensor

extern DHTesp dht;

bool getDHT = false;                      //required for non blocking ticker
float dhthum;                                //where we store the humidity
float dhttemp;                               //where we store the temperature

void setupDht(int DHT_PIN);          //call this in the start to configure the sensor
void getDHTData(bool PRN_DATA); // call this with a true if we want to print the info
void dhtTicker();
void dhtLoop();
#include "dhtSensor.h"

DHTesp dht;

void setupDht(int DHT_PIN){
  dht.setup(DHT_PIN, DHTesp::DHT11);          // Connect DHT sensor to GPIO 17
}

void getDHTData(bool PRN_DATA){
  dhthum = dht.getHumidity();
  dhttemp = dht.getTemperature();
  if(PRN_DATA){
    Serial.print("DHT Sensor Data:");
    Serial.print("\tTemp: ");
    Serial.print(dhttemp);
    Serial.print("\tHum: ");
    Serial.println(dhthum);
  }
}

void dhtTicker(){
    getDHT = true;    
}

void dhtLoop(){
    if (getDHT){
      getDHTData(true);
      getDHT = false;
    }
}

This is a really good teaching moment for understanding the difference between define and declare. They are not the same.

When you define a variable, you create an attribute list for that variable (e.g., ID, data type, scope, etc.) However, you also create a space in memory where that variable will live (i.e., its lvalue).

When you declare a variable, you also create the same attribute list as before, BUT no memory is allocated. That is, no memory is set aside for the variable.

For example, suppose you define variable x in file a.cpp, but you want to also use it in file b.cpp. Taking some simplification liberties, file a.cpp will have:

int x; // Attribute list: ID = x, data type = int, scope = global, etc.

In file b.cpp you have this:

void MyFunction()
{

  • x = 10;*
    }

If you try to compile the two files, the statement in file b.cpp throws an error because x is defined in file a.cpp. Solution: create a header file (e.g., MyHeader.h) that is read at the start of file b.cpp that has this statement in it:

extern int x;

The extern keyword in the statement in the MyHeader.h in essence says to the compiler: "Here's the attribute list for variable x so you can use it in this file even though it is defined in another file." The compiler then leaves a 2-byte "hole" in the code for the memory address of variable x in file b.cpp. It is the declaration of x in the header file that lets the compile proceed because it knows the attribute list for x. However, because it's a declaration, the memory address is unknown at this point...the hole is unfilled.

However, variable x is defined in file a.cpp, so the compiler now adds the memory address for x to its attribute list. When the linker comes along and sees the "hole" for x in file b.cpp, it can now take the memory address from the attribute list and "fill in the hole" for variable x in file b.cpp.

Header files use the extern keyword to provide data declarations for data that are defined elsewhere. Header files rarely have executable code in them. Instead, they hold symbolic constants and amcros (e.g., #define's), data declarations, and function prototypes.

That is a great explanation thank you!!

I used to just stuff routine in .h files but realised on this one that doing so has a lot of potential issues especially when building a complex application like this one.

I really do appreciate the assistance and guidance you guys have been giving and so far it all makes sense and have been able to overcome most of the obstacles.

I have however gotten to the really really hard part. the PID loop.

So far the Sensors are now working, The Wireless is working and checking that there is enough signal before connecting and initiating communications, the web server is now working and. the PID has a pile of little functions that I can see may give me a few problems.

Then its on to the json stuff so i can communicate with the web interface.

With my declarations would I be better off setting them up in a struct?

struct Config {
  bool fileLogStatus;
  int tempDiffValue;
};

When you have a struct in the main Config.h file and you have a .cpp with its own .h and in the .ccp you have a function that needs to read data in the struct of the Config.h and change some of the values how do you access it?

I tried the following to no avail

struct tmpSensor{
  float Inside;
  float Outside;
  float Ground;
  DeviceAddress OutSens = { 0x28, 0x5A, 0x82, 0x23, 0x17, 0x13, 0x01, 0x98 };   //Address for Sensor1 Outside the cabinet
  DeviceAddress GndSens = { 0x28, 0xEB, 0x09, 0x2F, 0x17, 0x13, 0x01, 0x01 };   //Address for Sensor2 Ground Temperature
  DeviceAddress InSens = { 0x28, 0xFB, 0x03, 0xBE, 0x16, 0x13, 0x01, 0x22 };   //Address for Sensor3 Inside the cabinet
};
tmpSensor senseData;
#pragma once                               //Important if you include header files from other header files
#include <OneWire.h>
#include <DallasTemperature.h>

extern OneWire oneWire;
extern DallasTemperature sensors;

//extern tmpSensor senseData;

#define TEMPERATURE_BUS D4                  //Dallas 1 wire Temperature Sensors
#define TEMPERATURE_PRECISION 12            //Dallas 1 wire Temperature Sensor Precision

void updateTemperature();
void setupSensors();
void setupSensors(){
  // set the resolution to 12 bit per device
  sensors.setResolution(senseData.OutSens, TEMPERATURE_PRECISION);
  sensors.setResolution(senseData.GndSens, TEMPERATURE_PRECISION);
  sensors.setResolution(senseData.InSens, TEMPERATURE_PRECISION);
}

void updateTemperature(){
  sensors.requestTemperatures();
  senseData.Outside = sensors.getTempC(senseData.OutSens);
  senseData.Ground = sensors.getTempC(senseData.GndSens);
  senseData.Inside = sensors.getTempC(senseData.InSens);