LOCODUINO

Ces tableaux qui peuvent nous simplifier le développement Arduino

.
Par : bobyAndCo

L’ambition de ce petit article n’est pas de faire une présentation exhaustive de ce que sont les tableaux dans le langage Arduino et C/C++ mais plus simplement d’apporter quelques « recettes » qui pourraient bien faciliter grandement vos développements.

Il est par exemple assez fréquent de voir des programmes où la déclaration et l’initialisation des broches sont faites de la manière suivante :

const int Pin23 = 23; 
const int Pin24 = 24;
const int Pin25 = 25;
const int Pin26 = 26;
const int Pin27 = 27;
const int Pin28 = 28;
...

Et parfois, les listes sont bien plus longues.

Et puis, dans le setup on trouve :

  pinMode(Pin23,  OUTPUT);
  pinMode(Pin24,  OUTPUT);
  pinMode(Pin25,  OUTPUT);
  pinMode(Pin26,  OUTPUT);
  pinMode(Pin27,  OUTPUT);
  pinMode(Pin28,  OUTPUT);
  ...

et puis encore la commutation des broches (dont cette fois je me dispenserai de faire toute la liste)

digitalWrite(Pin23, HIGH);
digitalWrite(Pin24, HIGH);
...

Procéder ainsi est exact au regard de la programmation. Mais c’est long, fastidieux, source d’erreurs et cela rend la maintenance problématique. Par ailleurs, ça prend beaucoup de place dans l’IDE et rend difficile une vision globale de notre code nécessitant d’utiliser les ascenseurs de la page. Quand on voit le bas du code, on ne voit plus le début et quand on voit le début, on ne voit pas la fin.

Encore une fois, ce que je présente ici n’est pas un cours sur les tableaux. Les puristes pourront dire que l’on pouvait faire encore plus, encore mieux. Je m’adresse ici avant tout aux lecteurs qui n’ont pas beaucoup d’expérience mais sont (très) motivés pour faire des programmes Arduino efficaces pour leur réseau et qui peuvent parfois passer beaucoup de temps à résoudre des erreurs relevant d’une simple faute de frappe.

Comment savoir si je dois recourir à l’utilisation d’un tableau ?

D’une manière générale, dès que vous rédigez des lignes de code répetitives, il y a de grandes chances qu’un tableau puisse vous simplifier la vie. Mais plutôt que des discours, voyons un exemple. Voici comment, avec un tableau, il est possible d’écrire les lignes de code présentées ci-dessus :

const byte pin[] = {22, 23, 24, 25, 26, 27, 28}; // Déclaration et initialisation d'un tableau

pin[] = {...,...}; est l’une des façons de déclarer un tableau qui portera le nom pin. Son type doit être le même que celui des valeurs qu’il contient. Ici ce sont des bytes puisqu’ils représentent des broches de la carte et que leur nombre n’atteindra jamais 256.. Et nous les déclarons comme constantes (const) puisqu’elles ne vont pas changer de valeur au cours de notre programme. N’hésitez pas à vous reporter à l’article de Jean-Luc qui met en lumière l’importance d’un bon typage.

Utiliser les tableaux.

Un tableau est une liste ordonnée de valeurs de même type. La taille d’un tableau correspond au nombre d’éléments du tableau. Ici, il y 7 éléments dans notre tableau de broches. On dit donc que la taille du tableau est 7.

Pour accéder à la valeur d’un élément du tableau, on utilise son index. Ici, le premier élément a la valeur 22, le second 23 et le dernier 28. Mais il y a une subtilité qui vous posera sans doute quelques déboires au début. Le premier élément du tableau a pour index 0 (zéro) et non 1. Le second a pour index 1 et ainsi de suite.

Si l’on voulait par exemple placer dans la variable test la valeur de la première broche, on écrirait ceci :

byte test = pin[0]; // test == 22

Avant d’aller plus loin, il faut que je vous présente le meilleur allié du tableau, la boucle for. Utilisée conjointement aux tableaux, elle fera des merveilles dans vos programmes. La boucle for est elle aussi indispensable pour traiter des opérations répétitives. Regardez par exemple comment je déclare mes broches de tout à l’heure en OUTPUT et que je les commute ensuite à HIGH dans mon setup :

void setup() {
  for (int i = 0; i < 7; i++) {
    pinMode(pin[i], OUTPUT);       // Toutes les pins sont commutées en OUT
    digitalWrite(pin [i], HIGH);      // Toutes les pins prennent pour valeur HIGH
  } // Fin de la boucle for
} // Fin Setup

Quatre lignes de code alors qu’il m’en fallait dix huit précédemment.

Ici toutes mes broches se suivaient, mais cela aurait aussi fonctionné de la manière suivante :

const byte pinIn[] = {22, 24, 26, 28, 30, 32, 34};
const byte pinOut[] = {23, 25, 27, 29, 31, 33, 35};

void setup() {
  
  for (int i = 0; i < 7; i++) {
    pinMode(pinIn[i], INPUT);      // Toutes les pins in sont commutées en IN
    digitalWrite(pinIn[i], LOW);   // Toutes les pins in ont pour valeur LOW
    pinMode(pinOut[i], OUTPUT);    // Toutes les pins out sont commutées en OUT
    digitalWrite(pinOut[i], HIGH); // Toutes les pins out ont pour valeur HIGH
  } // Fin de la boucle for
  
} // Fin Setup

Prenons un autre exemple. Imaginons que mon programme soit destiné à piloter les 16 aiguillages de notre réseau. Je vais encore pouvoir simplifier un peu le code ci-dessus.

Voici une autre façon de déclarer un tableau que l’on va ici appeler aiguillage tout simplement et dont on va mettre le nombre d’éléments qu’il contiendra entre les [] :

byte aiguillage[16]; // Déclaration d'un tableau ayant pour nom aiguillage dont la taille est de 16 éléments.

Notez bien qu’ici mon tableau est juste déclaré et pas encore initialisé car je ne lui ai donné aucune valeurs. Je vais le faire dans le setup d’une manière un peu similaire à toute à l’heure :

const byte nbre_aiguillages = 16;
byte aiguillage[nbre_aiguillages];        // Déclaration d'un tableau "aiguillage" de taille "nbre_aiguillages", soit 16 éléments.
const byte first_pin = 22;                // Valeur de la première pin qui va contrôler mes aiguilles.

void setup() {
  for (int i = 0; i < 16; i++) {
    byte pin = first_pin + i;            // va prendre la valeur 22 quand i = 0, 23 quand i = 1 etc…
    aiguillage[i] = pin;                 // revient à écrire, si i = 0, aiguillage[0] = 22, si i = 1, aiguillage[1] = 23
    pinMode(aiguillage[i], OUTPUT);     // Toutes les pins sont commutées en OUT
    digitalWrite(aiguillage[i], LOW);   // Toutes les pins ont pour valeur LOW
  } // Fin de la boucle for
} // Fin Setup

Allez, une dernière astuce pour rendre votre code plus facilement maintenable. En effet, si vous ajoutez une aiguille sur votre réseau, vous voyez bien que vous allez devoir parcourir le code pour remplacer 16 par 17.

Proposition -> ajouter au début de votre sketch :

#define NBRE_AIGUILLAGE 16

#define s’appelle une directive. Son comportement est assez simple. Quand vous lancez la compilation, le compilateur va commencer par rechercher partout dans votre code là où vous avez écrit NBRE_AIGUILLAGE et il va remplacer ce texte par la valeur 16. Un peu comme quand vous utilisez la fonction remplacer un mot par un autre dans un traitement de texte. Quel est l’intérêt ? Démonstration avec le code précédent :

#define NBRE_AIGUILLAGE 16
byte aiguillage[NBRE_AIGUILLAGE] ; // Déclaration d’un tableau dont la taille est NBRE_AIGUILLAGE, ici 16
const byte first_pin = 22 ; // Valeur de la première pin qui va contrôler mes aiguilles.

void setup() {
  for (int i = 0; i < NBRE_AIGUILLAGE; i++) {
    byte pin = first_pin + i;                  // va prendre la valeur 22 quand i = 0, 23 quand i = 1 etc…
    aiguillage[i] = pin;                       // revient à écrire, si i = 0, aiguillage[0] = 22, si i = 1, aiguillage[1] = 23
    pinMode(aiguillage [i], OUTPUT);           // Toutes les pins sont commutées en OUT
    digitalWrite(aiguillage [i], LOW);         // Toutes les pins ont pour valeur LOW
  } // Fin de la boucle for
} // Fin Setup

Vous voyez que si je change le nombre d’aiguillage, par exemple :

 

#define NBRE_AIGUILLAGE 18, toute la suite de mon code reste vraie sans que j’ai besoin de le modifier.

Je ne voudrais pas rendre les choses trop compliquées mais je souhaitais vous donner quelques autres avantages des tableaux par exemple dans le loop. Attention, soyez attentif, je vais volontairement introduire une difficulté qui nous a tous piégée un jour.

Pour commander mes 16 aiguilles, on va dire que j’ai 16 boutons numérotés de 1 à 16

Pour eux aussi, je vais me simplifier la vie en les plaçant dans un tableau :

byte btn[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

Voici donc un tableau contenant 16 boutons numérotés sur mon TCO de 1 à 16. Dans le programme, on peut écrire :

digitalWrite(aiguillage [btn[1]], LOW);

Ce qui revient à dire, faire un digitalWrite sur la broche aiguillage qui a pour index le bouton sélectionné. Ici le btn[1]. Ca fonctionne très bien et c’est même plutôt recommandé de programmer ainsi. Seulement, quelle ne sera pas votre surprise de constater que c’est l’aiguille 2 qui se mettra en mouvement et non la 1.

En effet, ne confondez pas l’index du tableau, et la valeur correspondant à cet index. L’index d’un tableau commence à 0 alors que dans notre cas, nous avons commencé la numérotation de nos boutons à 1.

Aussi :

btn[0] = 1;
btn[1] = 2;
.....

Pas très logique me direz-vous ! Eh bien si ; vous avez le droit de numéroter vos boutons comme vous le voulez. Pourquoi pas :

byte btn[] = {1, 12, 34};

* Sur ce point, je vous invite à lire attentivement la petite mise en garde en fin d’article.

Enumérations et tableaux.

Il n’est pas toujours facile de s’y retrouver avec des syntaxes qui ne sont pas très explicites :

byte btn[] = {1, 12, 34}; ou btn[1] ou encore btn[14]

D’aucun préfèrera des formulations comme « entrée gare », « sortie gare », « entrée dépôt »

Cela est envisageable en ayant recours aux énumérations :

enum { ENTREE_GARE, SORTIE_GARE, ENTREE_DEPOT,… };

déclare les identificateurs ENTREE_GARE, SORTIE_GARE, ENTREE_DEPOT,… comme étant des constantes entières de valeur 0, 1, 2, 3 ...

 

Dans le code, cela va se traduire ainsi : digitalWrite(aiguillage [btn[ENTREE_GARE]], LOW);
plus lisible que : digitalWrite(aiguillage [btn[0]], LOW);

 

Au sujet des énumérations, vous pouvez là encore vous reporter à l’article de Jean-Luc cité plus haut sur les constantes. http://www.locoduino.org/spip.php?a...

L’EEPROM est un tableau.

Pour finir, un exemple utilisant la mémoire EEPROM. On hésite souvent à enregistrer des données dans l’EEPROM simplement parce que l’on ne sait pas comment ça fonctionne. Là encore, mon objectif n’est pas de vous expliquer l’EEPROM mais de permettre que vous vous en serviez.

Eh bien l’EEPROM est un tableau de cases mémoire. Un UNO dispose ainsi de 1024 « cases » mémoire en EEPROM qui peuvent chacune stocker 1 octet (8 bits).

Pour éviter toute déconvenue, je vous invite à utiliser quand vous le pouvez le type byte pour votre tableau qui correspond exactement à la taille d’une case mémoire. Le byte est un nombre entier non signé d’une valeur de 0 à 255 ce qui est largement suffisant dans notre exemple à 16 aiguillages.

Comme cela est expliqué dans l’article de Locoduino sur la bibliothèque EEPROM vous pouvez utiliser la fonction EEPROM.write avec le numéro de la case mémoire puis la valeur que vous souhaitez enregistrer.

Pour vous y retrouver facilement, vous pouvez écrire :

#define NBRE_AIGUILLAGE 16
byte aiguillage[NBRE_AIGUILLAGE]; // Déclaration d’un tableau dont la taille est NBRE_AIGUILLAGE, ici 16
byte aigPos[NBRE_AIGUILLAGE]; // Déclaration d’un tableau qui va stocker la position de chaque aiguille
for (int i = 0; i < NBRE_AIGUILLAGE; i++) {
    aigPos[i] = HIGH;
    digitalWrite(aiguillage[i], aigPos[i]);
    EEPROM.write(i, aigPosit[i]);
}

mais vous pouvez aussi écrire sous forme de tableau :

#define NBRE_AIGUILLAGE 16
byte aiguillage[NBRE_AIGUILLAGE]; // Déclaration d’un tableau dont la taille est NBRE_AIGUILLAGE, ici 16
byte aigPos[NBRE_AIGUILLAGE]; // Déclaration d’un tableau qui va stocker la position de chaque aiguille
for (int i = 0; i < NBRE_AIGUILLAGE; i++) {
    aigPos[i] = HIGH;
    digitalWrite(aiguillage[i], aigPos[i]);
    EEPROM[i] = aigPosit[i] ;
}

De même, pour charger dans le setup par exemple les valeurs contenues dans l’EEPROM :

#include <EEPROM.h>
#define NBRE_AIGUILLAGE 16
byte aiguillage[NBRE_AIGUILLAGE];      // Déclaration d’un tableau dont la taille est NBRE_AIGUILLAGE, ici 16
const byte first_pin = 22;             // Valeur de la première pin qui va contrôler mes aiguilles.

void setup() {
  for (int i = 0; i < NBRE_AIGUILLAGE; i++) {
    byte pin = first_pin + i;                    // va prendre la valeur 22 quand i = 0, 23 quand i = 1 etc…
    aiguillage[i] = pin;                        // revient à écrire, si i = 0, aiguillage[0] = 22, si i = 1, aiguillage[1] = 23
    pinMode(aiguillage[i], OUTPUT);            // Toutes les pins sont commutées en OUT
    if (NULL == EEPROM[i])                      // Pas de valeur dans l'EEPROM à cette adresse
      digitalWrite(aiguillage[i], HIGH);       // Alors valeur par defaut : HIGH
    else                                        // Il y a une valeur dans l'EEPROM à cette adresse
      digitalWrite(aiguillage[i], EEPROM[i]);
  } // Fin de la boucle for
} // Fin Setup

En conclusion :

L’utilisation des tableaux nécessite une petite gymnastique intellectuelle mais permet de simplifier grandement le code, de le sécuriser et le rendre plus facilement maintenable.

A chaque fois que vous commencez à manipuler des données répétitives et en grand nombre, dites vous que les tableaux pouront sans doute vous aider. Quand vous serez convaincu de leur utilité il ne vous faudra pas longtemps pour les maîtriser.

Enfin, quand vous aurez franchi cette première étape, vous serez entré dans l’univers des tableaux qui recèle nombre d’autres possibilités très puissantes. Car les tableaux, c’est bien plus encore que ce que je vous présente ici.

Comme d’habitude, n’hésitez pas à poser toutes vos questions pour vous permettre de maitriser cette « brique » importante de la programmation et nous essayerons avec tous ceux qui connaissent ce sujet de vous répondre au plus vite et au mieux.

Et pour finir, je souhaite remercier l’un de nos sympathiques Locoduinistes qui a inspiré cet article (il se reconnaitra) et que je remercie pour le travail fait ensemble.

Beaucoup de plaisir avec vos trains et vos Arduino.

 

* Mise en garde concernant index et taille de tableaux :

Nous avons vu plus haut le cas d’un tableau contenant 16 éléments. Nous avons vu également que pour accéder au premier élément du tableau, nous devions appeler l’index 0 du tableau :

byte test = tableau[0];

Pour appeler la valeur du dernier élément du tableau, on devait donc écrire :
byte test = tableau[15]; // Qui a pour valeur 16

Ecrire ceci ne vous donnera tout au plus qu’une valeur incohérente car l’index 16 du tableau n’existe pas, mais le compilateur laissera faire, il ne vous signalera aucune erreur, aucun warning :

byte test = tableau[16];

Vous allez tout simplement lire la valeur contenue dans la case mémoire contigüe à tableau[15], ça peut-être rien, ça peut être quelque chose mais très probablement incohérent dans la logique de votre programme et cela risque de fausser son déroulement.

Plus grave, écrire ceci va effacer la valeur contenue dans la case mémoire contigüe à tableau[15], ça peut changer la cohérence de votre programme et croyez moi, vous risquez de chercher longtemps la cause :

tableau[16] = test;

Bon, tout au plus, sur un Arduino, vous risquez de changer une valeur par une autre non désirées. Vous pouvez aussi risquer le plantage. Mais par contre, dans un programme C/C++ exécuté sur un PC, si vous effacez des données de vos programmes ou de votre système, là ça fait très mal. Et "ctrl + Z" ne fonctionnera pas !

 

 

18 Messages

  • Ces tableaux qui peuvent nous simplifier le développement Arduino 29 octobre 2017 01:28, par Jean-Michel Bapt

    Bonjour,

    Il y a-t-il un avantage à déclarer une constante par l’intermédiaire d’un directive (« #define NBRE_AIGUILLAGE 16 ») plutôt que que par la méthode "habituelle" (« const byte nbre_aiguillages = 16 ; ») puisque dans les deux cas, il faut aller dans le programme pour modifier la valeur désirée (passer de 16 à 17 comme dans votre exemple) ?

    Par ailleurs, dans le programme exemple qui utilise la méthode "habituelle", il y a un bug potentiel car la constante déclarée en entête n’est pas utilisée dans la boucle void{} : la valeur est écrite "en dur" (« for (int i = 0 ; i < 16 ; i++) »)

    En tous cas, merci pour vos articles forts intéressants.

    Répondre

    •  

      Merci aussi pour vos questions fort intéressantes également.

      Il y a-t-il un avantage à déclarer une constante par l’intermédiaire d’un directive (« #define NBRE_AIGUILLAGE 16 ») plutôt que que par la méthode "habituelle" (« const byte nbre_aiguillages = 16 ; »)

      Utiliser les constantes de préprocesseurs #define est très utilisé en programmation C/C++. Regardez par exemple comment sont écrites les bibliothèques.

       

      Cependant, quand je lis la page du site Arduino, je constate qu’ils déconseillent l’utilisation de #define au profit de ce que vous appelez justement la méthode habituelle.

      https://www.arduino.cc/en/Reference...

       

      Jean-Luc avait écrit un petit article sur les constantes :
      http://www.locoduino.org/spip.php?a...
      où il mettait en garde sur le choix judicieux des noms pour éviter toute déconvenue. Il semble bien que ce soit pour cela que le site Arduino en déconseille l’usage.

       

      Personnellement, je trouve tellement pratique leur utilisation. J’utilise un nom en majuscule qui est une convention et qui me permet de les identifier rapidement dans le code.

      S’il y a au moins un avantage, c’est que je suis certain d’avoir bien déclaré une constante alors que je peux oublier le préfix const lors de la déclaration d’une variable qui devrait justement l’être en constante.

      Par ailleurs, dans le programme exemple qui utilise la méthode "habituelle", il y a un bug potentiel car la constante déclarée en entête n’est pas utilisée dans la boucle void : la valeur est écrite "en dur" (« for (int i = 0 ; i < 16 ; i++) »)

      Je ne pense pas qu’il y ait de bug potentiel en écrivant cela. J’ai déclaré et initialisé une variable en dehors de toute fonction (setup, loop ou autres) const byte nbre_aiguillages = 16;

       

      C’est donc une variable globale. Je l’utilise ensuite à la ligne du dessous et c’est tout. Ce n’est certes pas optimal en termes de programmation (ça se voulait être l’exemple à ne pas suivre) mais cela ne constitue en rien un bug potentiel.

       

      Bien amicalement,

      Christophe

      Répondre

      • Ces tableaux qui peuvent nous simplifier le développement Arduino 29 octobre 2017 10:29, par Jean-Michel Bapt

        Je suis d’accord avec vous, le mot "bug" est sans doute mal approprié, ce que je voulais dire est que cet "exemple à ne pas suivre" est représentatif du comportement inattendu possible d’un programme (je modifie une constante mais le résultat final ne change pas alors que ça devrait, c’est étrange...).
        Bien amicalement.
        Jean-Michel

        Répondre

  • je modifie une constante mais le résultat final ne change pas alors que ça devrait, c’est étrange…

    Oh là, je ne vous suis plus du tout. A aucun moment je n’ai essayé de "modifier" la valeur d’une variable déclarée et initalisée comme constante. D’ailleurs, le compilateur ne laisserait pas passer.

     

    Christophe

    Répondre

    • Bonjour

      Au nom de la communauté, merci pour ce très bon article à destination des débutants.


      Je peux essayer d’apporter un éclairage sur #define vs const :

      • #define permet de substituer un nom par une valeur partout dans le code, lors de la précompilation.
      • const tel qu’envisagé ici, est assez similaire : une variable globale déclarée en const n’occupe aucun espace en RAM. Le compilateur lui substitue sa valeur partout où elle est utilisée. Au final cela revient presque au même que #define, sauf qu’avec const la valeur est mieux définie car elle est typée. Le compilateur va vérifier qu’elle est bien utilisée conformément à son type, et générer une erreur si ce n’est pas le cas.

      A mon sens, #define ne devrait être utilisé que pour inclure/exclure des portions de code facultatives, typiquement un #define debug qui permet d’activer ou non des traces dans le programme.


      Enfin, la petite astuce que j’utilise souvent pour la taille des tableaux :

      int tableau = {1, 2, 3, 4, 5};
      const size_t NB_ELEMENTS = sizeof(tableau) / sizeof(int);

      NB_ELEMENTS est calculé par le compilateur, qui substitue ensuite la référence par sa valeur, partout où elle apparaît dans le code.
      Cela ne pèse donc rien dans le résultat compilé, et on peut ajouter un élément dans le tableau sans avoir aucune autre modif de code ailleurs ;-)

      Répondre

      • Merci aussi pour vos encouragements. Vous me semblez avoir des choses très intéressantes à partager également. Pourquoi ne pas vous aussi rédiger quelques contributions ???

         

        Au travers de l’exemple que vous apportez sur la taille des tableaux, je relève l’extraordinaire richesse des langages C et C++. Avec les quels tout je crois est possible mais l’est aussi souvent par plusieurs chemins différents. C’est ce qui le rend difficile à appréhender mais avec un peu de pratique, on peut "jouer avec" comme on joue avec des mots ou des concepts. L’objectif étant de trouver la réponse la plus efficiente. Il faut chercher à en comprendre les subtilités et ainsi les maitriser. Et merci au compilateur qui nous aide dans de nombreux cas à trouver nos erreurs.

         

        Bien amicalement
        Christophe

        Répondre

  •  

    J’ai fait un ajout dans l’article concernant les énumérations et les index de tableaux.

    Répondre

  • Bonjour,

    je cherche simplifier mon code pour gérer plusieurs sorties.

    je m’explique en écrivant mes sorties comme ça : int Sortie[] = {3, 4, 5, 6, 7}; j’aimerais pouvoir leurs donner l’info digitalWrite(Sortie [],HIGH); mais que l’info "HIGH" ou "LOW" de mes sorties soient gérée avec un tableau char allumage[8]{1,0,0,1,0,0,0,1};

    comme ça je pourrai réduire le nombre de ligne pour un chenillard à led

    J’espère que ce soit compréhensible.

    Merci de votre aide

    David Rey

    Répondre

  • Bonjour David,

     

    Attention tout d’abord, un tableau se déclare et s’initialise ainsi : int sortie[] = {3, 4, 5, 6, 7};. Essayez de ne pas mettre de majuscule à la première lettre de vos variables (Sortie) ce que l’on réserve par convention pour les distinguer des classes ou de structures par exemple.

     

    Pour activer (ou désactiver) toutes les broches facilement, vous pouvez en effet écrire une boucle :

     

    const int nbre_broches = 5;
    int sortie[nbre_broches] = {3, 4, 5, 6, 7};
    for (int i = 0; i < nbre_broches; i++) {
      pinMode(sortie[i], OUTPUT);
      digitalWrite(sortie[i], LOW);
    }

     

    Vous pouvez stocker l’état de vos broches comme vous le proposez dans un autre tableau byte allumage[5] ; (5 et non 8, autant d’état possible que de broches). Vous ajouterez alors :

     

    const int nbre_broches = 5;
    int sortie[nbre_broches] = {3, 4, 5, 6, 7};
    byte allumage[nbre_broches];
    
    void setup() {
      for (int i = 0; i < nbre_broches; i++) {
        pinMode(sortie[i], OUTPUT);
        digitalWrite(sortie[i], LOW);
        allumage[i] = 0;
      }
    }

     

    Si vous voulez accéder à l’état de la broche 6 par exemple, vous écrirez ceci : byte testEtatBroche = allumage[3]; (3 étant l’index de la broche 6). Par exemple :

     

    digitalWrite(sortie[3], HIGH);
    allumage[3] = 1;

     

    ou mieux :

     

    allumage[3] = 1;
    digitalWrite(sortie[3, allumage[3]);

     

    Mais vous pouvez, et c’est mieux, utiliser un tableau à 2 dimensions qui va contenir le numéro de la broche et son état comme ceci :

     

    const int nbre_broches = 5;
    int sortie[nbre_broches][2] = {{3, LOW}, {4, LOW}, {5, HIGH}, {6, LOW}, {7, HIGH}};

     

    L’utilisation se fera par exemple comme ceci :

     

    const int nbre_broches = 5;
    int sortie[nbre_broches][2] = {{3, LOW}, {4, LOW}, {5, HIGH}, {6, LOW}, {7, HIGH}};
    
    void setup() {
      for (int i = 0; i < nbre_broches; i++) {
        pinMode(sortie[i][0], OUTPUT);
        digitalWrite(sortie[i][0], sortie[i][1]);
      }
    }

     

    Mais vous parliez de chenillard, n’est pas quelque chose comme ceci que vous souhaitez ?

     

    const int nbre_broches = 5;
    const int nbre_etats = 8;
    
    int sortie[nbre_broches] = {3, 4, 5, 6, 7};
    byte allumage[nbre_etats] = {1, 0, 0, 1, 0, 0, 0, 1};
    
    void setup() {
      for (int i = 0; i < nbre_broches; i++) {
        pinMode(sortie[i], OUTPUT);
        digitalWrite(sortie[i], LOW);
      }
    }
    
    void loop() {
      for ( int i = 0; i < nbre_broches; i++) {
        for (int j = 0; j < nbre_etats; j++) {
          digitalWrite(sortie[i], allumage[j]);
          delay(100);
        }
      }
    }

     

    En espérant que cela vous aidera.

     

    Bien cordialement.

     

    Christophe

    Répondre

    • Analog 21 novembre 2019 07:43, par audouy laurent

      Bonjour,
      je ne vous vois pas utiliser de PIN analogique (A0, A..),

      chez moi ça donne pas grand chose,
      A0 = 14
      j’ai vérifié il semble que les PINs analogiques soient en fait les broches de 14 à 19 (UNO), du coup il faut une moulinette ou bien prendre l’habitude de déclarer les A par leur numéros cachés au grand public (pas cool pour partager du code)….

      Répondre

      • Analog 22 novembre 2019 08:32, par Jean-Luc

        Bon,

        Si vous aviez investigué un peu plus, vous auriez constaté que A0,A1, ... , An, sont des constantes numériques définies pour chaque Arduino. Pour le Uno par exemple, on trouve :

        #define PIN_A0   (14)
        #define PIN_A1   (15)
        #define PIN_A2   (16)
        #define PIN_A3   (17)
        #define PIN_A4   (18)
        #define PIN_A5   (19)
        #define PIN_A6   (20)
        #define PIN_A7   (21)
        
        static const uint8_t A0 = PIN_A0;
        static const uint8_t A1 = PIN_A1;
        static const uint8_t A2 = PIN_A2;
        static const uint8_t A3 = PIN_A3;
        static const uint8_t A4 = PIN_A4;
        static const uint8_t A5 = PIN_A5;
        static const uint8_t A6 = PIN_A6;
        static const uint8_t A7 = PIN_A7;

        Par conséquent, le code donné par bobyAndCo qui consiste à initialiser un tableau avec les pins pour le parcourir, ne nécessite aucun changement si ce n’est initialiser le tableau avec les pins qui vous intéresse, comme ceci par exemple :

        int sortie[nbre_broches] = {3, 4, 5, 6, A0, A1, A5};

        Répondre

        • Analog 22 novembre 2019 09:52, par audouy laurent

          harg, c’est ma faute j’ai oublié de préciser pour un retour en écriture dans le moniteur série, sinon j’avais bien remarqué que ça ne gênait en rien le code...
          rien d’insurmontable...
          merci pour votre réactivité et votre précision.
          laurent

          Répondre

  • Uhmm, uhmmm, je vous sens grincheux !

     

    Je propose des façons de faire qui peuvent obliger à (de petits) efforts intellectuels... ou peut-être simplement de la curiosité. Oui, pour des raisons qu’il est aisé de comprendre, j’utilise pour les broches une numérotation numérique sur laquelle il est aisé de faire des additions (i++) et non alphanumérique où c’est bien sûr plus compliqué.

     

    Vous cherchez : pin mapping arduino uno sur Google et vous trouvez immédiatement les équivalences.

     

    Maintenant, il est vrai que j’aurai aussi pu vous proposer d’utiliser des structures en C dans lesquelles on aurait pu entrer le nom A0, A1, An et son équivalent en numérique. Pas sûr que cela ait été plus compréhensible pour le plus grand nombre.

     

    Fort de votre remarque, je réfléchirai à deux fois maintenant avant de proposer quelque chose. Pour votre part, quel est le nombre de vos contributions sur Locoduino ?

    Répondre

  • Bonjour,

    Je cherchais justement quel était le problème avec A0,...
    Débutant avec les tableaux par envie d’être plus efficace.
    Merci pour votre travail et les réponses.
    Cordialement.

    Répondre

  • apprendre le langage arduino 28 janvier 2023 19:01, par salhi mohamed

    je voudrais avoir une liste exhaustive des codes codes Arduino et leurs fonctions.
    merci

    Répondre

  • développement Arduino 28 janvier 2023 19:04, par salhi mohamed

    liste exhaustive des codes du langage Arduino.
    merci.

    Répondre

  • Emuler touches clavier 5 décembre 2023 19:35, par ROCHE Benoit

    bonjour,
    j’utilise une matrice pour émuler des touches clavier pour PS5, sur 14 boutons je n’ai pas de souci car se n’est que des ctrl’lettre’ ou shift’lettre’
    mais pour le bouton 15 j’ai besoin de simuler un appuis long sur le ’s’, j’ai mis :
    Keyboard.press (’S’) ;
    delay(1000) ;
    Keyboard.release(’S’) ;
    delay(500) ;
    même en modifiant les temps, rien ne change.
    d’avance merci

    Répondre

  • Bonsoir,

    Je n’ai pas le sentiment que votre demande soit liée au modélisme ferroviaire qui est la raison d’être de Locoduino. Voir en bas de cette page.

    Quoi qu’il en soit, ce n’est pas non plus un problème de tableau, donc vous n’êtes pas dans la bonne rubrique. Et vous n’êtes pas non plus un lecteur très assidu du site car vous verriez que les delay() sont source de beaucoup de maux et je suis certaine que votre problème est là. Il faut leur préférer des solutions « non bloquantes » à base de millis(). Je vous montre l’exemple que j’avais sous la main que j’ai écrit hier et qui justement utilise un tableau :

    for ( uint8_t i = 1; i < tabIdSize; i++)
    {
       if (lastHeartbeatTime[i] > 0 && millis() - lastHeartbeatTime[i] > watchdogTimeout)
       {
         // Déclencher la procédure d'erreur pour i+1
         Serial.print("Aucun signe de vie pour le satellite ");
         Serial.println(i + 1);
       }
    }

    Si vous ne voyez pas du tout de quoi je parle, contactez moi par MP et envoyez moi votre code, SAUF s’il s’agit bien d’un projet ferroviaire, auquel cas il faut poster sur le forum pour que la communauté en profite.

    Bien cordialement

    Christophe

    Répondre

Réagissez à « Ces tableaux qui peuvent nous simplifier le développement Arduino »

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.

Lien hypertexte

(Si votre message se réfère à un article publié sur le Web, ou à une page fournissant plus d’informations, vous pouvez indiquer ci-après le titre de la page et son adresse.)

Rubrique « Programmation »

Les derniers articles

Les articles les plus lus