C‘est dans la boucle de base void loop() que généralement on traite l’interface Homme/Machine et l’on souhaite que si l’opérateur frappe une commande, que cette dernière soit le plus rapidement possible prise en compte. On va supposer ici que c’est le cas même s’il n’y a pas encore de dialogue installé. C’est du reste pour contrôler le fonctionnement de cette boucle infinie que souvent je fais clignoter rapidement la LED Arduino en D13. Si le programme s’enlise dans une séquence « infinie », la LED ne clignote plus et le programmeur en est alors averti optiquement.
Des chronomètres à gogo.
Chaque usage de la fonction millis permet de créer un chronomètre indépendant qui ne bloque pas le déroulement du programme dans un delay() qui immobiliserait le microcontrôleur, et on peut en créer à volonté. Toutefois, chaque chronomètre devra se servir d’un « Top chrono » qui lui est propre. La Fig.24 présente un exemple avec deux chronomètres indépendants. Lorsque le microcontrôleur est mis sous tension ou lors d’un RESET, un compteur interne démarre à zéro et se voit incrémenté mille fois par seconde. (Il contient la durée écoulée en mS.) À tout moment millis peut en lire la valeur est la retourner sous forme d’un unsigned long en sortie de cette fonction. Pour mesurer l’intervalle de temps T1 la valeur retournée par millis est enregistrée dans Top_1. Puis dans le programme le chronomètre A va lire en permanence la valeur de millis. Dès que la valeur de [millis – Top_1] sera égale ou plus grande que la valeur désirée T1 c’est que la durée calibrée sera atteinte et l’on déclenchera l’action pour A, puis immédiatement Top_1 sera rechargé avec millis pour démarrer un nouveau chronométrage. Pour réaliser un deuxième chronomètre B afin de mesurer une temporisation T2 il suffit de dupliquer cette séquence, avec comme origine de chronométrage une mémoire TOP_2 et effectuer la comparaison [millis – Top_2]. On peut ainsi en créer autant que nécessaire. Ces séquences peuvent se situer n’importe où dans le programme avec des durées T1 et T2 quelconques. Noter que la durée de la temporisation ne sera pas strictement égale à celle calibrée, car il faut tenir compte du fait que l’écart de temps étant arrivé, le programme peut être occupé ailleurs. (Par exemple tant qu’un B.P. est cliqué …)
Analyse du chronométrage pour les LEDs.
Exemple typique d’un chronométrage sans pénalité pour la rapidité du logiciel, la Fig.25 présente le listage de la séquence qui gère les LEDs dans le démonstrateur P01 et qui est invoquée à chaque cycle de la boucle de base infinie void Loop. C’est dans la zone 1 coloriée en rose pastel que sont effectués les tests pour le chronométrage n°1. Cette comparaison est très rapide et la sortie est immédiate tant que la durée attendue n’est pas atteinte. Puis, dès que l’on dépasse la temporisation consignée dans la valeur mise en évidence en jaune, on déclenche toutes les actions de la zone vert pastel 3. La première action urgente pour obtenir un chronométrage précis, est en 2 le Top_1 de la Fig.24 et dans notre cas il y besoin de mémoriser cette valeur puisqu’il y a deux chronométrages à gérer. Généralement les actions 3 n’exigent que peu de cycles microcontrôleur et ensuite la boucle de base reprend sa routine de fond généralement à un rythme élevé. De façon totalement analogue on effectue dans la zone rose pastel 4 le chronométrage pour le clignotement rapide. Puis, dès que l’on dépasse la temporisation ici donnée en constante dans la zone jaune, on déclenche toutes les actions de la zone vert pastel 6. Immédiatement c’est en 5 que le Top_2 est mémorisé. Noter que pour le délai de la LED bleue la valeur est paramétrée en tête de programme et facile à modifier.
Paramétrer en tête de programme.
Dans le démonstrateur P01, par exemple dans la procédure void setup() on doit modifier la date de validation du logiciel en question, ou dans ce même programme modifier la rapidité de la manipulation Morse virtuelle, ou encore la cadence de la transmission des données sur la ligne USB. Tout au long du développement d’un logiciel il peut y avoir besoin de modifier parfois des constantes ou de nombreux paramètres et on doit pouvoir facilement repérer les lignes d’instruction concernées. Il suffit de les faire terminer par des remarque de type //@@@@@@@@@@@@@. Toutefois, quand on est amené à corriger des valeurs dans un listage bien plus « étalé » que celui du démonstrateur P01, il est fortement recommandé de définir tous les paramètres d’initialisation en tête de programme et si possible de les regrouper.
Ainsi, on a une énumération compacte et l’on ne risque pas d’en oublier, et surtout c’est bien plus rapide que d’avoir à chercher de multiples emplacements dans un long listage. Cette façon de faire concerne directement la « programmation avec méthode ». Aussi, dans le programme de développement P01_Tester_le_materiel.ino la date de version est définie en tête de listage par la constantes Version et le taux de transfert sur la ligne de dialogue USB est défini par la constante Vitesse_USB. Du reste, comme on peut l’observer sur la Fig.26 on a regroupé quatre paramètres sous forme de déclarations #define. Dans ces dernière il est possible de définir des chaînes de caractères, des entiers, des réels, des booléens etc. Par exemple la valeur false pour Rapide engendrera une cadence lente pour la manipulation Morse virtuelle. Je vous invite à la remplacer par true pour voir la différence et remplacer le 500 par 1000 par exemple pour voir la différence.
Rapidité de « rotation » de la boucle de base.
Dans les nombreux conseils prodigués péremptoirement dans ce didacticiel, il me semble important de préciser que l’on doit mesurer la rapidité d’exécution void loop() pour vérifier que la cadence de prise en compte des consignes opérateur soit élevée, donc vérifier que le dispositif est réactif. Seule limite, il faut disposer d’un fréquencemètre. Pour ceux qui le désirent, sur https://www.robot-maker.com/ouvrages/apprendre-a-programmer-arduino-en-samusant/ est décrit ce type d’appareil réalisé avec une carte Arduino.
On obtient pour le démonstrateur P01 une période de 102mS soit une fréquence de 9,79 Hz. La prise en compte des consignes arrivant sur la ligne USB sera donc rapide.
Un bilan de consommation des ressources.
Compilant P01 on constate que le « Sketch » se goinfre déjà de 3128 Octets de l’espace réservé au programme soit 10% de ce dernier alors que l’on n’a encore écrit aucune routine destinée à ÉNIGMA. Nous sommes en droit de nous inquiéter et d’envisager l’impossibilité d’aboutir dans ce projet par manque de place pour le programme alors que pour ce petit démonstrateur le code a été optimisé. Pas de panique ! Une longue expérience en programmation C++ sur Arduino a montré que dans tous les programmes, les premières séquences sont boulimiques. Mais plus les subroutines installées augmentent, plus l’inflation diminue, car le compilateur ensuite se contente d’invoquer les séquences installées. Par exemple dans notre démonstrateur la simple utilisation de la ligne série engloutit à elle seule environ 272 octets uniquement pour Serial.println(); Ensuite, les autres affichages deviennent bien moins gourmands. Par ailleurs, les textes sont considérés comme des tableaux et prennent beaucoup de place à la fois dans la zone réservée au programme et empiètent de façon équivalente dans la zone réservée à la mémoire dynamique. Un moyen particulièrement efficace consiste à loger les textes du dialogue en mémoire non volatile EEPROM. Aussi, et même si ce n’est pas indispensable, quand le moment sera venu on ne va pas s’en priver, y compris si ce n’est pas utile. (« Le moment sera venu » quand le logiciel contiendra suffisamment de textes pour que ce soit rentable.) Par ailleurs on a déjà mis en place les séquences qui génèrent du code morse, et elles vont certainement être intégrées dans le programme final d’exploitation du petit boitier bleu. Bref, on peut rester sereins et ne pas faire preuve de pessimisme et ce d’autant plus qu’actuellement les démonstrateurs sont compilés avec la version 1.7.9 de l’IDE. Hors la version 1.8 du compilateur est plus optimisée et le code qu’elle génère est bien moins volumineux. Donc si nécessaire on terminera notre cheminement avec cette version du compilateur de l’IDE. (Personnellement je préfère la version 1.7.9, mais pour des raisons « futiles !)
Pour montrer de façon visuelle la progression de la taille du programme par rapport aux ressources disponibles, j’aime bien la représenter sous la forme d’un thermomètre avec en rouge le pourcetage actuellement occupé et en vert la place encore disponible. Chaque fois qu’une « fonction spécifique » aura été développée et validée, je reprendrais cet artifice visuel pour monter l’évolution du programme d’utilisation de notre Énigma virtuelle.
La suite est ici.