Que vous soyez tentés par la solution expérimentale de la Fig.13B en A ou pour la version de luxe avec coffret en B dans les deux cas les programmes de ce didacticiel seront strictement identiques. Que ce soit les nombreux démonstrateurs de ce tutoriel ou le logiciel d’exploitation définitifs, tous ces « sketch » sont logés dans le dossier nommé <Les programmes Arduino>. Avant de commencer à aligner du code C++ en vue d’émuler les organes électromécaniques d’ÉNIGMA, il est prudent de vérifier l’intégralité du bon fonctionnement du matériel. On devrait toujours commencer un projet par définir avec précision sa structure matérielle, agencer complètement cette dernière et surtout en vérifier informatiquement son bon fonctionnement. C’est indispensable pour pouvoir ensuite programmer en étant certain que si le comportement attendu n’est pas celui observé, c’est bien le logiciel qui est en cause et non le matériel. C’est précisément le but du démonstrateur P01_Tester_le_materiel.ino prévu pour valider le bruiteur et la LED bleue.
Anticiper une version de luxe.
Signalé en page 4, on peut désirer ne rien investir et se contenter uniquement d’une carte Arduino NANO reliée au P.C. par sa ligne USB de téléversement. Dans ce cas ce petit module pourra servir à une autre application lorsque vous aurez exploré les exercices de ce didacticiel. Toutefois, si pour une somme relativement dérisoire vous optez pour la présence du bruiteur, on va pouvoir s’amuser à générer en code Morse l’équivalent de la lettre qui sera transmise au logiciel à partir du Moniteur de l’IDE. (Lettre en Morse une fois qu’elle aura été cryptée ou décryptée par la codeuse.) Partant de l’idée que ce petit amusement sera possible pour la version définitive du logiciel d’exploitation, autant dès ce démonstrateur créer les routines de traduction en code Morse.
Programmer avec méthode.
Bien que nous soyons dans un domaine ludique, le but fondamental de ce cheminement consiste à explorer ensemble des pistes de codage en langage C++ ayant pour cible les cartes du monde Arduino ; ce n’est plus le résultat qui compte, mais un cheminement informatique qui se veut rigoureux et optimal. Autrement dit, on va chercher à minimiser à outrance le code et programmer « avec méthode« . Dans ce cadre particulier, on doit impérativement commencer par choisir des identificateurs « évidents », la première qualité d’un logiciel quel qu’il soit est sa LISIBILITÉ. Envisager que votre « production » doit être compréhensible par « tous », et surtout par vous si vous devez reprendre l’ouvrage quelques semaines ou quelques années plus tard. Un skech comportera inévitablement des calculs non évidents, ou des astuces d’optimisation. Dans ce cas il sera primordial de les expliciter avec des commentaires. Éviter autant que possible les séquences très longues imposant des défilements du listage sur l’écran de l’ordinateur. Idéalement, une procédure ou une fonction ne devrait « jamais » dépasser en longueur la possibilité d’affichage de l’écran pour avoir toutes les instructions simultanément visibles. Pour illustrer ces conseils nous allons commencer dès le démonstrateur P01_Tester_le_materiel.ino pour lequel en outre on va chercher également à optimiser le choix du type des variables utilisées.
Bien que ce ne soit pas une obligation du tout, il est fortement recommandé de placer toute fonction ou procédure avant celle qui y fait appel. Ainsi, en déverminage, on sait que si une séquence est invoquée, il faut la rechercher en amont. Cette recommandation qui est une obligation en langage PASCAL par exemple fait gagner un temps fou quand on dévermine ou quand on améliore un programme « long » c’est à dire incluant des centaines d’instructions.
Stratégie adoptée pour la programmation.
Comme avec ce démonstrateur P01_Tester_le_materiel.ino on va anticiper la fonction qui génère du Morse dans le petit bruiteur passif, il importe dès cette phase d’adopter une technique homogène avec ce qui sera le programme d’exploitation futur. Après une analyse initiale, je suis arrivé à la conclusion qu’une lettre traitée sera codée par un nombre conformément au tableau de la Fig.14 où les lettres sont codées directement par leur place dans l’ordre alphabétique. Je vous laisse le soin de décoder 2/15/14/10/15/21/18. Cette technique de transposition directe des lettres par des nombre présente divers avantages. Que ce soit un char ou un byte dans les deux cas la place occupée en mémoire sera la même. En outre, pour agencer les tableaux de codage des Rotors et du Réflecteur on utilisera directement le byte du code de la lettre comme indice de sélection des positions dans les variables tableaux qui représenteront ces éléments de la machine de codage.
Pour traduire les lettres en Morse on va pour chacune utiliser un byte comme précisé sur la Fig.15 dans lequel le nombre binaire en violet N indique le nombre d’éléments dans le caractère. Les BITs à « 0 » représenteront des points, alors que les BITs à « 1 » traduiront des traits. Ces éléments seront lus de la droite vers la gauche. Par exemple sur la Fig.15 on a codé la lettre B. Toutes les lettres dans l’alphabet Morse ne compte au maximum que quatre éléments. De ce fait trois BITs sont suffisants pour indiquer le nombre d’éléments du caractère codé. Quatre BITs seront utilisés pour traduire en binaire les points et les traits. Un tableau ordonné de 26 éléments de type byte sera suffisant pour transcoder l’intégralité des lettres. Le démonstrateur étant téléversé sur notre simulateur, Le mot proposé en exemple est entendu dans le bruiteur, puis la LED en D13 d’Arduino et la LED bleue ajoutée vont clignoter à une cadence rapide. Le matériel étant validé, on va pouvoir commencer à construire informatiquement notre machine ÉNIGMA.
Avant de poursuivre, il me semble important de justifier l’utilisation d’un BUZZER de type actif. Le composant d’apparence strictement équivalente montré sur la Fig.16 existe aussi bien en passif qu’en actif. Le type passif a été éliminé pour les raisons suivantes :
• Il impose de générer un signal périodique ce qui impose un code objet plus important, surtout si l’on utilise l’instruction du genre tone(BUZZER,3000). Avec cette instruction la taille du programme augmente de 1312 Octets d’un coup et 23 Octets de plus dans les données dynamiques. On pourrait utiliser la PWM mais les deux fréquences disponibles sont relativement basses.
• Le composant est un solénoïde qui sous 5V présente une impédance de 11W ! Du coup il se comporte presque un court-circuit sur la sortie binaire et à ce régime l’ATmega328 ne résisterait pas très longtemps. Il faudrait intercaler un petit transistor amplificateur de courant …
Conclusion : Nous allons employer le composant passif de la Fig.16 dont la consommation reste très inférieure à ce que peut fournir Arduino. Sa Tonalité d’environ 3000Hz est idéale et l’activer n’imposera que peu de code objet. À toute fin utile, je vous livre l’adresse où j’ai approvisionné ce composant. (Vous constaterez qu’il est difficile de trouver des liens où on ne livre qu’un seul composant … et c’est souvent plus coûteux.) :
https://www.amazon.fr/gp/product/B00GX6YCBI/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1
Fonctionnement et utilisation du démonstrateur P01.
Étant donné que le but de ces manipulation réside dans l’exercice de la programmation structurée en Arduino, il me semble incontournable de détailler certaines séquences du démonstrateur P01_Tester_le_materiel.ino que vous téléversez sur votre carte NANO. Soulignons au passage que l’intégralité des démonstrateurs ainsi que le programme d’exploitation sont totalement compatibles avec une carte de type UNO car ils n’utilisent pas les deux entrées spécifiques. Si la NANO est sélectionnée dans ce projet, c’est à la fois pour des raisons financières (Un module NANO est bien moins couteux qu’une carte UNO.) et surtout pour sa compacité.
Compte tenu de la structuration des données proposée en Fig.14 et en Fig.15 pour transposer un caractère alphabétique en code Morse, le tableau donné ci-contre résume les diverses représentations de ces entités. C’est le BIT de droite qui sera l’élément convertit en TRAIT ou en POINT pour la transposition sonore. Du coup le codage des éléments se fait en sens symétrique comme montré sur la Fig.17 sur laquelle sont ajoutés les poids binaires des divers BITs qui indiquent le nombre d’éléments dans le caractère.
Pour extraire le nombre d’éléments du caractère de sa représentation binaire on utilise les opérateurs et les masques logiques.
Le domaine MASQUES LOGIQUES.
Fréquentant depuis de longues années des programmeurs amateurs, force est de constater que les si les opérateurs booléens tel que le OU et le ET sont bien assimilés, il en est tout autrement pour l’usage des masques logiques. C’est particulièrement vrai quand on programme en langage évolué comme BASIC, PASCAL ou C++ etc. Généralement des expressions comme :
C’est la pratique de la programmation « au raz de la machine » notamment en ASSEMBLEUR qui généralise l’usage des opérateurs LOGIQUES BIT à BIT et tout particulièrement l’intervention des masques logiques. Pourtant, comme on va le voir dans l’exemple de P01 ce type de programmation peut rendre de signalés services également dans les langages évolués. (On oubliera ici les opérateurs de décalage utilisés plusieurs fois dans ce petit projet s’ils sont utilisés pour multiplier ou diviser rapidement par des multiples de deux.) Nous allons dans ce chapitre passer en revue le domaine d’application des masques logiques et des opérateurs associés. On peut déjà noter que :
La modification d’un OCTET BIT Ã BIT.
Bien que ce chapitre prend en exemple des données de huit BITs, on peut généraliser sans autre forme de procès à des variables entières de taille quelconque. Par exemple on va raisonner sur une variable OCTET qui dans une procédure adaptée sert à lire ou écrire directement les huit BITs des broches binaires allant de D2 à D9 comme montré sur la Fig.18 donnée ci-contre. L’instruction suivante OCTET = DATA recopiera dans les huit BITs de sortie d’OCTET ceux de la variable DATA. Réciproquement, DATA = OCTET recopiera dans DATA les huit BITs des entrées BINAIRES d’OCTET. Ici l’opérateur « = » agit d’un seul coup sur l’intégralité du groupement nommé OCTET. On va maintenant voir comment à l’aide des opérateurs et des Masques LOGIQUES on peut agir sur des BITs individuels.
Le tableau de la Fig.19 propose trois exemples, mais pour bien saisir les transformations qui résultent de ces opérateurs reportez-vous sur la Fig.20 au résumé de l’emploi des Masque LOGIQUE :
Sur la Fig.19 la ligne A correspond à un Masque LOGIQUE commun affecté aux trois exemples. Sur la ligne B trois fois la même données sur laquelle est appliqué l’opérateur. En C est affiché le résultat de l’opération. Dans l’exemple avec le ET, supposons que les huit sorties BINAIRES de OCTET pilotent des LEDs. Et bien cette instruction va éteindre D2, D4, D8 et D9 sans modifier les autres sorties. Si on exécute une deuxième fois l’opération sur cette donnée OCTET modifiée en C, avec le même Masque LOGIQUE on constate sur la ligne D que l’on ne retrouve pas l’état initial du BIT concerné. La donnée initiale est définitivement perdue car il est impossible d’en retrouver la combinaison de départ. Le ET associé à un Masque LOGIQUE sert également à tester un BIT individuel sur une donnée globale. Supposons par exemple qu’OCTET a été initialisé en huit entrées binaires reliées à des capteurs. On désire savoir dans quel état se trouve celui qui est branché sur D5 par exemple. Il suffit dans la donnée lue de forcer tous les autres BITs à « 0« . L’instruction devient : Entrees = OCTET; if (Entrees && B00010000) then …
Vous avez certainement compris que l’opérateur OU qui force des « 1 » individuellement va servir à piloter des sorties binaires individuellement. Si on désire mettre en marche le moteur (Ou la LED etc.) branché sur D7 il suffit d’un OU avec 00000100. Pour le stopper c’est ET associé à 11111011 qui servira de masque. Il nous reste encore à passer en revue le domaine d’exploitation classique du OU Exclusif. On a vu en Fig.20, ce que confirme l’exemple de droite de la Fig.19 que cet opérateur sert à inverser les BITs correspondant lorsque dans le Masque LOGIQUE on a placé des « 1 ». Du coup on peut inverser l’état d’un système sans se préoccuper de son état initial. C’est exactement ce que font sans que nous le sachions des instructions de type :
La première instruction par exemple inverse l’état de la LED de D13 une fois par seconde. Dans ces deux instructions, l’opérateur d’inversion d’état qui en C++ est symbolisé par « ! » génère en interne pour le microcontrôleur une opération élémentaire avec un OU Exclusif et un masque logique.
Il me semble important de vous faire remarquer que la ligne relative au clignotement de la LED d’Arduino ne fonctionne correctement que par le fait qu’un OU Exclusif appliqué deux fois sur la même donnée avec un Masque LOGIQUE identique restitue cette dernière. Du coup on obtient bien une alternance d’état sur une paire d’exécution puis le cycle se poursuit.
Utilisation classique de l’opérateur ET.
Avant de passer à la suite, examinons ensembles une application banale en informatique de l’opérateur ET pour transformer un texte saisi en minuscules par des majuscules. Par exemple nous allons utiliser cette technique pour le dialogue Homme/Machine abordé dans le prochain chapitre. Chaque commande est obtenue par un caractère et il est précisé dans l’encadré de la Page 17 que Quel que soit la touche frappée on ne sera pas obligé de passer en MAJuscule. Par exemple l’usager frappe ‘E‘ pour dans le protocole adopté corriger une donnée. Vous désirez que cet usager ne soit pas forcément obligé d’enfoncer la touche [MAJ]. S’il frappe ‘e‘, le programme devra le transformer en ‘E‘. En codage ASCII c’est le BIT n°6 qui à « 1 » correspond à une minuscule, et à « 0 » donne son équivalent majuscule. L’instruction du genre Caractere = Caractere & 223; transformera toute minuscule en majuscule.
ATTENTION : Cette transformation n’est correcte que si le clavier utilisé retourne des codes ASCII et non de l’EBCDIC ou des codes clavier « IBM » qui sont totalement différents …
Application concrète des opérateurs de décalages.
Dans la procédure void TRANSCODE() on doit isoler le nombre d’éléments dans l’OCTET codé pour le Morse conformément à la Fig.17 donnée en page 11. Dans ce but on doit faire transiter les trois BITs de poids forts de gauche dans les trois BITs de poids faibles à droite. Par exemple en Fig.22 A on retrouve le codage du caractère L de la Fig.17 avec en violet le nombre d’éléments. On désire le déplacer à droite comme montré en B tout en forçant les autres BITs à zéro. Dans ce but nous allons utiliser l’opérateur logique SHIFT de décalage à droite qui en C++ se code avec « >>« . Par exemple l’instruction en Nb_Elements = Lettre >> 1; engendre le résultat montré en C. Tous les BITs ont été « poussés » d’une position à droite, celui de poids faible étant définitivement perdu. Sur la gauche un « 0 » est inséré.
ATTENTION, c’est le cas pour un byte mais pour une variable signée (De type char, int ou long.) on insère le même état que celui du BIT de gauche pour conserver le signe. Dans notre cas on désire décaler cinq fois, l’instruction utilisée dans P01 devient Nb_Elements = Lettre >> 5. Un autre exemple se trouve dans l’instruction if ((Lettre & 1) > 0) TRAIT(); else POINT(); qui combine SHIFT et Masque logique. Cette action est suivie de l’instruction Lettre = Lettre >> 1; qui utilise le masque logique 1 avec l’opérateur ET pour forcer dans le résultat tous les BITs à zéro sauf celui de poids faible et ainsi afficher un point ou un trait. Ensuite Lettre = Lettre >> 1; décale l’octet pour faire passer les éléments suivants d’une position à droite. Décalant l’OCTET représentatif de la gauche vers la droite, on traite ainsi le caractère de la droite vers la gauche ce qui était précisé en Fig.17 de la page 11. Sur un RESET de P01, si on a activé le Moniteur de l’IDE avec
à 57600 baud le logiciel se présente, puis liste les lettres en morse sur l’écran et en impulsions sonores. Enfin, le programme saute à la boucle de base void loop() qui tourne à l’infini en faisant clignoter à 1Hz la LED bleue.
La suite est ici.