10) Le programme d’exploitation de l’appareil autonome version n°1.

Gnarf, gnarf, gnarf, cette broche binaire D11 qui n’est pas utilisée me titille les neurones. Je déteste payer du matériel et ne pas m’en servir. Aussi en réfléchissant un tantinet de plus, j’ai trouvé un moyen de l’utiliser. C’est encore « un petit plus » pour faire vendre auquel je n’avais pas pensé, car trop précipité à coder je n’ai pas respecté l’un de mes meilleurs conseil proposé en rouge dans la Page 15, la Page 18 et en bas de la Page 19. L’idée consiste comme sur la Fig.12 de la page 6 de câbler une diode électroluminescente sur D11, de couleur blanche par exemple. Cette dernière sera visible en face avant. Elle sera utilisée de deux façons. Si sur RESET on active le Mode_TEST, elle éclaire en permanence pour avertir l’opérateur que les données affichées ne sont pas les vraies. En fonctionnement standard, elle s’allume dès que le B.P. passe en Clic long avertissant l’opérateur que ce n’est plus la peine de persévérer. Encore une option qui aurait dû être pensée avant de commencer à programmer !

Puisque nous en sommes aux options, sachez qu’il existe dans le commerce des composants spécifiques tel que celui de la Fig.33 avec pour certain que j’ai déjà utilisé plusieurs couleurs comme sur notre rampe lumineuse. Bien qu’il puisse conduire à une version plus compacte, je ne l’ai pas envisagé pour plusieurs raisons. Il est conseillé de l’insérer dans un support de 10 broches de longueur qui n’est pas très courant et que l’on ne trouvera pas à l’unité. Il faut injecter 10mA par LED. Avec les 390Ω de la Fig.34 on arrive à environ 8mA, donc 80mA pour une rampe complète ce qui commence a faire beaucoup. (On peut raisonnablement descendre à 1kΩ pour un courant de 3mA qui maintien une luminosité suffisante.) Il faut mobiliser dix broches d’E/S au lieu de huit sans que ça apporte réellement grand chose. Et surtout, on perd l’aspect de visualisation « thermomètre » qui emporte ma préférence. Donc on en restera aux huit diodes indépendantes, libre à vous de tester une telle version si vous le désirez …

Paramétrer en tête de programme.

Dans le démonstrateur P06, par exemple dans la procédure Convertir_la_valeur_de_simulation() on doit modifier des grandeurs limites retournées par la CAN de la tension du potentiomètre de simulation. On retrouve relativement facilement cette procédure car elle est repérée par une remarque de type //@@@@@@@@@@@@@. Toutefois, quand on est amené à corriger de nombreux paramètres dans un listage bien plus « étalé » que celui du petit démonstrateur, 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 d’exploitation P07_Exploitation_pour_V1.ino les limites basse et haute des valeurs de la CAN du potentiomètre sont définies en tête de listage par des constantes MIN et MAX. Du reste, comme on peut l’observer sur la Fig.35 on a regroupé

quatre paramètres sous forme de déclarations #define et la valeur Etalonnage sous forme d’une constante de type float que l’on initialise à 1. D’une façon générale, un #define affecte à l’identificateur un type correspondant à la valeur mentionnée. Par exemple VERSION génère une chaîne de caractère. Mais on peut aussi imposer un type qui ici précise que c’est un réel et non un entier.

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 immobilise 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.36 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. Le principe du chronométrage en partie explicité en Page 11 est repris sur la Fig.36 sur laquelle on va prendre en compte deux chronométrages. 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 surveiller en permanence la valeur de millis. Dès que [millisTop_1] sera égal ou plus grand 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 et 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 [millisTop_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 que le B.P. est cliqué, le « petit cÅ“ur » de la boucle de base cesse de battre. (Le pauvre ! ! !)
Autre façon de créer un chronométrage : Utilisation d’un compteur qui ici est nommé Horloge_chauffage, listé sur la Fig.37 qui est ici initialisé à zéro lors de la mise sous tension ou lors d’un RESET. Dans la boucle de base Faire_battre_le_coeur_du_programme() est invoquée très rapidement et déclenche les actions de la séquence 2 pratiquement une fois par seconde. C’est en 1 que l’on retrouve le chronométrage pour cette temporisation. Le compteur est incrémenté en 3 dans la zone jaune tant qu’il n’arrivera pas à la valeur de 14400 pour mesurer la durée de quatre heures. Ensuite, en 3 il ne sera plus modifié jusqu’à un autre RESET. Arrivé à cette valeur critique de calibration, la comparaison de la zone rose devient positive et son action sera déclenchée une fois par seconde. L’instruction Rapide = false dans la

zone 4 a pour effet de ne plus faire clignoter rapidement la LED Arduino dans la boucle de base. Une seule fois serait suffisante, toutefois la réitérer à l’infini est sans inconvénient, alors inutile de compliquer le programme avec un booléen supplémentaire. En revanche, dans la zone 4 l’instruction Inverser_LED_Arduino() est maintenant invoquée à chaque « battement de cÅ“ur » dans la boucle de base void loop().
RÉSUMÉ : Pour réaliser un chronométrage on peut à convenance :
• Utiliser l’instruction delay() qui mobilise le microcontrôleur durant tout le chronométrage,
• Utiliser la fonction millis qui permet de créer des chronomètres indépendants,
• De créer un chronométrage géré par le programmeur au moyen d’un simple compteur.
(On peut aussi faire par « interruptions », mais c’est un autre sujet !)

Auto vérification du matériel.

Encore un comportement du programme que l’on aurait été capable de prévoir si les études préliminaires n’avaient pas été bâclées. Ceci dit, ne soyons pas médisants par principe, ou « des ayatollahs » de la programmation. Quel que soit le projet, c’est forcément durant le développement que l’expérimentation fera émerger des idées nouvelles car confrontés aux manipulations effectives on découvrira des faiblesses ou des améliorations possibles. Un retour en arrière sur le démonstrateur P02 avait montré que le logiciel pouvait générer deux alertes :
• ALERTE 1 : Temps d’attente dépassé.
• ALERTE 2 : Erreur de checksum.
Le logiciel d’exploitation P07 quand à lui peut déclencher deux autres types d’erreurs :
• ALERTE 3 : Mesure incohérente. (PPM dépasse la valeur de 4000.)
• ALERTE 4 : Mesure = 0 ! (Le capteur MQ135 est non alimenté …)
Comme toujours, il faut décider du comportement qui sera émulé dans le logiciel d’exploitation. Parmi l’infinité des solutions possible, par paresse j’ai opté pour l’une des plus simple à coder, mais qui philosophiquement est la moins élégante car non seulement elle fait appel à un goto, et de surcroit cette instruction à bannir au maximum sert à créer des boucles infinies dans lesquelles on enferme le microcontrôleur. Pourquoi la mettre au banc de la société C++ ? Car utilisée à mauvais escient elle rend incapable le programmeur de savoir ce qu’à fait son programme et le cheminement qu’il à suivi dans les instructions … donc « impossible » à mettre au point. Pour s’en rendre compte, considérons l’organigramme de la Fig.38 dans lequel les …….. représentent des lignes d’instructions. Lorsque le programme « tourne », scrachhhhh : Se produit durant l’Action 3 un problème. Ce dernier peut naturellement avoir sa source durant Action 3. Cependant il peut aussi avoir été généré par tout ce qui précède. Hors on suppose que l’incident n’est arrivé qu’après avoir introduit la séquence de la Fig.38, c’est dans cette dernière qu’il faut rechercher la vermine. Pour la trouver il faut savoir par où est passé le traitement et les hypothèses sont multiples. En voici la liste :
• Début > Action 2 > Action 3 > Scratchhhhh
• Début > Action 1 > Action 3 > Scratchhhhh
• Début > début Action 1 > goto ICI > fin Action 2 > Action 3 > Scratchhhhh
Pour trouver l’erreur, il va falloir faire du traçage, c’est à dire d’introduire dans le code une palanquée d’instructions qui précisent où se trouve le programme. Si de plus les divers « chemins » sont parcourus un grand nombre de fois … je vous souhaite bien du plaisir !

Conclusion : L’instruction goto ne doit être utilisée que dans des cas très particuliers.

Tournicoter à l’infini.

Résumé sur l’organigramme de la Fig.39 le comportement du programme lorsqu’il détecte un problème matériel est facile à décrire. Il commence par afficher la nature de l’erreur sur la ligne USB du Moniteur. Jusqu’à ce stade l’écran vidéo affichait les valeurs mesurées qui défilaient verticalement. À partir d’ici, le programme est définitivement enfermé dans la boucle tracée en rouge sur l’organigramme. Le défilement sur l’écran vidéo est définitivement figé sur le texte d’alerte. La carte Arduino NANO génère alors un BIP sonore par seconde jusqu’à intervention de l’opérateur. Ce comportement n’est toutefois pas suffisant, car sur la machine autonome l’opérateur sait qu’il y a un problème matériel, sauf qu’il ne peut pas savoir lequel puisqu’il n’y a plus l’écran de l’ordinateur pour en lire la nature. Il faut donc ajouter un artifice spécifique.

Justification : Bien que l’introduction de petites boucles infinies dans les programmes soit d’un usage peu fréquent, je plaide ici « non coupable ». Il peut arriver que ce soit parfaitement justifié. L’exemple typique, c’est pour void loop() impérative car un microcontrôleur ne peut pas être arrêté. (Il peut se voir imposer le mode sommeil, qui n’est que provisoire.) Une technique bien connue pour faire une boucle infinie consiste à coder une condition définitive :

while (true) {Ici les instructions de la boucle infinie;}
Je trouve que c’est bien plus lisible d’utiliser :
INFINI: Ici les instructions de la boucle infinie; goto INFINI

Si vous recherchez la boucle en question, il suffit de proposer « infini » à [Trouver…] alors que dans l’écriture banale l’analyse va passer par tous les while du programme.

Préciser la source du problème matériel détecté.

Plusieurs options sont envisageables. Par exemple utiliser la rampe lumineuse : ALERTE_1 : Deux bleues, ALERTE_2 : Deux verts, ALERTE_3 : Deux jaunes, ALERTE_4 : Deux rouges. À mon sens c’est une approche visuelle tout à fait opérationnelle. Je vous laisse la tester, c’est celle par défaut. Pour ce logiciel d’exploitation on va aussi expérimenter une deuxième possibilité pour bien montrer qu’à chaque facette d’un projet on peut trouver des solutions différentes. Donc dans ce programme

le parti-pris consiste à utiliser la rampe lumineuse, toutefois en changeant la valeur d’un booléen on pourra aussi tester avec la LED tricolore, le tableau de la Fig.40 explicite les combinaisons adoptées. Sans modification du logiciel, c’est la Rampe lumineuse qui traduira la nature du problème matériel rencontré. En modifiant la ligne d’option :

on aura un fonctionnement avec précision de la source du problème avec la LED triple ou sur les trois LEDs blanches indépendantes.

Rapidité de « rotation » de la boucle de base.

Dans les nombreux conseils prodigués péremptoirement dans ce didacticiel, il est précisé que l’on doit mesurer la rapidité d’exécution void loop() pour vérifier que le taux d’affichage est important, (Ce qui ici est sans importance, mais s’il s’agit d’un écran graphique « animé » c’est plus justifié.) que le délai de prise en compte des potentiomètres, B.P. et autres périphériques de type clavier est faible. Bref, que le dispositif soit 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.
Avec un Fréquencemètre très précis on obtient : 1742Hz. La prise en compte du bouton poussoir sera donc très rapide dans ce skech d’exploitation.

Chaque version de ce petit projet est accompagnée d’une fiche à imprimer et à plastifier pour en décrire le comportement, sorte de notice d’utilisation condensée.

La suite est ici.