Passé totalement inaperçu, l’avènement de l’électroluminescence a constitué une révolution qui a envahi l’intégralité de nos environnements. Omniprésente, on peut presque affirmer que plus un seul dispositif n’échappe à l’emprise de l’électroluminescence, cette technologie ayant presque totalement supplanté celle des cristaux liquides. Commencer notre promenade par la mise en œuvre de diodes électroluminescentes, alias les LEDs, est pratiquement incontournable vu la facilité de leur emploi et le prix de vente devenu dérisoire de ces composants. Deux approches sont envisageables :
• Faire appel à un petit module du commerce directement exploitable.
• Réaliser un petit montage personnel sur une platine de prototypage.
On se doute que les deux approches seront abordées tout au long de notre promenade.
Expérience 001 : Pilotage binaire d’une LED.
Application strictement inéluctable, commençons par assimiler les informations de la Fiche n°9 de laquelle nous allons extraire le schéma de la Fig.1 D et le concrétiser comme visible sur la Fig.1 avec des composants discrets sur une platine d’essais. Comme le courant qui transite dans une ligne électrique où les éléments sont mis en série est indépendant de l’ordre dans lequel ils se trouvent, on peut librement les insérer à notre guise. On choisit par exemple le montage typique de la Fig.2 A que j’adopte généralement « par souci de standardisation ». Toutefois j’inverse sans hésiter l’ordre de R et de L comme en B si ça facilite la réalisation d’un circuit imprimé par exemple. Dans cette expérience on peut utiliser indifféremment n’importe laquelle des 14 broches D0 à D13. Toutefois, on va exclure D0 et D1 qui sont respectivement réservées à RX et TX du dialogue série avec le Moniteur de L’IDE et les téléversements des programmes. La Fig.3 résume le fonctionnement attendu de notre programme Experience_001.ino préservé dans le dossier dédié <Les programmes Arduino> accompagnant ce didacticiel. Les conventions personnelles relatives à l’utilisation des organigrammes normalisés sont précisées sur la Fiche n°11. L’observation de la Fig.3 ressemble à l’évidence à la fig.1 de la Fiche n°12 et l’on peut affirmer haut et fort que nous avons ici à faire à un automatisme aveugle. Considérons le fonctionnement de la procédure Temporiser_une_demi_seconde() qui est particulière :
void Temporiser_une_demi_seconde() {Delai = 0; while (Delai < 660589) Delai++;}
Dans cet exemple, résumé sur la Fig.4, pour cantonner le microcontrôleur dans la procédure pendant une demi-seconde, on l’oblige à faire 660589 fois Delai = Delai + 1 et après chaque addition regarder si la valeur de Delai est arrivé à 660589. On en déduit que l’une des méthodes classique pour imposer une pause à l’ATmega328 consiste à lui imposer une boucle répétée un grand nombre de fois. On peut évaluer ici que pour effectuer les instructions de la boucle le microprocesseur ne met que 0.5 / 660589 seconde soit environ 0,7µS. C’est qu’il est très rapide et cadencé en standard à 16MHz. (Certains clones chinois ne « tournent » qu’à 12MHz.) La technique pour calibrer la valeur du test est précisée dans Experience_001.ino. Toutefois, générer une temporisation précise est à la fois très fréquent en microinformatique, mais tout le monde ne dispose pas d’un périodemètre précis pour effectuer la détermination de la valeur de sortie de la boucle. Aussi l’instruction delay() et sa sœur delayMicroseconds() ont été développées dans ce but en langage C++.
Un programme qui ne fait absolument RIEN !
Ouvrons une petite parenthèse avant de passer à l’exercice suivant. Si vous consultez le listage d’Experience_001.ino vous constaterez que le skech consomme déjà 2% de l’espace réservé au programme. On peut s’en étonner vu que ce programme ne fait pas grand chose. Dans la pratique on constate que les premières lignes de code présentent une boulimie d’espace mémoire consommé. C’est normal, car chaque instruction amène en mémoire le code objet pour la réaliser. Puis, plus le programme gagne en consistance, et moins les lignes d’instruction n’ajoutent de séquences binaires. Elles se contentent de faire appel aux procédures déjà installées. Alors il ne faut pas s’inquiéter de la taille du programme en début de développement alors que l’on n’a encore soumis que très peu de lignes de programme par rapport à ce qui sera nécessaire pour le logiciel final. Listé sur les deux lignes de la fenêtre contextuelle de l’IDE en Fig.5 on peut observer le plus court programme accepté par le compilateur C++ d’Arduino. Il traite les instructions de void setup() … qui est vide. Puis, il va boucler sans fin sur void loop() qui ne fait rien du tout. Et pourtant avec la version 1.7.9 du compilateur le programme consomme déjà 450 Octets et loge 9 Octets en mémoire dynamique. Il ne faut pas perdre de vue que pour pouvoir gérer un programme aussi élémentaire qu’il soit, un noyau de base doit être disponible pour assurer le fonctionnement de la PILE, celui du TAS, la prise en compte des éventuelles interruptions etc. Bref, tout un contexte est implanté en mémoire et forcément consomme de la place.
Expérience 002 : Clignotement de deux LEDs à une cadence très précise.
Rien à modifier au schéma de la Fig.2 sauf si vous désirez vous convaincre que de permuter deux éléments agencés en série ne modifie pas le comportement électrique de la ligne. Dans ce cas on passe au schéma de la Fig.6 sur lequel on a permuté l’ordre de R et de L par rapport aux deux branches qui étaient conformes à « mon standard » A. Histoire de vérifier que toutes les sorties binaires présentent des comportements analogues, cette fois on utilise D4 et D5 pour le programme Experience_002.ino qui reste un automatisme aveugle. L’organigramme de la Fig.3 reste valide, sauf si on introduit directement et deux fois l’instruction delay() dans la boucle void loop() ce qui est le cas dans le démonstrateur. On peut noter au passage que la période n’est pas absolument d’une seconde, car il faut du temps pour allumer et éteindre les LEDs et effectuer le retour au début de la boucle de base. Nous verrons avec le démonstrateur suivant Experience_003.ino comment calibrer la durée d’une séquence avec un maximum de précision si le programme l’exige.
Expérience 003 : Calibrer avec grande précision la durée d’une séquence.
À partir du moment où l’on s’impose de travailler avec exactitude, il faut impérativement s’entourer des appareils de mesures qui sont aptes à assurer la précision désirée. La précision de l’horloge d’Arduino, et par voie de conséquences de ses instruction de gestion du temps, est déjà très bonne puisque calibrée par un oscillateur à quartz. Toutefois, ce dernier a forcément une certaine imprécision. Par ailleurs, cette fréquence dérive légèrement en fonction de la température d’équilibre atteinte dans le coffret intégrant l’application. Aussi, avant de procéder à du calibrage il faut attendre l’équilibre thermique dans l’appareil contenant Arduino. Comme il n’est pas question ici de modifier quoi que ce soit d’électronique dans notre montage, on va corriger l’imprécision constatée dans Experience_002.ino par programme, c’est à dire peaufiner le code qui génère les temporisations dans void loop(). Avec le démonstrateur P002 on mesure la durée de l’impulsion à l’état « 1 » et celle à l’état « 0 » sur l’une des deux sorties. Dans les deux cas on trouve 0.499785S à plus ou moins une unité, comme pour tout appareil de mesure numérique. Quand on commute l’appareil de mesure utilisé sur la fonction Périodemètre, il affiche la valeur présentée sur la photographie de la Fig.7 mesure affectée d’une fluctuation normale de ± 1 µS.
On peut alors affirmer que la temporisation pour chaque état est trop faible de 1.000000 – 999571 divisée par deux soit 0.000429S / 2 qui donne 215µS. On ajoute donc à delay(500) un complément calculé delayMicroseconds(215) qui doit logiquement aboutir à la temporisation désirée. Avec cette nouvelle approche dans P003 on aboutit au résultat de la Fig.8 qui n’est pas si mal que ça.
Si l’on voulait « pinailler », il suffirait de diminuer de 2µS les deux instructions de calibrage et passer à 213 la valeur du paramètre. Toutefois, avant d’envisager une telle action il faudrait qu’Arduino soit enfermé dans un coffret et patienter au moins une heure de fonctionnement pour atteindre l’équilibre thermique. Enfin, si vraiment l’application exige une précision dépassant le 10-6 une horloge externe thermostatée et compensée en température (TCXO) serait alors nécessaire … c’est une autre manche et l’on sort un peu du domaine ludique.
Expérience 004 : Bloquer le déroulement d’un programme.
C’est le cas particulier où j’utilise l’instruction « interdite » goto. (Voir impérativement les Fiches n°13 et n°14.) On envisage d’utiliser une LED triple et d’en allumer en séquence les trois couleurs fondamentales. Il s’agit encore d’un automatisme av
eugle. Comme les trois composantes n’ont pas le même rendement, il faut affecter pour chaque couleur une valeur de résistance conduisant à une luminosité homogène. Le schéma de la Fig.9 propose un montage utilisant des composants discrets (A de la Fig.10) réunis sur une platine d’essai. Naturellement on peut utiliser un petit module du commerce comme celui photographié en B, n’ayant de ce cas pas à déterminer la valeur idoine pour les résistances de limitation du courant dans les diodes. Pour cette Experience_004.ino on suppose que dans le déroulement de la boucle de base void loop() le comportement pour le Rouge et le Bleu n’est pas celui prévu, et que l’on soupçonne une erreur dans les initialisations de void setup(). Sous cette hypothèse on décide de bloquer le programme immédiatement après qu’il se soit occupé des deux composantes Rouge et Bleue. Dans cette optique on « immobilise » le logiciel dans une boucle infinie en ligne 22. Dès le téléversement et l’activation du code objet la LED triple allume les deux composantes, prouvant que l’initialisation des deux broches de sortie D6 et D8 est correcte. Il serait alors certain que le problème se cache dans la boucle de base, et on envisagerait alors d’autres hypothèses et d’autres vérifications pour trouver l’origine du problème. Notons en passant que Rouge plus Bleu aboutit à une lumière de couleur violette. Dans la pratique, en fonction des composantes excitées et de l’intensité qui les traverse on peut obtenir en théorie n’importe quelle couleur. Si les trois broches sont à intensités égales on obtient du blanc … qui n’est pas une couleur ! Pour terminer cet exercice, je vous propose de passer en remarque la ligne 22 et de téléverser à nouveau le sketch qui cette fois fonctionnera correctement. Les lignes 20, 21 et 23 sont alors inutiles.
Expérience 005 : Variation du rapport cyclique.
Notion incontournable lorsque l’on va pratiquer le MULTIPLEXAGE, l’influence du rapport cyclique sur un effecteur qu’il soit lumineux, thermique ou de toute autre nature, est fondamentale. Pour appréhender en douceur ce chapitre particulier de l’électronique, consultez avec attention la Fiche n°10 qui traite un peu de ce sujet appliqué à l’éclairage des LEDs. Le schéma électrique à brancher pour Experience_005.ino montré sur la Fig.11 se résume à peu de chose. Nous allons utiliser dans cet exemple une particularité de certaines broches de sorties binaires résumée en page 25 du petit livret SYNTAXE à imprimer.pdf. Comme la LED rouge utilisée présente un très bon rendement, sa résistance de limitation de courant a été augmentée à 10kΩ. Même dans ces conditions, alimentée à plus que un cinquième du temps on ne distingue plus vraiment l’augmentation de luminosité raison pour laquelle le rapport cyclique ne va pas jusqu’à 1, valeur qui serait obtenue pour Rapport = 254. Conformément aux informations contenues dans le livret, pour D5 la fréquence de répétition de la PWM est de 976 Hz ce que confirme sur la Fig.12 la photographie d’une partie d’un petit oscilloscope effectuée lorsque le rapport cyclique était à 0.184 c’est à dire presque à son maximum. Comme la fréquence de répétition dépasse largement les 20Hz nous avons une impression de lumière constante, le découpage binaire de l’énergie n’est pas détectable.
Expérience 006 : Rapport cyclique 0,5 et fréquence variable.
C’est pour montrer qu’à partir d’une certaine fréquence le découpage d’un signal de type PWM n’est plus discernable que l’on adopte dans cet exercice un rapport cyclique constant de un demi. La LED recevra en permanence un courant moyen égal à celui d’une tension constante de 5V divisée par deux. On conserve le schéma de la Fig.11 pour se simplifier la vie. Il suffit de téléverser le démonstrateur Experience_006.ino qui éclaire la LED en changeant de fréquence toutes les deux secondes. Les fréquences générées sont respectivement de 10Hz, 20Hz, 30Hz, 40Hz, 50Hz, et 500Hz. Les valeurs en rouge dans cette liste sont celles où le clignotement est discernable. À partir de 40Hz l’éclairement semble constant et on ne perçoit plus le « découpage » … sauf si on prend en mai la LED ou la platine et qu’on la déplace alternativement et rapidement en translation. Dans ce cas, si la fréquence de répétition n’est pas trop élevée, on distingue nettement un tracé lumineux en pointillés. Ce phénomène facilement observable est typique des systèmes MULTIPLEXÉS dont le balayage des afficheurs se fait à une cadence pas trop élevée. Nous y reviendrons. Notez que jusqu’à 50Hz dans la boucle for la valeur la plus grande restant inférieure à 255 on peut pour l’indice I utiliser un byte. Pour la fréquence de 500Hz il faut effectuer 1000 itérations, du coup l’indice I pour le comptage dépassant 255il faut impérativement passer à un entier int.
Expérience 007 : Le coup du lièvre.
Mentionné dans la Fiche n°12 le lièvre est un long dispositif de lampes alignées au centre d’une piste d’atterrissage des avions de ligne pour mettre en évidence l’entrée de la piste en service. Sur la Fig.13 le balisage est relatif à un aéroport important. Pour des installations plus simples le lièvre devient une simple ligne dans l’axe de la piste avec l’allumage rapide d’une seule ampoule à la fois. On a l’impression d’un spot lumineux qui se déplace à toute vitesse dans la direction et le sens avec lequel l’avion doit se poser. Nous allons matérialiser ce type de dispositif lumineux avec par exemple huit LEDs pilotées dans l’ordre par D3 à D10. Comme une seule sera illuminée à la fois, on peut adopter le schéma de la Fig.14 montrant un agencement à cathode commune et une seule résistance de limitation de courant. Naturellement on peut adopter des LEDs de couleur quelconque, mais toutes issues d’un lot commun pour présenter des rendements identiques. Le « déplacement lumineux » est relativement rapide sur ce type d’installation.
NOTE : La temporisation est placée en procédure. Il aurait été possible de ne pas créer cette dernière et remplacer chacun de ses appels par delay(70) dans void loop(). Cette approche présenterait deux inconvénients majeurs :
• Le code objet présenterait 52 octets de plus,
• Si l’on veut changer la rapidité du lièvre il faudrait modifier huit paramètres au lieu
d’un seul. (Chaque fois qu’une séquence doit être dupliquée, tester son remplacement
par une procédure et plusieurs appels pour choisir la meilleure solution.)
Expérience 008 : Une erreur intentionnelle dans le programme.
C’est bien parce-que je sais qu’il n’y aura pas de conséquence pour le matériel que j’ouvre cette parenthèse qui vise à démontrer au passage que si plusieurs sorties doivent simultanément passer à l’état « 1 » la cathode commune n’est plus potentiellement utilisable. Que va t’il se passer si le programmeur se trompe et que plusieurs sorties passent à l’état travail ? On va avec Experience_008.ino tester le pire des cas à savoir : Les huit sorties passent à « 1 » et y restent. On pourrait penser que chaque sortie D3 à D10 fournissant du +5V le courant circulant dans R adoptée à 1kΩ serait huit fois plus important. Et bien ce n’est pas du tout ce qui se passe. Pour que cet exercice soit valide et fiable, j’ai utilisé un lot de huit LEDs parfaitement identiques. Le tableau de la Fig.15 précise la valeur de la tension aux bornes des LEDs et de R en fonction du nombre Nb qui sont allumées, sachant que +Vcc = 4,9V constant valeur que l’on retrouve sur toutes les sorties à l’état « 1 ».
Explications : Lorsqu’une seule LED est alimentée, on trouve à ses bornes une tension qui est directement fonction de sa couleur et du courant limité par R qui la traverse. Contrairement à ce qui vient à l’esprit, le courant ITOTAL ne peut pas être proportionnel aux nombres de sorties à l’état « 1 » et ce pour une raison simple. La tension aux bornes des LEDs ΔULED correspond à leur « seuil de conduction » varie relativement peu comme pour une diode Zener par exemple. Du coup la tension aux bornes de la résistance R va ressembler à 4,9V – 3,1V et le courant ITOTAL traversant la résistance de 1kΩ avoisine une valeur de 2,7mA qui varie relativement peu en fonction du nombre de LEDs qui sont allumées.
Étudions un peu plus précisément le comportement élémentaire de l’une des diodes électroluminescente. Il n’y a pas de miracle. En supposant que toutes les LEDs présentent des caractéristiques strictement identiques, elles vont devoir se « partager » le courant ITOTAL à parts égales. Comme ce courant varie relativement peu, on en déduit que plus il y a de LEDs allumées, moins grande sera la « part » pour chacune. C’est bien ce que l’on constate dans la colonne mise en évidence en rose dans le tableau de la Fig.15. Observons le graphe de la Fig.16 qui traduit pour la LED1 la variation d’intensité qui la traverse et qui correspond à la part pour toutes les autres. On constate qu’au début le courant diminue
brusquement, mais qu’à partir de 3 LEDs allumées on remarque une stabilisation manifeste. La courbe tracée en vert ressemble furieusement à une exponentielle présentant une asymptote horizontale. Ce phénomène résulte du fait que le seuil « Zener » devient de plus en plus stable. On peut déduire que l’éclairement des LEDs va devenir rapidement dérisoire. Là encore ce n’est pas du tout ce que l’on constate. S’il est évident que pour deux ou trois éléments on observe bien une chute notable de luminosité, en dessous d’un certain courant, le rendement des composants actuels étant très élevé, l’aspect visuel ne diminue plus de façon perceptible et la luminosité globale, comme visible sur la Fig.17 reste tout à fait exploitable.
Expérience 009 : Un ruban lumineux.
Artifice d’une grande banalité pour afficher de façon très visuelle la variation d’un paramètre physique ou virtuel, les rubans linéaires peuvent facilement être matérialisés par des rampes de LEDs. Comme le nombre de ces dernières qui vont être allumées varie entre « zéro et beaucoup », on imagine assez bien qu’il va falloir les alimenter chacune avec sa propre résistance de limitation du courant en reproduisant le schéma de la Fig.9 avec autant de branches qu’il y a de LEDs. (Le nombre total restera toutefois limité aux nombre de sorties disponibles sur la carte Arduino … sauf si on multiplexe, l’approche étant alors très différente.) Et bien pour montrer que l’on peut parfois se contenter d’une seule résistance commune comme sur la Fig.14 on ne va rien changer à la circuiterie et téléverser l’automatisme aveugle d’Experience_009.ino qui matérialise un ruban rectiligne, encore que l’on pourrait augmenter le nombre de LEDs et les placer sur un arc de cercle. Suite à cette expérience qui montre que la diminution de luminosité reste acceptable on peut résumer par :
Conclusion : Lorsque l’on pilote plusieurs LEDs dont une seule sera allumée à la fois, il est avantageux de n’utiliser qu’une seule résistance de limitation de courant. Cette solution reste toutefois acceptable lorsque plusieurs éléments seront illuminés simultanément, mais que leur nombre reste modéré et qu’ils sont tous issus d’un même lot, présentant des caractéristiques identiques.
Expérience 010 : Une autre façon de temporiser.
Comme dans les exercices qui précèdent nous avons abordé le thème de temporisation soit en utilisant une boucle de type while soit en utilisant la facilité apporté par delay() ou sa petite sœur delayMicroseconds(), il me semble opportun à ce stade de vous faire découvrir la fonction millis() incontournable quand on désire gérer des chronométrage sans enliser le processeur dans des boucles où il ne fait que « compter le temps qui passe ». Suite à ce préambule vous foncez en page 31 du petit manuel SYNTAXE à imprimer.pdf.
Supposons, pour illustrer notre propos, que simultanément au lièvre de l’exercice P007 on désire faire clignoter à une cadence d’une seconde une autre sortie de la carte Arduino. Par exemple on va choisir la sortie D13 qui ainsi pilotera la LED locale et nous évitera d’avoir à modifier notre circuiterie. Le problème, c’est que la boucle de base void loop() doit tourner à une cadence rapide, alors que delay() pour allumer et éteindre D13 « planterait » le processeur durant deux secondes. Il y a forcément une incompatibilité qui est résolue matériellement par une ressource interne à l’ATmega328 que l’on gère par l’outil C++ millis(). Avec cette fonction on peut facilement créer plusieurs chronométrages indépendants. Téléverser Experience_010.ino qui fait bien « cavaler » le lièvre tout en faisant clignoter la LED de D13 lentement. Outre l’utilisation de millis() ce démonstrateur présente une autre particularité : Avec digitalRead(Sortie_binaire) on peut lire l’état actuel d’une broche initialisée en sortie. Dans le langage C++ d’Arduino, la valeur d’un BIT « 1 » ou « 0 » peut être directement interprétée comme un booléen respectivement à true ou à false. Cet artifice est exploité dans l’instruction digitalWrite(LED_Arduino,!digitalRead(LED_Arduino)) qui sert comme le précise l’identificateur de la procédure à Inverser l’état de la LED témoin logique d’Arduino.
Explications :
En 1 le programme commence par lire l’état actuel de 2 la sortie nommée LED_Arduino. Puis en 3 l’opérateur ! du C++ inverse l’état binaire de l’entité entre parenthèses, c’est à dire l’état actuel de D13. Enfin en 4 le résultat de ce traitement est écrit dans la variable 5, c’est à dire sur D13. pour la transposition en ligne 29 voir les explications en Fiche n°23 et Fiche n°24.
La suite est ici.