Go Down

Topic: >> RESOLU << #Include... (Read 2190 times) previous topic - next topic

LibertyCareche

Dec 06, 2012, 07:04 pm Last Edit: Dec 07, 2012, 08:40 pm by LibertyCareche Reason: 1
Bonjour à tous,    :)

Sauf erreur, quand un programme utilise un .h avec la directive de compilation #include x.h, il peut utiliser les fonctions et variables déclarées dans ce .h et le cas échéant developpées dans le .cpp connexe.
J'essaye d'utiliser la bibliothèque TimerOne.h depuis un .h mais cela ne fonctionne pas alors que si TimerOne.h est inclus dans la Main, cela fonctionne.


Le main (Timer1DansUnInclude)
Code: [Select]

//#include "TimerOne.h"

#include "Tim.h"
boolean hool;

void setup()
{
 pinMode(13, OUTPUT);
 Timer1.initialize(500000);              <<<<< LIGNE MISE EN SURBRILLANCE PAR LE COMPILATEUR avec le message : " 'Timer1' was not declared in this scope "
 Timer1.attachInterrupt(Bascule);
}

void Bascule()
{
 digitalWrite(13, hool);
 hool = !hool;
}

void loop()
{}



Tim.h :
Code: [Select]

#ifndef Tim_h
#define Tim_h

#include "TimerOne.h"

#endif


Quelqu'un saurait-il pourquoi !?


Le compilateur me répond :
Code: [Select]

In file included from Timer1DansUnInclude.cpp:3:
/Tim.h:6:22: error: TimerOne.h: No such file or directory
Timer1DansUnInclude.cpp: In function 'void setup()':
Timer1DansUnInclude:8: error: 'Timer1' was not declared in this scope

Quidquid agis, prudenter agas, et respice finem !

barbudor

L'environnement Arduino fait des trucs bizarre. Il y a un Arduino-pre-processeur avant le pre-processeur du C qui parse le fichier INO et fabrique un fichier CPP.
Des fois les résultats sont étranges.

Je n'ai pas essayé ton code mais je ne serais pas étonné que la 1ere erreur que tu rencontre soit que dans Tim.h le  #include "TimerOne.h" ne marche pas (fichier include non trouvé).

Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

LibertyCareche

#2
Dec 06, 2012, 07:15 pm Last Edit: Dec 06, 2012, 07:32 pm by LibertyCareche Reason: 1
Merci pour ta réponse BarbuDOr   :)

Effectivement,... d'ailleurs, je viens de corriger le post en intégrant les erreurs transmises par le compilateur.
L'erreur "principale" retenue  est
'Timer1' n'a pas été déclaré dans cette portée

L'analyse par l'Arduino pré-prcesseur, dans ce cas est mal faite car le principe est on ne peut plus simple et le code semble correct tellement le changement est faible.
Quidquid agis, prudenter agas, et respice finem !

barbudor

En fait le pre-processeur arduino est là pour trouver les libs.
Quand tu met le include de "timerone.h" dans le ino, le preprocesseur arduino le voit, trouve le repertoire de la lib et met dans le cpp généré un include de "xxx/libraries/timerone/timerone.h"
De plus, celà lui permet aussi d'ajouter les sources de la lib dans la generation du projet.

Quand il est dans ton tim.h, il ne le trouve pas et doc le compilateur ne sait pas où le trouver.

Dans un vrai environnement de dev, c'est au développeur de configurer proprement les chemins vers les libs installées (ex. AVRstudio).

Arduino fait ce genre de bricolage pour rendre facile la plateforme a des non développeurs.
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

LibertyCareche

#4
Dec 06, 2012, 08:40 pm Last Edit: Dec 06, 2012, 09:09 pm by LibertyCareche Reason: 1
Je te crois sur parole mais je dois ajouter un argument qui ne va pas dans ce sens...

Le code en exemple est une simplification de mon problème. Dans mon problème réel, j'ai quelque chose comme ça :
String.h et Arduino.h sont appelées d'un ... je ne sais pas comment cela s'appelle en C... une "Unité" en Delphi... d'un .h nommé "def_code.h" (cf. la photo de la structure du programme) qui est situé tout en haut de la structure. Malgré cela... le tout fonctionne bien. Est-ce parceque TimerOne declare une classe...?

Code de TimerOne :

Code: [Select]

#ifndef TIMERONE_h
#define TIMERONE_h

#include <avr/io.h>
#include <avr/interrupt.h>

#define RESOLUTION 65536    // Timer1 is 16 bit

class TimerOne
{
 public:
 
   // properties
   unsigned int pwmPeriod;
   unsigned char clockSelectBits;
char oldSREG; // To hold Status Register while ints disabled

   // methods
   void initialize(long microseconds=1000000);
   void start();
   void stop();
   void restart();
void resume();
unsigned long read();
   void pwm(char pin, int duty, long microseconds=-1);
   void disablePwm(char pin);
   void attachInterrupt(void (*isr)(), long microseconds=-1);
   void detachInterrupt();
   void setPeriod(long microseconds);
   void setPwmDuty(char pin, int duty);
   void (*isrCallback)();
};

extern TimerOne Timer1;
#endif
Quidquid agis, prudenter agas, et respice finem !

LibertyCareche

Ta réponse a inspiré un essai positif, BarbuDOr,...

Je vais vérifier mais en re-déclarant dans Main : #include "TimerOne.h"
Je n'ai plus d'erreur... Je confirmerai plus tard.

Quidquid agis, prudenter agas, et respice finem !

barbudor

C'est parce que String.h et Arduino.h et les include avr sont dans des répertoires définis et connus.
Toutes les installations les ont et donc l'environnement Arduino les met dans les chemins d'include par défaut du compilateur GCC

Par contre les libs, tu en a certaines, j'en ai d'autres et pour chaque projet on n'utilise pas les mêmes.

Donc l'équipe Arduino a pris le partit :
- De ne pas inclure systématiquement toutes les libs installées dans les chemins de recherche d'include
- D'identifier celles que tu utilises en analysant le .INO et uniquement le .INO
- De fabriquer un CPP qui est le fichier INO re-travailler

Ce n'est pas un environnement de développement fait par des informaticiens, c'est à l'origine un projet d'artistes.

Regarde plus en détail les traces qui sont générés pendant la compil via l'IDE Arduino.
La phase de préprocesseur Arduino n'est pas montrée mais après fabrication du CPP :

Compilation de blink.cpp (fabriqué à partir de blink.ino).
Code: [Select]
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=102 -ID:\Projets\tools\arduino\hardware\arduino\cores\arduino -ID:\Projets\tools\arduino\hardware\arduino\variants\standard d:\tmp\build1109244496596348257.tmp\blink.cpp -o d:\tmp\build1109244496596348257.tmp\blink.cpp.o
Constate le peu de répertoire de recherche d'include qui sont passés : core-arduino, variant-standard (pour une UNO).

Compilation du Core Arduino :
Code: [Select]
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=102 -ID:\Projets\tools\arduino\hardware\arduino\cores\arduino -ID:\Projets\tools\arduino\hardware\arduino\variants\standard D:\Projets\tools\arduino\hardware\arduino\cores\arduino\WInterrupts.c -o d:\tmp\build1109244496596348257.tmp\WInterrupts.c.o
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-gcc -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=102 -ID:\Projets\tools\arduino\hardware\arduino\cores\arduino -ID:\Projets\tools\arduino\hardware\arduino\variants\standard D:\Projets\tools\arduino\hardware\arduino\cores\arduino\wiring.c -o d:\tmp\build1109244496596348257.tmp\wiring.c.o
.... (j'en enlève un pu)
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-g++ -c -g -Os -Wall -fno-exceptions -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=102 -ID:\Projets\tools\arduino\hardware\arduino\cores\arduino -ID:\Projets\tools\arduino\hardware\arduino\variants\standard D:\Projets\tools\arduino\hardware\arduino\cores\arduino\WString.cpp -o d:\tmp\build1109244496596348257.tmp\WString.cpp.o


Fabrique un vrai lib core.a a partir de ce qu'il vient de compiler :
Code: [Select]
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-ar rcs d:\tmp\build1109244496596348257.tmp\core.a d:\tmp\build1109244496596348257.tmp\WInterrupts.c.o
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-ar rcs d:\tmp\build1109244496596348257.tmp\core.a d:\tmp\build1109244496596348257.tmp\wiring.c.o
.....
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-ar rcs d:\tmp\build1109244496596348257.tmp\core.a d:\tmp\build1109244496596348257.tmp\WString.cpp.o


Edition de lien et fabrication du fichier HEX
Code: [Select]
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-gcc -Os -Wl,--gc-sections -mmcu=atmega328p -o d:\tmp\build1109244496596348257.tmp\blink.cpp.elf d:\tmp\build1109244496596348257.tmp\blink.cpp.o d:\tmp\build1109244496596348257.tmp\core.a -Ld:\tmp\build1109244496596348257.tmp -lm
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-objcopy -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 d:\tmp\build1109244496596348257.tmp\blink.cpp.elf d:\tmp\build1109244496596348257.tmp\blink.cpp.eep
D:\Projets\tools\arduino\hardware\tools\avr\bin\avr-objcopy -O ihex -R .eeprom d:\tmp\build1109244496596348257.tmp\blink.cpp.elf d:\tmp\build1109244496596348257.tmp\blink.cpp.hex


Regarde dans ton cas, identifie le répertoire de travail de l'IDE et va voir par toi même à quoi ressemble le CPP généré.



Il faut donc utiliser l'environnement Arduino pour ce qu'il est prévu : des petits projets simples.
Si tu veux plus de rigueur et un environnement traditionnel de développeur, tu prends AVRstudio.
Il faut ajouter quelques passerelles, recompiler le core-Arduino pour en faire une vrai lib et puis ca marche.
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

barbudor


Je vais vérifier mais en re-déclarant dans Main :[/color] #include "TimerOne.h"
Je n'ai plus d'erreur... Je confirmerai plus tard.


Normal. Car dans ce cas le pré-processeur Arduino à identifié la lib et modifié le CPP pour aller le chercher au bon endroit.
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

LibertyCareche


Si tu veux plus de rigueur et un environnement traditionnel de développeur, tu prends AVRstudio.
Il faut ajouter quelques passerelles, recompiler le core-Arduino pour en faire une vrai lib et puis ca marche.



Cela me parait bien au dessus de mes compétences mais je chercherai.
Je te remercie beaucoup pour tes réponses barbudor... faut que j'arrête avec le majuscules moi  :D
Quidquid agis, prudenter agas, et respice finem !

LibertyCareche

#9
Dec 06, 2012, 10:15 pm Last Edit: Dec 06, 2012, 10:23 pm by LibertyCareche Reason: 1
Voici une solution qui fonctionne...

Timer1DansUnInclude
Code: [Select]

#include "TimerOne.h"
#include "Tim.h"

void setup()
{
 pinMode(13, OUTPUT);
 initA();
}

void loop() {}


tim.h :
Code: [Select]

#ifndef Tim_h
#define Tim_h

#include "Arduino.h"
#include "TimerOne.h"

//boolean hool; //                <<< NOTEZ QUE LA DECLARATION ICI NE FONCTIONNE PAS !
//                                    MAIS PROVOQUE : ' multiple definition of `hool ' !!?

//void Bascule(); // pas besoin.
void initA();

#endif


tim.cpp :
Code: [Select]

#include "tim.h"

boolean hool; //                 <<< BIZAREMENT LA DECLARATION DOIT ETRE ICI !!

void Bascule()
{
 digitalWrite(13, hool);
 hool = !hool;
}
void initA()
{
 Timer1.initialize(500000);  
 Timer1.attachInterrupt(Bascule);
}



Le problème original étant "réglé",... à la barbare soit mais bon ...  Pourquoi la déclaration de hool dans le header ne fonctionne pas ?
Quidquid agis, prudenter agas, et respice finem !

barbudor

Il ne faut pas confondre définition et déclaration.

- La définition d'un objet (variable, fonction) décrit l'élément afin de procéder à son allocation et à le définir entièrement (mémoire, contenu type, nom/symbole ).
- La déclaration consiste à signifier (déclarer) qu'un élement existe mais ne procède pas à une réservation.

Le mot clé en C/C++ qui distingue une déclaration d'une définition est "extern" (en gros "viens d'ailleurs"). Le mot clé est optionnel pour une fonction : une fonction sans corps est une déclaration.

Exemple de déclarations à mettre dans un fichier MonCode.H :
Code: [Select]
extern int MaVariable;
extern int MaFonction( int param ); // mot clé extern optionel mais recommandé


Exemple de définitions à mettre dans un fichier MonCode.CPP :
Code: [Select]
int MaVariable = 0;
int MaFonction( int param )
{
  return param + 1;
}


Attention, ce qui est au dessus est vrai en C++ (fichier CPP) ou en C pur (sans mélange C/C++)

Ca ne marche plus pour du C que l'on veut appeller depuis du C++
Or le sketch INO va etre convertit en CPP et compilé comme du C++

Donc ce qui est au-dessus marchera SI ET SEULEMENT SI le fichier ci dessus est MonCode.CPP mais l'édition de lien va foirer si c'est MonCode.C

Pour qu'un code C soit utilisable tant depuis du C que du C++ il faut ajouter un petit truc au fichier H associé

Code: [Select]
#ifndef _MonCode_H
#define _MonCode_H

#ifdef __cplusplus
extern "C" {
#endif

extern int MaVariable;
extern int MaFonction( int param );

#ifdef __cplusplus
}
#endif

#endif // _MonCode_H


Pas besoin pour le fichier H associé à un fichier CPP. (une tendance est d'appelle HPP les fichiers H associés à un module CPP mais pas sur que ca marche avec Arduino.

Corrolaire : Il n'est pas possible d'utiliser un module C++ depuis un module C (alors que l'inverse oui si H respecte le code ci-dessus)
Barbuduino: Arduino sur Breadboard & VinciDuino: Clone Leonardo // WR703: Mini-routeur hacké // LauchPad MSP430 et Stellaris // Panda II Arduino-like .NetMF sous VisualC#
RTFC: Read That F.....g Code / RTFD: Read That F.....g Doc / RTFDS: Read That F.....g DataSheet / RTFS: Read That F.....g Schematic / Wot da ya wanna D.I.Y. today ?

LibertyCareche

Wahoo...   XD

Merci pour ces précieux, clairs et concis éclaircissements qui ...assombrissent un peu le code   :)

Le C/C++ est assez formidable par sa clarté/compacité mais... que de détails à gérer... et puis ce sont de "trucs" qui ne s'inventent pas... on le sait... ou pas !!

Quoiqu'il en soit barbudor, un grand merci   ;)
Quidquid agis, prudenter agas, et respice finem !

Go Up