[Résolue] Aide S.V.P pour les pointeurs « * » et « & » en langage Arduino,pas...

Bonjour,

Je suis nouveau en C, C++ et Arduino, mais j'étais très bon en langage Pascal.

Je souhaite travailler par adresse mémoire avec les pointeurs sur les registres des cartes Arduino :

J'ai trouvé sur « Programmation C » :

http://fr.wikibooks.org/wiki/Programmation_C/Pointeurs !

et

http://fr.wikibooks.org/wiki/Programmation_C_Types_avanc%C3%A9s#D.C3.A9finitions_de_synonymes_de_types_.28typedef.29

Il y a donc deux manières de travailler par adresse mémoire et pointeur en C :

1) :

uint16_t *ServomoteurBroche46 = &OCR5A;// Accès au registre ServomoteurBroche46 Timer5

2) :

// Définition du type de variable « t_Pointeur », qui est un pointeur « * »,
// de type « uint16_t » nommé « Pointeur ».
typedef uint16_t t_Pointeur *Pointeur;
Pointeur ServomoteurBroche46 = &OCR5A;// Accès au registre ServomoteurBroche46 Timer5

Mais, n'y l'une n'y l'autre ne fonction en Arduino !

Vous pourriez m'aider ?

Merci d'avance !

L'ami René

Humm… je me sert presque tout les jours des pointeurs mais la je vois vraiment pas ce que tu veux faire xD

Que ce que: “OCR5A” ???

Je suppose que ServomoteurBroche46 lui est égale à un numéro de broche?

Skizo

Là, un tuto http://forum.arduino.cc/index.php?topic=101780.0

uint16_t *ServomoteurBroche46 = &OCR5A;// Accès au registre ServomoteurBroche46 Timer5

Cette écriture fonctionne si OCR5A est une variable.
Si par contre OCR5A est un #define de l’adresse du registre alors il faut écrire

uint16_t *ServomoteurBroche46 = (int*)OCR5A;// Accès au registre ServomoteurBroche46 Timer5

Concernant cette partie

typedef uint16_t t_Pointeur *Pointeur;

typedef ne fonctionne pas comme ça
typedef définit une équivalence entre un type existant et un nouveau type
typedef type_atomic nouveau_nom_de_type;

Dans ton cas

typedef uint16_t* Pointeur;

Ce qui pourrait donner

Pointeur ServomoteurBroche46 = (int*)OCR5A;// Accès au registre ServomoteurBroche46 Timer5

Mais en fait il existe déjà des moyens plus simple d’accéder aux registres le compilateur définit des macro pour lire/écrire dans les registres

#define OCR0A _SFR_IO8(0x27)

OCR0A peu être utilisé dans des affectations à gauche ou à droite du signe égal.
Ces définitions sont dans le répertoire: hardware\tools\avr\avr\include\avr (enfin cela dépend si tes Windows ou Linux)

Bonjour skizoh,

“OCR5A”, c’est le nom en langage Arduino d’un registre des puces Artmel, c’est la variable qui conserve le fréquence de la minuterie numéro 5 “Timer5” qui contrôle le PWM de la broche numéro 46 d’une carte Arduino Mega.

Pour le moment j’utilise une directive de compilation comme « #define servo46 OCR5A », mais j’ai horreur de cela même si cela fonctionne déjà très bien.

J’ai plusieurs raisons, alors, dans le désordre :

  1. Pour rendre le code source plus modulable, car en général, on regroupe les directives de compilation hors de la structure des fonctions qui utilisent ces constantes et variables que sont les « #define ». Et on regroupe les directives de compilation au début (en haut du code source) et c’est parfois loin des fonctions qui les utilisent.

  2. De manière générale simplement mettre où je veux dans mon code des déclarations de constante et de variable.

  3. Éviter la lourdeur des directives de compilation.

  4. En général, avoir le moins possible recourt aux directives de compilation.

Une autre manière de dire que je veux remplacer la ligne de code « #define servo46 OCR5A », ce serait de dire que :

Comment faire pour que l’adresse mémoire de ma variable « ServomoteurBroche46 » soit la même que l’adresse mémoire du registre mémoire « OCR5A » ?

En langage Pascal, cela se fait facilement, alors en C++ cela devrait être encore plus facile !

Etc. Les goûts de chacun sont dans la nature et la manière de programmer aussi.

Mais on s’éloigne du sujet, les ligues de code que je écrie sont-elles valident ?

uint16_t *ServomoteurBroche46 = &OCR5A;

Cela devrait faire que la variable « OCR5A » et « ServomoteurBroche46 » ont la même adresse mémoire, est-ce exact ?

Et le code suivant :

typedef uint16_t t_Pointeur *Pointeur;
Pointeur ServomoteurBroche46 = &OCR5A;

Devrait aussi faire que la variable « OCR5A » et « ServomoteurBroche46 » ont la même adresse mémoire, est-ce exact ?

Mais cela ne passe pas à la compilation, alors pourquoi, et surtout, comment corrigé ce problème ?

Je suis sous Linux Kubuntu 12.04, 64 bits avec l’IDE Arduino 1.0.5.

Respectivement, les messages d’erreur sont pour « uint16_t *ServomoteurBroche46 = &OCR5A; »:

MegaLCD_ServoCinciAdresse:506: error: invalid conversion from ‘volatile uint16_t*’ to ‘uint16_t*’
MegaLCD_ServoCinciAdresse.ino: In function ‘void loop()’:
MegaLCD_ServoCinciAdresse:1018: error: call of overloaded ‘print(uint16_t*&)’ is ambiguous
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:58: note: candidates are: size_t Print::print(char) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:59: note:                 size_t Print::print(unsigned char, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:60: note:                 size_t Print::print(int, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:61: note:                 size_t Print::print(unsigned int, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:62: note:                 size_t Print::print(long int, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:63: note:                 size_t Print::print(long unsigned int, int) <near match>
MegaLCD_ServoCinciAdresse:1021: error: call of overloaded ‘print(uint16_t*&)’ is ambiguous
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:58: note: candidates are: size_t Print::print(char) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:59: note:                 size_t Print::print(unsigned char, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:60: note:                 size_t Print::print(int, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:61: note:                 size_t Print::print(unsigned int, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:62: note:                 size_t Print::print(long int, int) <near match>
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:63: note:                 size_t Print::print(long unsigned int, int) <near match>

Et pour :

typedef uint16_t t_Pointeur *Pointeur;
Pointeur ServomoteurBroche46 = &OCR5A;

MegaLCD_ServoCinciAdresse:504: error: expected initializer before ‘*’ token
MegaLCD_ServoCinciAdresse:505: error: ‘Pointeur’ does not name a type
MegaLCD_ServoCinciAdresse.ino: In function ‘void loop()’:
MegaLCD_ServoCinciAdresse:1013: error: ‘servo46’ was not declared in this scope

Le registre, la variable « OCR5A » est valide, cela fonctionne avec la directive de compilation, il n’y a pas de doute sur ce point.

Vous avez un remède docteur ?

L’ami René

Bonjour fdufnews,

Et merci pour toutes ces informations et votre aide !

fdufnews:
Là, un tuto http://forum.arduino.cc/index.php?topic=101780.0

Je regarde cela après l’écriture de mes réponses aux réponses.

fdufnews:

uint16_t *ServomoteurBroche46 = &OCR5A;// Accès au registre ServomoteurBroche46 Timer5

Cette écriture fonctionne si OCR5A est une variable.
Si par contre OCR5A est un #define de l’adresse du registre alors il faut écrire

C’est déjà dans le code d’Arduino, car je n’ai pas défini cette variable, et c’est dans la documentation Artmel de 448 pages pour les Mega.

fdufnews:
Concernant cette partie

typedef uint16_t t_Pointeur *Pointeur;

typedef ne fonctionne pas comme ça
typedef définit une équivalence entre un type existant et un nouveau type
typedef type_atomic nouveau_nom_de_type;

Mais voici ce que l’on trouve sur « Programmation C »

Quelques exemples:

typedef struct ma_structure * ma_struct;

/* Utilisation */

ma_struct pointeur = NULL;

Et « struct » c’est un type de variable.

fdufnews:
Dans ton cas

typedef uint16_t* Pointeur;

Oui, maintenant cette ligne passe la compilation. Bravo et merci !

fdufnews:
Ce qui pourrait donner

Pointeur ServomoteurBroche46 = (int*)OCR5A;// Accès au registre ServomoteurBroche46 Timer5

Cela me donne comme message d’erreur :

MegaLCD_ServoCinciAdresse:506: error: invalid conversion from ‘int*’ to ‘uint16_t*’
MegaLCD_ServoCinciAdresse.ino: In function ‘void loop()’:
MegaLCD_ServoCinciAdresse:1016: error: invalid conversion from ‘long int’ to ‘uint16_t*’
MegaLCD_ServoCinciAdresse:1021: error: call of overloaded ‘print(uint16_t*&)’ is ambiguous
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:58: note: candidates are: size_t Print::print(char)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:59: note: size_t Print::print(unsigned char, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:60: note: size_t Print::print(int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:61: note: size_t Print::print(unsigned int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:62: note: size_t Print::print(long int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:63: note: size_t Print::print(long unsigned int, int)
MegaLCD_ServoCinciAdresse:1024: error: call of overloaded ‘print(uint16_t*&)’ is ambiguous
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:58: note: candidates are: size_t Print::print(char)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:59: note: size_t Print::print(unsigned char, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:60: note: size_t Print::print(int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:61: note: size_t Print::print(unsigned int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:62: note: size_t Print::print(long int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:63: note: size_t Print::print(long unsigned int, int)

Et pour :

Pointeur ServomoteurBroche46 = (uint16_t*)OCR5A;

Ça passe à la compilation, mais le problème se retrouve plus loin avec :

ServomoteurBroche46 = map (PotentiometreValeur, 0, 1023, 1046, 4564);

Le compilateur donne :

MegaLCD_ServoCinciAdresse.ino: In function ‘void loop()’:
MegaLCD_ServoCinciAdresse:1016: error: invalid conversion from ‘long int’ to ‘uint16_t*’
MegaLCD_ServoCinciAdresse:1021: error: call of overloaded ‘print(uint16_t*&)’ is ambiguous
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:58: note: candidates are: size_t Print::print(char)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:59: note: size_t Print::print(unsigned char, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:60: note: size_t Print::print(int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:61: note: size_t Print::print(unsigned int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:62: note: size_t Print::print(long int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:63: note: size_t Print::print(long unsigned int, int)
MegaLCD_ServoCinciAdresse:1024: error: call of overloaded ‘print(uint16_t*&)’ is ambiguous
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:58: note: candidates are: size_t Print::print(char)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:59: note: size_t Print::print(unsigned char, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:60: note: size_t Print::print(int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:61: note: size_t Print::print(unsigned int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:62: note: size_t Print::print(long int, int)
/home/rene/sda6/Électroniques/Arduino_Linux/hardware/arduino/cores/arduino/Print.h:63: note: size_t Print::print(long unsigned int, int)

C’est comme si le compilateur ne voulait que des adresses mémoires pour mon pointeur « ServomoteurBroche46 ». Et là il y a bogue !

fdufnews:
Mais en fait il existe déjà des moyens plus simple d’accéder aux registres le compilateur définit des macro pour lire/écrire dans les registres

#define OCR0A _SFR_IO8(0x27)

OCR0A peu être utilisé dans des affectations à gauche ou à droite du signe égal.
Ces définitions sont dans le répertoire: hardware\tools\avr\avr\include\avr (enfin cela dépend si tes Windows ou Linux)

Oui, mais cela est plus lourd en ressource mémoire et processeur, etc.

En espérant que vous pourrez poursuivre votre aide qui m’est précieuse !

Merci encore !

L’ami René

Bonjour

Il n’y a PAS de langage Arduino. Le “sketche” (ou croquis comme on dit dans la Belle Province :)) est 100% du C++ et suit les règles du C++ (qui ne sont pas forcément celles du C).

uint16_t *ServomoteurBroche46 = &OCR5A;// Accès au registre ServomoteurBroche46 Timer5

Le début déclare une variable ServomoteurBroche46 qui est de type pointeur sur uint16 c’est à dire une variable qui contient une adresse.

OCR5A n’est pas une variable mais une macro qui s’étend après préprocesseur en :
(*(volatile uint16_t *)(0x128))
Elle s’utilise comme une pseudo variable dont l’emplacement mémoire a été forcé à 0x128 c’est à dire à l’adresse du registre OCR5A en question.
En écrivant :

OCR5A = valeur;

On écrit ‘valeur’ dans le registre en question.

En écrivant :

uint16_t *ServomoteurBroche46 = &OCR5A;

Tu fait 2 choses en même temps que l’on peut décomposer ainsi :

uint16_t *ServomoteurBroche46; // déclare une variable de type pointeur vers uint16
ServomoteurBroche46 = &OCR5A; // fait pointer la variable ServomoteurBroche46 vers l'adresse du registre OCR5A.

Donc les écritures ci-dessous sont maintenant équivalentes :

OCR5A = valeur;
(*(volatile uint16_t *)(0x128))= valeur;
*ServomoteurBroche46 = valeur;

Tu noteras le ‘*’ devant le nom de la variable qui désigne une indirection. Cella veut dire d’aller écrire “valeur” non pas dans la variable ServomoteurBroche46 mais à l’endroit pointé par ServomoteurBroche46.

Si tu veux passer par un typedef, ca donne :

typedef uint16_t *PointeurSurUint16;
PointeurSurUint16 ServomoteurBroche46 = &OCR5A;

Oui, mais cela est plus lourd en ressource mémoire et processeur, etc.

Archi faux.
Chercher à remettre l’adresse de OCR5A dans une variable puis écrire une indirection via cette variable :

  • occupe plus de mémoire RAM : création d’une variable supplémentaire qui prend 2 octets
  • occupe plus de flash : définit une table qui sert à l’initialisation de la dite variable
  • occupe plus de code : pour obtenir l’adresse du registre il faut d’abord aller lire la variable avant de pouvoir faire l’indirection
  • prend plus de cycles CPU : puisqu’il y a plus de code pour faire cela.

Rien n’est plus efficace que d’écrire

OCR5A=valeur;

barbudor: Rien n'est plus efficace que d'écrire

OCR5A=valeur;

Comme quoi je ne suis pas le seul à le penser ;)

C'est moi qui suis à l'origine de tout ça en fait hi hi hi! dans un code, j'ai mis tout au début #define servo46 OCR5A , ce qui permet de faire servo46 = valeur; ou valeur = servo46; simplement pour savoir qu'on commande le servomoteur connecté à la broche N°46.

Je conçois bien qu'il n'est pas facile quand on débute de comprendre tout ça...

De plus, dans le cas de René, c'est encore plus compliqué, car si l'on veut pouvoir utiliser toutes les pin permettant une gestion hard de servomoteur, on doit accéder à tous les OCRnX (n = timers 1, 3, 4 et 5, X = sorties A, B et C). ces registres sont dans la plage étendue, cad en RAM, il faut donc passer par leurs adresses (en 16bits).

uint16_t *ServomoteurBroche46 = 0x0128;// Accès au registre ServomoteurBroche46 Timer5

peut alors marcher, car on donne directement l'adresse du registre, mais l'accès sera comme l'a dit barbudor, deux fois plus long au moins...

je ne suis pas sûr que ça marche :

const uint16_t *ServomoteurBroche46 = 0x0128;// Accès au registre ServomoteurBroche46 Timer5

et perso, je trouve ça particulièrement illisible...

Dans tes 2 derniers cas, je pense qu'il faudra un cast pour que ca passe à la compil. J'ai pas essayé mais je ne vois pas pourquoi le dernier ne marcherait pas. Dans ce cas, l'implémentation pourrait être équivalente à OCR5Q sauf qu'il ne faut pas oublier l'étoile '*'

Un gros truc qui manque et sur lequel j'ai oublié de percuter : IL MANQUE LE VOLATILE !!!! Sans classifier la destination comme volatile, le compilateur peut optimiser (supprimer) les accès au registre ! Encore un inconvénient d'essayer de refaire soi même ce que d'autres ont déjà fait bien mieux :cold_sweat:

Et puisqu'on est en C++ on peut aussi écrire :

volatile uint16_t &RegistreToto = *(uint16_t*)0x128;
RegistreToto = 5;

barbudor: Un gros truc qui manque et sur lequel j'ai oublié de percuter :

et j'y avais pensé en plus...

Bonjour barbudor et Super_Cinci,

Un grand merci pour tous ces détails et toutes ces explications !

Il y a 25 (1988), dans ma formation comme programmeur analyste, à l’époque en langage Pascal on m’avait appris le contraire de ce que vous venez de décrire.

Je me souviens comme si c’était hier, le professeur explique que l’utilisation des pointeurs en Pascal économisait l’espace mémoire et le nombre d’instructions-machine pour un même résultat par rapport aux autres langages modernes. Car à la compilation, en Pascal, le compilateur remplaçait en code binaire le nom d’une variable par un pointeur de pointeur, alors que dans le cas d’un pointeur, c’est directement et uniquement l’adresse mémoire du pointeur qui était conservée dans le code binaire. Et le nombre d’instructions-machine était presque divisé par deux, quelque chose du genre 6 ou 7 au lieu de 13 ou 14 instructions.

Je n’ai à l’époque qu’effleuré l’Assembleur dans mes études, mais moi et deux autres copains avons fait un concours de programmation pour le code le plus rapide. Un petit programme pour trier directement à l’écran d’un ordinateur en temps réel, une matrice de 3200 caractères (80 x 40) avec les trois techniques de trie que nous venions d’apprendre, moi je programmais en Pascal, un en Assembleur et l’autre en C ou C++, je ne me rappelle plus du détail. Et le résultat corroborait les dires du professeur aux grands étonnements de tous. La vitesse d’exécution du Pascal, avec une large utilisation des pointeurs était de loin le plus performant de 30 % et 50 % respectivement par rapport à l’Assembleur et au C.

Le constat avec ce que vous expliquez, c’est que les choses ont bien changé depuis.

Voilà pour la petite histoire.

Je teste le code avec le « typedef … » pour ne pas avoir à utiliser constamment le « * » et je vous reviens avec les résultats comparatifs avec le code utilisant le « #define … ».

Merci encore !

L’ami René

Rebonjour,

Bon, avant d’avoir des résultats, il faut que ça passe à la compilation. Dans mon code qui fonctionne avec le « #define », j’ai remplacé avec le code :

//  #define Servomoteur46 OCR5A // Accès au registre Servomoteur46 Timer5
  typedef uint16_t *PointeurUint16;
  PointeurUint16 Servomoteur46 = &OCR5A;

Mais, j’ai les erreurs suivantes :

Arduinobot_Cinci_01_typedef.ino: In function ‘void Servomoteur46Init(word)’:
Arduinobot_Cinci_01_typedef:672: error: invalid conversion from ‘volatile uint16_t*’ to ‘uint16_t*’
Arduinobot_Cinci_01_typedef.ino: In function ‘void SortieTrouve()’:
Arduinobot_Cinci_01_typedef:1223: error: ‘Servomoteur46’ was not declared in this scope
Arduinobot_Cinci_01_typedef.ino: In function ‘void CapAuPlusGrandDegagement()’:
Arduinobot_Cinci_01_typedef:1483: error: ‘Servomoteur46’ was not declared in this scope
Arduinobot_Cinci_01_typedef.ino: In function ‘void TrouverPlusGrandDegagement()’:
Arduinobot_Cinci_01_typedef:1509: error: ‘Servomoteur46’ was not declared in this scope
Arduinobot_Cinci_01_typedef.ino: In function ‘void setup()’:
Arduinobot_Cinci_01_typedef:1684: error: ‘Servomoteur46’ was not declared in this scope

Vous pouvez m’aider, le n’ai pas d’idée pour corriger ce problème ?

L’ami René
P.-S. Tout le code source en pièce jointe, et la ligne de code, ligne 670 du fichier « Arduinobot_Cinci_01_typedef.ino ».

Arduinobot_Cinci_01_typedef.zip (15.8 KB)

essaie en forçant l'adresse mémoire en direct :

//  #define Servomoteur46 OCR5A // Accès au registre Servomoteur46 Timer5
  typedef uint16_t *PointeurUint16;
  PointeurUint16 Servomoteur46 = 0x0128;

Il semble que pointer sur un alias ne soit pas une bonne idée.

Salut Super_Circin,

Je ne comprends pas, comment on fait ça « en forçant l'adresse mémoire en direct » ?

L'ami René

PointeurUint16 Servomoteur46 = 0x0128;

Bonjour Super_Circin,

Merci pour la ligne de code, c’est très apprécié !

Donc le code :

  typedef uint16_t *PointeurUint16;
//  PointeurUint16 Servomoteur46 = &OCR5A;
  PointeurUint16 Servomoteur46 = 0x0128;

Me donne :

Arduinobot_Cinci_01_typedef.ino: In function ‘void Servomoteur46Init(word)’:
Arduinobot_Cinci_01_typedef:672: error: invalid conversion from ‘int’ to ‘uint16_t*’
Arduinobot_Cinci_01_typedef.ino: In function ‘void SortieTrouve()’:
Arduinobot_Cinci_01_typedef:1222: error: ‘Servomoteur46’ was not declared in this scope
Arduinobot_Cinci_01_typedef.ino: In function ‘void CapAuPlusGrandDegagement()’:
Arduinobot_Cinci_01_typedef:1482: error: ‘Servomoteur46’ was not declared in this scope
Arduinobot_Cinci_01_typedef.ino: In function ‘void TrouverPlusGrandDegagement()’:
Arduinobot_Cinci_01_typedef:1508: error: ‘Servomoteur46’ was not declared in this scope
Arduinobot_Cinci_01_typedef.ino: In function ‘void setup()’:
Arduinobot_Cinci_01_typedef:1683: error: ‘Servomoteur46’ was not declared in this scope

Et ma fonction complète « void Servomoteur46Init(word) » c’est :

//*****************************************************************************
// FONCTION Servomoteur46Init
//*****************************************************************************
void Servomoteur46Init (word T)
{
//  #define Servomoteur46 OCR5A // Accès au registre Servomoteur46 Timer5
  typedef uint16_t *PointeurUint16;
//  PointeurUint16 Servomoteur46 = &OCR5A;
  PointeurUint16 Servomoteur46 = 0x0128;
  
  if (T > 32767)
  {
    T = 32767;      // Période maximum possible : 32,7ms
  }

  TCCR5A  = 0;
  TCCR5B  = 0;
  ICR5    = T << 1;        //  TOP : T(pwm)
  TCCR5A |= 0x02;
  TCCR5C  = 0x00;
  TCCR5B  = 0x1A;  // Activer timer5, prescaler = F_CPU/8  
  DDRL   |= 0x08;  // port L3 en sortie
  TCCR5A |= 0x80;  // activation OC5A
  TCCR5A &= 0xBF;
}
//*****************************************************************************

Une idée du problème ?

L’ami René

Stop !

j'ai dit que

uint16_t *PointeurSurUint16 = &variable;

était décomposable en/équivalent à

uint16_t *PointeurSurUint16;
PointeurSurUint16 = &variable;

uniquement pour illustrer que tu fais 2 choses en 1 seule ligne : une déclaration et une initialisation. Cela ne veut pas dire que tu peux effectivement écrire de cette façon n'importe où.

La 1ère ligne est une définition -> ne génère pas de code mais uniquement une réservation en mémoire de la variable PointeurSurUint16 La 2nde ligne est une affectation -> demande donc à générer du code pour écrite une valeur dans la variable Hors tu ne peut pas générer de code en dehors d'un corps de fonction.

Donc dans le cas l'espace global en dehors d'une fonction, seule l'écriture condensée définition + initialisation est autorisé. Par contre l'écriture en 2 lignes marcherait dans le corps d'une fonction mais dans ce cas la variable serait une variable locale à la fonction.

A noter que l'initialisation d'une variable dans l'espace globale et l'affectation d'une variable dans le corps d'une fonction se passe de manière totalement différente. Dans le cas de l'initialisation lors de la définition, aucun code spécifique n'est généré. Le compilateur réserve une zone mémoire correspondant à la variable puis préparer une table d'initialisation en FLASH qui va contenir les valeurs d'initialisation. A l'exécution, avant le main(), une boucle vient recopier les valeurs d'initialisation de table vers la RAM pour initialiser d'un coup toutes la variables globales. De plus, en C++, si la variable est un objet, le constructeur est appelé.

C'est fou tout ce qui se passe avant d'arriver au main().

Par rapport au code de ta fonction. Généralement on ne déclare pas un typedef dans un corps de fonction. Ce n'est pas que ça ne marche pas mais généralement quand on déclare un type c'est pour l'utiliser à plusieurs endroits. Un typedef n'est qu'une déclaration, un raccourcis d'écriture. Cela ne génère aucun code machine et ne sert qu'à rendre le source éventuellement plus lisible.

La première erreur que te retourne la compilation est due à la conversion de type : le compilateur refuse de convertir un int (0x128) en un pointeur sans que tu lui dise explicitement de le faire. C'est ce qu'on appelle un cast : il faut forcer un changement de type sur 0x128 pour le faire considérer comme un pointeur afin que l'initialisation soit effectué.

void test()
{
  typedef uint16_t *PointeurSurUint16;
  PointeurSurUint16 ptr = (uint16_t *)0x128;
  
  *ptr  = 55;
}

Voir même :

void test()
{
  typedef uint16_t *PointeurSurUint16;
  PointeurSurUint16 ptr = (PointeurSurUint16)0x128;
  
  *ptr  = 55;
}

LamiRene: Donc le code :

  typedef uint16_t *PointeurUint16;
//  PointeurUint16 Servomoteur46 = &OCR5A;
  PointeurUint16 Servomoteur46 = 0x0128;

Me donne :

Arduinobot_Cinci_01_typedef.ino: In function ‘void Servomoteur46Init(word)’: Arduinobot_Cinci_01_typedef:672: error: invalid conversion from ‘int’ to ‘uint16_t*’ Arduinobot_Cinci_01_typedef.ino: In function ‘void SortieTrouve()’: Arduinobot_Cinci_01_typedef:1222: error: ‘Servomoteur46’ was not declared in this scope Arduinobot_Cinci_01_typedef.ino: In function ‘void CapAuPlusGrandDegagement()’: Arduinobot_Cinci_01_typedef:1482: error: ‘Servomoteur46’ was not declared in this scope Arduinobot_Cinci_01_typedef.ino: In function ‘void TrouverPlusGrandDegagement()’: Arduinobot_Cinci_01_typedef:1508: error: ‘Servomoteur46’ was not declared in this scope Arduinobot_Cinci_01_typedef.ino: In function ‘void setup()’: Arduinobot_Cinci_01_typedef:1683: error: ‘Servomoteur46’ was not declared in this scope

Il faut apprendre à lire les messages d'erreur. La ligne importante est celle-là:

Arduinobot_Cinci_01_typedef:672: error: invalid conversion from ‘int’ to ‘uint16_t*’

C est stricte sur les types. On ne peut pas affecter une valeur/variable d'un type à une variable d'un autre type. Il faut soit: - que les 2 parties de l'égalité aient le même type - faire explicitement la conversion de type (ce qu'on appelle le cast) en précisant devant la valeur le type dans lequel on veut la convertir. La conversion n'est pas transparente, il peut y avoir des pertes dans certains cas. Par exemple quand on cast un int en char on perd l'octet de poids fort.

Les constantes sont par défaut de type int donc dans ton cas comme l'explique barbudor il faut indiquer la conversion en pointeur

le #define d'origine marchait si bien... =>[]

Bonjour,

LamiRene: Bonjour fdufnews,

Et merci pour toutes ces informations et votre aide !

fdufnews: Là, un tuto http://forum.arduino.cc/index.php?topic=101780.0

Je regarde cela après l'écriture de mes réponses aux réponses. ...

Bon cela est fait.

Merci encore !

L'ami René

barbudor: ... Rien n'est plus efficace que d'écrire

OCR5A=valeur;

Rebonjour tout le monde !

Ok, je reprends avec cette dernière citation qui est à l'origine de mon problème et je tente d'en faire une synthèse.

Pour mon cerveau biologique de chaire et de sang, qui ne dispose que de 2 K de mémoire, quand je vois dans mon code source « OCR5A », cela ne me dit rien, mais si je voyais à sa place « FréquenceSurLaBrochePWM_46 », cela me dit tout et m'est rapidement compréhensible.

Alors la conclusion de ce que vous m'avez écrit, c'est que pour pouvoir remplacer dans mon code source le littéral « OCR5A » par un littéral qui me parle plus, comme par exemple « FrequenceBroche46 » de la manière la plus simple, la moins gourmande en CPU et en mémoire, et la plus performante en vitesse d'exécution, c'est avec une directive de compilation du genre « #define FrequenceBroche46 OCR5A ».

Tout cela est bien noté et vous me le dites si je me suis gouré ou pas !

La meilleure manière de faire la désignation des broches analogiques et digitales des cartes Arduino, est-ce aussi avec des « #define » ?

Par exemple aurais-je avantage a changer pour des « #define » les désignations de broche, pour un capteur sonar HC-SR04 ou un capteur infrarouge pour télécommande VS1838B ou un pont en H L298N pour contrôler des moteurs CC :

Pour le moment, j'ai comme ligne de code :

...
// Broche d'Arduino pour recevoir le signale du capteur infrarouge.
const byte CAPTEUR_IR_1_1SORTIE = 53;
...
// Broche d'Arduino pour le capteur a ultrason 2, le sonar.
const byte Sonar_1_TRIG = 24;
const byte Sonar_1_ECHO = 25;
...
// Broche d'Arduino pour le contrôleur moteur 1 (double Pont en H).
const byte CONTROLE_MOTEUR_1_ENA = 14;
const byte CONTROLE_MOTEUR_1_IN1 = 15;
const byte CONTROLE_MOTEUR_1_IN2 = 16;
const byte CONTROLE_MOTEUR_1_ENB = 17;
const byte CONTROLE_MOTEUR_1_IN3 = 18;
const byte CONTROLE_MOTEUR_1_IN4 = 19;
...

Encore un grand merci à tous les grands pédagogues du forum ! Oui oui, c'est de toi que je parle ! ;)

L'ami René