Aide Aide programmation Arduino

L

lion10

Compagnon
Bonjour
Une variable globale aura une existence toute la durée du programme et sera accessible partout.
Une variable locale non statique sera allouée provisoire ment. Sans entrer dans les détails si on déclare énormément de variables globales on peut dépasser les capacités du micro-contrôleur. On le saura lors de l génération du programme exécutable phase d' édition de lien transparente je suppose dans l 'environnement Arduino pour l' utilisateur basique.
Si on déclare beaucoup ( grosse quantité tel un grand tableau) de variables locales selon l'enchaînement du programme, empilement d' appel de fonction on pourra avoir un" bug" en fonctionnement !
Pour la clarté du programme je préfère déclarer une variable locale dans la fonction plutôt que déclarer dans le bloc du "for"méme si le langage C le permet.
Si les noms des variables locales, globales et autres sont identiques cela pourra entraîner des bugs car le programme ne gérera pas forcément les variables comme on le pense sauf à regarder de près comment sont gérées les priorités locales / globales par le langage. En plus ce n'est pas clair.
Cdlt lion10
 
F

fredcoach

Compagnon
Je suis autodidacte avec arduino et de son langage. donc je ne suis pas un pro , :mrgreen:
ça fait longtemps que j'ai laissé tombé les variables locales , je n'utilise que des variables globales déclarées en début de programme, même les variables de boucles
ça m'oblige a être structuré , de définir un peusdo organigramme qui lui m^me va me definir mes besoins en termes de variable bien sur mais aussi en termes de fonctions.
C'est très bien pour un programme court et simple sur lequel tu es seul à travailler.
Mais si tu dois le modifier plus tard ou si quelqu'un d'autre doit le faire évoluer ou l'intégrer avec d'autres modules, la maintenance devient rapidement un enfer.
Plus il y a de variables globales plus il y a de risques de conflits de noms. Et ça, c'est un genre d'erreur qui peut te bouffer du temps et tes nerfs.
 
D

Dudulle

Compagnon
Oui c'est ça, on trouve des cours avec un certain formalisme, mais on peut très bien l'écrire à sa sauce.
l'important est de bien détailler chaque fonction, pour ne plus avoir qu'à le transcrire en langage final
 
W

wika58

Compagnon
salut c est comme même pas très clair tes #define
Pourquoi?
C'est comme ça qu'ils nous apprenent dans le cours.
D'après les profs ca permet d'enlever dans le code tous les liens vers les pins... et donc facilité la transposition à une appli avec d'autres pin.... et de rendre le code plus comprehensible...
 
W

wika58

Compagnon
Bonjour Pat

Ca ne la rend pas globale, elle ne sera pas plus visible en dehors. Satic fait que quand tu quittes une fonction où cette variable static est déclarée , la valeur de cette variable est conservée, sinon au prochain passage dans cette fonction elle repart à. 0

Essaies ça avec la console à 115200:
Cordialement
jpbbricole
Merci JP,
J'etais la journée chez ma fille...
Je reprends les cours demain... et j'essaie ton bout de code...
 
M

mvt

Compagnon
Bonsoir,

Ha les variables...
A mes début de la programmation, je n'avais à disposition que l'assembleur 360 (IBM) (on a fait des super trucs avec) et COBOL (un peu de RPG II, mais anecdotique). Tout devait être impérativement déclaré... et initialisé. Idem en C
En dehors des indices de tableau ou les I, J K & L sont souvent utilisés, on a vite fait de se mélanger les pinceaux dans les déclarations.
Pour moi, je mets en global tout ce qui est utile tout au long du programme, tout le reste est en local. Attention aux static, parfois, on a de grosses surprises !
Dans la démarche de programmation que l'on m'avait apprise à l'époque, on nous parlait de programmation structurée modulaire. C'est à dire que, dans les applications que nous avons développées et vendues, il y avait un ensemble de modules "auto suffisants" avec passage des valeurs par variables et un minimum de variables globales pour limiter le plus possible les effets de bord (C, Pascal, L4G Informix, L4G Oracle & Python). Je ne programme plus depuis longtemps en dehors de petites moulinettes de temps à autre en Python (manipulation de fichiers de données), mais j'ai conservé cette habitude.
Certains éditeurs de texte sont plus rigoureux côté syntaxe que l'IDE Arduino.
J'ai regardé rapidement le MOOC cité ci dessus. Intéressant. Il y a une liste de composant à trouver ? (interrupteurs, leds, etc. ou il existe des kits tout prêts ?)
 
M

midodiy

Compagnon
Regarde post17, j’ai mis la photo de ce que j’utilise
Une planche à pain
Une carte nano
2 led + 2 resistances
2 bouton-poussoirs
Pour l’instant, ça suffit.
 
M

mvt

Compagnon
Il faut que je regarde dans mes houilles, pour le board, ok, les fils ok, les arduino ok, les poussoirs, j'ai pas ça en stock (en enfichable), les leds, elles sont à récupérer.
Sinon, il y a leur shield robotique, mais dispo en Suisse uniquement apparemment
 
W

wika58

Compagnon
Oui leur shield ne semble pas obligatoire.
Et je dois dire que vu le peu de "présence" que j'ai relaté dans le msg initial j'aurais des craintes à commander qqch.
J'ai fait un mail aux profs sur l'adresse qui figure sur les documents et je n'ai jamais eu de reponse.
Il y a un document qui explique comment construire la platine de test necessaire pour les exos.

Moi je me suis pris un petits morceau de veroboard (où j'ai soudé les 2 BP, les 2 LED et le buzzer) que je peux enficher sur le Uno.
IMG_20240107_163808.jpg


Pour les BP, si tu n'en as pas sous la main, deux micro-switch font l'affaire aussi...


Si tu veux suivre le cours et que tu faits le montage, il est utile de respecter l'affectation GPIO pcq la vérification de ton programme est faite par un système "robotisé" (autre Uno monté en simulateur sur le Uno dans lequel ils download ton code). Et donc si tu n'as pas la bonne affectation ça déclare ton programme NOK alors qu'il est peut-être bon.

Mais bon ça c'est dans le cas où la soumission des exos de programmation fonctionne. Ce qui n'est pas le cas pour la session en cours...:smt022
 
Dernière édition:
S

speedjf37

Compagnon
Bonjour,
C'est comme ça qu'ils nous apprenent dans le cours.
D'après les profs ca permet d'enlever dans le code tous les liens vers les pins... et donc facilité la transposition à une appli avec d'autres pin.... et de rendre le code plus comprehensible...

[léger HS ON]
Il y a autant de méthode/style d'écriture de programme que de prof/programmeur.
La meilleure c'est celle qui te convient !

Pour en avoir lu des milliers/millions de ligne dans plusieurs langues on y trouve plus une philosophie/façon de penser que de la logique/organisation.
Le plus difficile c'est quand une fonction tient en une seule ligne qui fait plusieurs écran de large !

Chaque langage a aussi ses contraintes avantage et défauts.

Ayant pratiqué longtemps l'assembleur (et encore maintenant) j'ai toujours à l'esprit l'économie de mémoire pour le code et les variables.
C'est totalement opaque en C++ et de nombreux autres langages mais on sature vite un Arduino Uno/Nano.

Quand on gère de nombreuses entrée/sorties les contraintes matérielles nous rattrapent assez vite:
Rebond sur les contacts -> utiliser des lib avec debounce
Vitesse trop lente pour piloter des moteurs pas a pas -> lib stepper ou accelstepper
Acquisition de signaux rapides (Règles , encodeur , compteur -> lib ou gestion des compteurs internes
Afficheurs pour remplacer des leds
Afficheurs Lcd/oled pour afficher des menus

Utilisation des bus I2C SPI (I2S pour l'esp32)

Temps réel sur des projets un peu exigeants (interruptions , pas d'instruction delay ).

Et pour les plus gros projets découpage en nombreux fichiers.

Bienvenue à tous dans un monde quasiment sans limites !
Quand c'est trop dur/lourd laisser tomber un moment et s'y remettre plus tard , c'est souvent très instructif !

[léger HS OFF]

Cordialement JF
 
W

wika58

Compagnon
Encore une question sur les variables...:oops:

Elles peuvent s'écrire chaque fois de 2 façons:
- char ou int8_t
- unsigned char ou uint8_t
- int ou int16_t
- unsigned int ou usint_16
- long ou int32_t

Y a-t-il des avantages/inconvénients à l'une ou la l'autre écriture ?

Vaut-il mieux prendre la peine de se fixer l'une ou l'autre dénomination depuis le début ?
 
M

mvt

Compagnon
de façon schématique 8, 16 ou 32 indique le nombre de bits utilisés pour "stocker" ta valeur numérique, le chiffre représente donc aussi la puissance de 2 (binaire)
Ainsi un entier "simple" sur 8 bits est limité à +/-255 (FF en hexa décimal)
1 1 1 1 1 1 1 1
128 64 32 16 8 4 2 1
Sur 16 bits à 65536
Sur 32 bits à 4294967296
Avec bien entendu l'occupation mémoire correspondante.
Par exemple, Excel 2003 ne peut avoir au maximum de 2^16 lignes, limites qui a disparu par la suite.
Bien entendu, sur une grosse boucle ou un gros système de comptage (nombre de lignes d'un fichier par exemple à utiliser par exemple un Int 8 entrainera un dépassement de capacité une fois dépassé 255... mais pas toujours en fonction des compilateurs !

Finalement, un programme et les algorithmes associés, c'est un peu comme avec un tableur : il n'y a pas de mauvaise méthodes. Il y a plusieurs façons d'arriver au résultat. Certaines sont "propres" et maintenables, d'autres sont imbitables.
C'est aussi parfois le reflet de l'état d'esprit de celui qui a réalisé le truc ! Mais ça, c'est valable partout en ingénierie !
 
F

furynick

Compagnon
L'utilisation des variables globales est une mauvaise pratique très courante en prog Arduino et uC en général. Elles saturent rapidement la RAM.
D'un autre côté elles simplifient énormément la programmation donc il faut trouver un juste milieu.
En ce qui me concerne les objets des classes de bibliothèques et les variables d'interruptions sont définies en globales, pour le reste j'essaie de les limiter au maximum.

Pour les types il est largement préférable d'utiliser les notations explicites (uint8_t, int32_t, etc) pour éviter toute confusion.
Un int sur une Nano occupe 1 octet en mémoire, sur un ESP32 ça en occupe 4.
On peut donc se trouver avec des cas vicieux genre :

int b = 0;
while (b++ < 200);
print "terminé";

Sur une Nano c'est une boucle infinie.
 
Dernière édition:
P

Philippe85

Ouvrier
Un premier exemple est au sujet de la portée des variables.
J'ai bien compris que la variable peut être globale (si déclarée en tout début de programme) ou locale (si déclarée dans la boucle setup ou loop)..
Mais sur un Tuto, je vois qu'une variable locale "int i" dans la boucle Loop() peut être transformée en variable globale en lui mettant un "static int i".
A quoi ca sert et pourquoi ne pas déclarer le i en tout début... comme ça, il aurait une portée globale... :7hus5:
En C (sauf erreur de souvenir) static laisse la portée de la variable en locale (donc non utilisable hors portée) par contre elle est permanente (garde sa valeur) d'un passage à l'autre dans la portée. Typiquement quant on veut qu'une fonction garde la valeur précédente (en faisant attention à l'initialisation).
 
F

furynick

Compagnon
la syntaxe correcte pour la déclaration d'un static est la suivante (type et valeur à changer en fonction des besoins) :
static uint8_t var = 0;

Comme déjà dit en effet, les variables static n'ont qu'une portée locale mais leur espace mémoire est réservé globalement donc la valeur n'est pas perdue à la sortie de la fonction.

Pour préciser un peu le comportement des variables locales il faut comprendre le mécanisme d'allocation mémoire.
En très vulgaire, le compilateur va déterminer un espace mémoire nécessaire pour chaque fonction.
Lorsque cette fonction sera appelée, la quantité de mémoire nécessaire sera allouée et libérée à la fin de la fonction.
C'est pour cette raison qu'il est impératif d'initialiser les variables à leur première utilisation car, d'une fonction à l'autre, c'est potentiellement le même espace mémoire qui est utilisé et on peut ainsi retrouver les valeurs des variables d'une précédente fonction dans les variables locales d'une autre fonction.

Dans le même état d'esprit, il est aussi important d'éviter les cascades d'appel de fonction ou pire, les fonctions récursives (qui s'appellent ell-même). Tant qu'une fonction ne s'est pas terminée, son espace mémoire n'est pas libéré et la nouvelle fonction appelée va consommer elle aussi de la mémoire. Il y a donc un risque de saturation mémoire qui malgré tout est assez limitée sur un µC.
 
Dernière édition:
P

Philippe85

Ouvrier
Encore une question sur les variables...:oops:

Elles peuvent s'écrire chaque fois de 2 façons:
- char ou int8_t
- unsigned char ou uint8_t
- int ou int16_t
- unsigned int ou usint_16
- long ou int32_t

Y a-t-il des avantages/inconvénients à l'une ou la l'autre écriture ?

Vaut-il mieux prendre la peine de se fixer l'une ou l'autre dénomination depuis le début ?
Une question plus de style d'écriture (et de capacité des autres à relire pour certain choix int ou char).
Cela évite des confusions et indique ce que l'on veut faire.

Spontanément, et même si équivalent, je choisis int si c'est un numérique et char si c'est un caractère à l'usage. (attention aux évolutions peu prévisible un char pourrait demain être codé sur 2 caracteres).

Ensuite entre long et int32 dépend de la portabilité que l'on souhaite : int32 sera toujours sur 4 octets, long dépendra du microprocesseur et de son compilateur (8 bits, 16, 32, 64) au moment de la compilation. Donc si on fait un compteur et qu'on sait l'intervalle plutôt choisir la taille pour être sur de ne pas dépasser ou de gérer le dépassement, si on fait une calculatrice plutôt laisser le compilateur choisir sous condition de trapper les erreurs.

Beaucoup d'écriture en C sont équivalent mais un style assez constant améliore la maintenance et permet une aide. Je lis les réponses et pour avoir écrit quelques centaines de milliers de lignes dans plusieurs langages, il vaut mieux structurer son code, prendre de bonnes habitudes et le C est peu contraignant pour débuter.

Par exemple dans l'en-tête (du fichier, de la fonction ...), en premier les constantes servant de paramètre, puis les variables.
Au niveau global ou static limiter au maximum pour diminuer l'empreinte mémoire.
Éviter les déclarations au milieu du code (les heures passées ensuite à comprendre que la variable de boucle masque une autre variable).

Se faire une petite charte de nommage des fonctions, variables, constantes ... améliore le style
 
W

wika58

Compagnon
Merci messieurs pour avoir pris le temps de répondre au débutant que je suis. :smileJap:

Pour l'affectation static d'une variable c'est limpide.:smt023

Pour le choix "int" <> "int16_t" ou "long" <> "int32_t", je comprends bien que la 2° notation est plus claire/précise... mais quand je regarde la plupart des codes écrits pour nos applications DIY, c'est la première qui est utilisée à 95%...:7hus5:
 
F

furynick

Compagnon
oui, les dev sont flemmards et les novices tombent tous dans le piège par méconnaissance.
dans 95% des cas ça n'aura pas d'impact mais c'est une source d'erreur très difficile à identifier.

C'est comme partout, il y a des bonnes pratiques qui sont là pour prévenir d'un certain nombre de problèmes mais comme elles sont potentiellement contraignantes la plupart ne les suivent pas quand bien même elles en aurait connaissance (ce qui est rare).
 
F

furynick

Compagnon
De plus, coller toutes les variables en int est d'autant plus critiquable ce que c'est souvent le signe de la non prise en compte de la conso mémoire.
par ex.
for (int i = 0; i < 35; i++) {;}

Sur ESP32 ce sont 4 octets de mémoire consommés pour une variable qui ne consomme que 6 bits dans tous les cas.
Un seul octet suffit donc largement
for (uint8_t i = 0; i < 35; i++) {;}
 
G

greg_elec

Compagnon
existe-il un tableau avec les differends types de variables et leur occupation mémoire suivant arduino et esp 32 ?
 
F

furynick

Compagnon
on peut ajouter les alias suivants :
signed char = int8_t
unsigned char = uint8_t, byte
signed short = int16_t
unsigned short = uint16_t, word
signed long = int32_t
unsigned long = uint32_t
signed long long = int64_t
unsigned long long = uint64_t
 
G

gégé62

Compagnon
la syntaxe correcte pour la déclaration d'un static est la suivante (type et valeur à changer en fonction des besoins) :
uint8_t var = 0;
pardon de cette remarque, c'est pour être sûr que j'ai compris....il manque "static" avant ?

sinon merci pour toutes ces explications même si certaines me passent au-dessus....:).

Pour un ESP32 par exemple, donc qui travaille sur 32 bit, quand on définit une variable comme étant uint_8, on "consomme" réellement 4 fois moins de mémoire que si on mettait simplement int ?
 
F

furynick

Compagnon
Bien vu pour le static (j'ai corrigé ma monstrueuse boulette), c'est tout à fait exact !

En théorie oui mais le compilateur fait de nombreuses optimisations automatiquement.
Pour le vérifier tu peux créer un programme qui définit une variable globale de type int.
Lorsque tu compiles ce programme avec une Nano comme carte tu devrais avoir une consommation de 1 octet de mémoire.
Le même programme avec une ESP comme carte devrait statuer 4 octets de mémoire.

P.S. : désolé, je fais 2 trucs en même temps et j'ai lu ta question de travers donc je reformules ma réponse
Pour le vérifier tu peux créer un programme qui définit une variable globale de type int
Lorsque tu compiles tu devrais avoir une conso de 4 octets.
Après transformation de ta variable en uint8_t, le compilateur (toujours en ESP32) devrait t'indiquer 1 octet de mémoire consommée.
 
Dernière édition:
G

gégé62

Compagnon
Après transformation de ta variable en uint8_t, le compilateur (toujours en ESP32) devrait t'indiquer 1 octet de mémoire consommée.
En plus je n'avais pas à l'esprit que le travail du compilateur est fait en fonction du type de µC.....
 
F

furynick

Compagnon
Il faut imaginer que chaque µC a son propre langage (langage machine). Le compilateur a pour but de convertir le code d'un langage évolué en langage machine. Le compilateur est donc spécifique à chaque µC et un même programme aura donc des tailles différentes en fonction du µC de destination.
 

Sujets similaires

W
Réponses
122
Affichages
10 857
Philippe85
P
N
Réponses
3
Affichages
838
jpbbricole
jpbbricole
lolo
Réponses
0
Affichages
443
lolo
T
Réponses
1
Affichages
222
Teddy55
T
D
Réponses
0
Affichages
240
dodochef
D
osiver
Réponses
14
Affichages
37 503
osiver
osiver
D
Général langage MMBASIC
Réponses
8
Affichages
1 049
Dudulle
D
J
Réponses
12
Affichages
538
Robert
R
P
Réponses
33
Affichages
17 555
wika58
W
T
Réponses
2
Affichages
26 829
Tristan l'apprenti
T
esloch
Réponses
0
Affichages
352
esloch
esloch
altitude
Réponses
21
Affichages
2 883
laboureau
laboureau
laurenttanguy
Réponses
0
Affichages
560
laurenttanguy
laurenttanguy
Haut