coder en plusieurs fichiers

Bonjour, j’essaie de coder en plusieurs fichiers pour rendre le programme plus lisible et mieux ordonner mais je n'arrive pas à compiler; il me dit; "multiple definition of mes variables"
à comprends pas !

le fichier .ino:

/*
  ReadAnalogVoltage
  Reads an analog input on pin 0, converts it to voltage, and prints the result to the serial monitor.
  Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.
 
 This example code is in the public domain.
 */

#include "configuration.h"

// the setup routine runs once when you press reset:
void setup() {
    // initialize digital as an output for the led
  pinMode(pin_led, OUTPUT);
    // initialyze digital pin as input for the button
  pinMode(button, INPUT);
  
  
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  
  Serial.println("Initializing Serial port...");
  Serial.println("Serial port initialized");
  
}

// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int sensorValue = analogRead(A0);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
  float voltage = sensorValue * (5.0 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
  read_button(button); // affiche l'état du bouton sur le port série
  
}

le fichier configuration.h

#ifndef configuration_h
#define configuration_h

#include "Arduino.h"

// size of buffer used to serial print
#define BUF_SZ   20

char buffer[BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char index = 0;

int pin_led = 8;
int button = 2;
int button_state = 0;

void read_button (int pin);



#endif //__configuration_H

et le fichier configuration2.cpp

#include "Arduino.h"
#include "configuration.h"

void read_button (int pin)  {
  button_state = digitalRead(button);
  
    if (button_state == HIGH) {     
    // turn LED on:    
    digitalWrite(pin_led, HIGH);

//    buffer[0] = "O";
//    buffer[1] = "N";
//    Serial.println(buffer);  

  } 
  else {
    // turn LED off:
    digitalWrite(pin_led, LOW);
//    buffer[0] = "O";
//    buffer[1] = "F";
//    buffer[3] = "F";
//    Serial.println(buffer);  
  }
  
  
  
}    // end of read_button ()

Pourtant les vairiables ne sont déclarées qu'une seule fois dans "configuration.h", même si il est appelé plusieurs fois...

int pin_led = 8;

Si tu déclares et instancies des variables dans un fichier .h elles seront considérées comme définies dans chaque fichier où t'inclus ton .h
Ce qui n'est pas le cas pour les #define qui n'étant pas des variables en soi, ne posent pas de problème particulier.

Pour résoudre ce problème, il faut utiliser le .h pour ce à quoi il est prévu, c'est à dire, déclarer mais pas créer. Par conséquent, pour déclarer une variable dans un .h il faut faire comme suit :

extern int pin_led;

et puis, dans un fichier .c ou .cpp en plus (ou dans ton .cpp déjà existant où t'as tes fonctions) :

int pin_led=8;

Dans le premier cas (.h), tu déclares ta variable en disant, en gros : "ne vous inquiétez pas, vous pouvez l'utiliser, elle sera instanciée quelque part dans le programme final".
Dans le 2e cas (.c/.cpp), tu instancies ta variable, ce qui veut dire que tu la crées vraiment. Et c'est donc sur cette instance que tout le reste de ton code va se baser pour fonctionner.

Je te suggère donc de faire la modif pour toutes les variables et de re-tester, si t'as encore un problème n'hésite pas à revenir.

Ensuite, et ce n'est que personnel, pour définir une constante, c'est à dire une valeur qui ne va à priori pas changer durant l'exécution de ton programme, comme le N° d'une PIN, moi personnellement je préfère utiliser des #define. Cela peut cependant être contesté dans le cadre de l'optimisation de l'utilisation de la mémoire de ton Arduino, mais je pense que tu n'en est pas encore là... :wink:

D'accord, merci beaucoup, ça compile maintenant si je déclare seulement la variable dans le .h avec le préfixe "extern" et si je l'instancie dans le .cpp même s'il faut aussi la déclarer pour lui donner ou non une valeur.

Et ça ne rentre pas trop dans le sujet mais je voudrais afficher (envoyer une chaîne de caractères) sur le com série qui afficherait l'état du bouton poussoir; "ON" ou "OFF" et il me parle d'un problème de conversion de type:

configuration_2.cpp: In function 'void read_button(int)':
configuration_2.cpp:18: error: invalid conversion from 'const char*' to 'char'
configuration_2.cpp:19: error: invalid conversion from 'const char*' to 'char'

Je ne dois pas utiliser la bonne méthose pour remplir le buffer ce char à envoyer sur le serial:

    if (button_state == HIGH) {     
    // turn LED on:    
    digitalWrite(pin_led, HIGH);

   buffer[0] = "O";
   buffer[1] = "N";
    Serial.println(buffer);  

  }

une chaîne de caractères se termine toujours par un caractère '\0', dans ton code il manque :

buffer[2] = '\0'; // sans oublier de dimensionner buffer correctement donc avec une taille >= 3

de plus, si tu affectes des caractères un par un comme tu fais, tu dois utiliser des guillemets simples ' (caractère) et pas doubles " (chaîne de caractères).

Enfin, au vu de tes connaissances, je te conseille de tenter de suivre un tuto, tu apprendras plus vite qu'en posant tes questions une par une dans un forum...

C'était juste une question subsidiaire à la structuration des programmes et c'était l'exemple que j'avais pris pour tester le code en plusieurs fichiers.
Parce que je suis déjà sur un autre tuto au vu du projet que je suis en train de faire et que je voulais mieux structurer, merci encore.

Pas de souci ! bonne continuation ! :wink:

Je reviens sur le sujet puisque je ne trouve pas vriament sur des tutos que j’ai pu voir: tuto coder en plusieurs fichiers

Au niveau de de mon programme, je voudrais juste laisser tel quel le .ino avec le setup () et le loop () dedans mais dans lesquels je ferai des appels à des fonctions instanciées dans d’autres pages et préalablement déclarées dans le fichier.h le précédent alphabétiquement.

Voilà mon .ino:

void setup()
{
    // disable Ethernet chip
    pinMode(10, OUTPUT);
    digitalWrite(10, HIGH);
    
    //Serial.begin(9600);       // for debugging
    Serial.begin(115200);       // for debugging

    //affiche ();
    
    // initialize SD card
    init_SD ();

avec le configuration.h

#ifndef configuration_h
#define configuration_h

// comment out the next line to eliminate the Serial.print stuff
// saves about XX Ko of program memory
#define ServerDEBUG


// size of buffer used to capture HTTP requests
//#define REQ_BUF_SZ   20
#define REQ_BUF_SZ   90


// fonction d'initialisation de la carte SD
void init_SD ();


#endif //__configuration_H

et le configuration2.cpp

#include "configuration.h"
#include "Arduino.h"


#include <Ethernet.h>
#include <SPI.h>
#include <SD.h>


///// fonction d'initialisation de la carte SD
void init_SD ()  {
    #ifdef ServerDEBUG
    Serial.println("Initializing SD card...");
    #endif
    if (!SD.begin(4)) {
        #ifdef ServerDEBUG
        Serial.println("ERROR - SD card initialization failed!");
        #endif
        return;    // init failed
    }
    #ifdef ServerDEBUG
    Serial.println("SUCCESS - SD card initialized.");
    #endif
    // check for index.htm file
    if (!SD.exists("index.htm")) {
        #ifdef ServerDEBUG
        Serial.println("ERROR - Can't find index.htm file!");
        #endif
        return;  // can't find index file
    }
    #ifdef ServerDEBUG
    Serial.println("SUCCESS - Found index.htm file.");
    #endif
    
}    /// fin de init_SD

Mais il ne reconnaît pas la fonction SD dans le .cpp comme si la libraire SD.h n’avait pas été déclarée alors qu’elle l’a été !

Pour que celà fonctionne il faut que tous les fichiers soit dans le même répertoire ou dans un des répertoires utilisé pour déposer les bibliothèques.
Il faut aussi mettre l'include configuration.h dans le fichier ino.
Dans ce que tu nous montre il n'y a de déclaration #include "configuration.h" dans le fichier ino.

L'IDE transforme le fichier ino en un VRAI fichier cpp
Le compilateur va compiler chaque fichier cpp séparément.
Pour chaque fichier cpp il faut que le compilateur ait connaissance des fonctions qui pourront être appelées.

Si si, j’ai bien #include “configuration.h” dans le .ino

Donc concrètement, il faudrait que je mette SD.h SPI.h etc… dans le dossier où il y a mon .ino, mon configuration.h et mon configuration.cpp ?

Bonjour,

Non.

68tjs:
Pour que celà fonctionne il faut que tous les fichiers soit dans le même répertoire ou dans un des répertoires utilisé pour déposer les bibliothèques.

Si tu as écrit les fichiers h et cpp dans le but de pouvoir les utiliser comme une bibliothèque tu peux soit les copier à la demande dans chaque répertoire contenant le fichier ino : cela fonctionne mais c’est lourd et gâcheur de place, soit les placer dans le répertoire “libraries” de ton schetbook en respectant la structure des bibliothèques Arduino ( 1 répertoire par blibli, un dossier exemple, etc ).

Pour des fichiers qui ne sont qu’une simple extension à un programme et donc en principe non réutilisables il faut les placer dans le même répertoire que le fichier ino et bien mettre tout les includes avec des “” (qui signifient qu’il faut prendre les fichiers dans le répertoire courant et non pas des <> qui signifient qu’il faut prendre les fichiers dans 1 des répertoires connus de l’IDE pour être des dépots de bibliothéques système ou personnelles.

Oui, c’est bien ce que j’ai fait; des include “configuration.h” dans le .ino et le .cpp mais l’erreur est pour l’appel d’une fonction de la librairie SD.h, c’est çà que je ne comprends pas.

domo4.zip (4.83 KB)

As-tu essayé un des exemples (le plus simple possible) d'utilisation de cette bibliothèque pour vérifier si cela ne fonctionnerait pas quand même ?

C'est une bibliothèque qui est livrée avec l'IDE ou c'est une version différente que tu as téléchargée ?

çà compile !

Il fallait mettre les

#include <Ethernet.h>
#include <SPI.h>
#include <SD.h>

dans le .ino ET dans le .cpp !

Y’aurait-pas un tuto un peu plus précis que celui qu’j’ai regardé ?

dans le .ino ET dans le .cpp !

Est-ce que ce n'est pas ce que je t'avais dit :

L'IDE transforme le fichier ino en un VRAI fichier cpp
Le compilateur va compiler chaque fichier cpp séparément.
Pour chaque fichier cpp il faut que le compilateur ait connaissance des fonctions qui pourront être appelées.

Ouais merci pour les explications mais je trouve étrange que ça soit si compliqué à “parsemer” un projet en plusieurs fichiers.

D’ailleurs, là je galère trop; mon programme initial fonctionne très bien mais commence à être illisible et c’est pourquoi j’ai voulu le découper en plusieurs fichiers tel le Marlin des imprimantes 3D sur Mega2560 mais je vais d’erreurs en erreurs et je n’avance pas !

Aurait-il été possible que vous puisâtes regardez le projet complet ci-joint (hormis les pages webs et leurs fichiers respectifs) et me dire comment ré-agencer tout çà pour que cela puisse enfin compiler ?

Le programme fonctionne dans un seul .ino mais si je veux rajouter d’autres choses, c’est de plus en plus pénible et la mollette de ma souris en conteste !

P.S: il y a tout les commentaires possibles

domo4.zip (6 KB)

Aurait-il été possible que vous puisâtes regardez le projet complet

Désolé mais je ne suis qu’un pauvre électronicien qui s’est mis à la programation à 65 balais, il y a 5 ans de cela.
Quand un sujet m’intéresse j’essaye de m’y intéresser le plus possible (google, wikipédia, developpez.com et autres) mais mes connaissances restent forcément dans des domaines étroits.
Quand je peux donner des tuyaux sur les sujets que j’ai approfondit je le fait avec plaisir mais franchement me plonger dans les programmes des autres ce n’est pas mon truc. Je suis plus à l’aise dans le domaine de l’électronique analogique.

emmett_brown:
Aurait-il été possible que vous puisâtes regardez le projet complet ci-joint

un subjonctif que je ne connusse point, on dirait du passé simple mélangé a du subjonctif imparfait, mais de quel verbe ... j'aurais mis "puissassiez', mais alors c'est le verbe "puiser"= sortir "quelquechose" d'un puits

"pussassiez" n'aurait pas été en reste

Bonjour,
Il y a des bizarreries dans la langue française. Personnellement je trouve inacceptable que l’on ne puisse pas traire à l’imparfait du subjonctif.
:grin:

Salut,

QQ remarques toutes personnelles d’un débutant mais pas tant.

Découper en fichier c’est bien ! Rester simple c’est mieux donc je ferais l’impasse sur le fichier fonctions.h et ne garderais qu’un seul fichier d’entête configuration.h par exemple.

Ensuite je pense que l’ordre des #include est important, perso. je prendrais cet ordre là

#include <Ethernet.h>
#include <SPI.h>
#include <SD.h>

#include "configuration.h"

Tertio : Tu ne peux pas faire l’impasse de tout déclarer dans le fichier d’entête. J’ai tenté de compiler mais il manquait au minimum les lignes suivantes.

char StrContains(char *str, char *sfind);
void StrClear(char *str, char length);

EthernetClient cl;
void XML_response(EthernetClient cl);
void XML_resp2(EthernetClient cl);

ensuite j’ai arrêté car on retrouve toujours le même problème de déclaration.

Et enfin l’IDE Arduino permet pas mal de chose mais quand je manipule plusieurs fichiers je préfère NotePad ++ avec l’addon Arduino il permet de faire des recherches sur tous les fichiers du répertoire, des comparaisons entre fichiers et tout plein de truc sympa quand on édite un gros programme en plusieurs fichiers.

Voilà espérant avoir fait avancé un peu ton projet

domo4.0.1.zip (6.21 KB)