Table des matières
TP 1 Informatique Embarquée CESI
Dire aux étudiants de se connecter en ge2i / ge2i et d'utiliser le navigateur firefox
Installation et lancement de wokwi2gtkwave
En début de chaque séance, taper ALT+F2 puis saisir gnome-terminal . Dans le terminal copier coller le texte suivant et laisser ouvert le terminal:
echo commence mkdir -p ~/wokwi cd ~/wokwi rm wokwi2gtkwave.py wget https://raw.githubusercontent.com/bvandepo/wokwi2gtkwave/main/wokwi2gtkwave.py chmod a+x wokwi2gtkwave.py python3 ./wokwi2gtkwave.py echo fini
Informations avant de commencer!
Pour faire le TP, vous devrez bien lire le sujet, ne pas sauter de parties, ne pas inventer de prototypes de fonctions mais bien respecter ce qui est demandé, car les fonctions que vous écrirez devront pouvoir être substituées à d'autres fonctions ayant les mêmes prototypes. Les marges de manœuvre dont vous disposez sont au niveau de l'implémentation de ces fonctions, mais les prototypes font partie du cahier des charges et ne sont pas négociables! Le TP se déroulera sur plusieurs séances, il est de votre responsabilité de conserver les fichiers que vous aurez produits; pour cela, sauver l'URL de votre projet sur Wokwi et également LE CONTENU DU CODE pour éviter toute perte. Vous devrez également conserver les chronogrammes intéressants pour pouvoir les revoir à posteriori et les comparer.
Prise en main du programme d'exemple
Vous allez dans un premier temps utiliser un programme existant pour en comprendre le fonctionnement puis vous devrez écrire votre propre programme avec des contraintes différentes. Ouvrir dans une autre fenêtre: https://wokwi.com/arduino/libraries/SevSeg/SevSeg_Counter
Puis, en haut à gauche, cliquer sur “Save a copy”. Comme pour te TD, vous devriez vous loguer et conserver cette URL ainsi que sauvegarder votre programme à la fin de la séance et vous l'envoyer par mail (car vous travaillez sur un compte local sur le PC).
Analyse de la schématique et des composants
Lire la documentation du composant afficheur 7 segments multiplexé à 4 chiffres: https://docs.wokwi.com/parts/wokwi-7segment
En lisant le fichier diagram.json, déterminer le type d'afficheur 7 segments utilisé.
Relever sur papier les connexions électriques entre l'Arduino (avec la numérotation Arduino) et l'afficheur
En plus de la numérotation des broches Arduino, vous devrez également relever la correspondance avec les broches du microcontrôleur ATMEGA328P. Les connecteurs IOL et IOH (avec la numérotation Arduino de 0 à 13) à droite sont respectivement pilotés par les registres PORTD et PORTB sur le schéma suivant:
Regrouper les broches des différents signaux et dire par quoi elles sont pilotées. Par exemple, les 7 segments sont pilotés par …
Schéma de la carte Arduino UNO R3: https://bvdp.inetdoc.net/files/cesi/Arduino_Uno_Rev3-schematic.pdf
Utilisation d'une librairie haut niveau pour piloter l'afficheur
Dans le programme fourni, la valeur à afficher est transmise via sevseg.setNumber(val, position_point_décimal); puis sevseg.refreshDisplay() doit être appelée régulièrement pour réaliser une étape du balayage
Analyser le code fourni et comprendre l'utilisation du timer par scrutation qui a été abordée au dernier TD.
Modifier la schématique pour reproduire le schéma suivant:
Au besoin, le fichier de schématique est disponible sur: https://bvdp.inetdoc.net/files/cesi/tp1/diagram1.json
Adapter le code pour piloter l'affichage avec la valeur 10bits lue sur le Convertisseur Analogique Numérique via l'entrée A0. Ajouter également l'affichage sur la console de Debug de la valeur lue en décimal suivie d'un retour à la ligne. Vérifier en simulation le bon fonctionnement du système pour différentes positions du potentiomètre.
Analyse des signaux de commande de l'afficheur
Ajouter à la schématique le composant “Logic Analyzer (8 channels)” et connecter
- les entrées D3..0 de l'analyseur logique aux broches 5..2 de l'Arduino
- les entrées D7..4 de l'analyseur logique aux broches 13..10 de l'Arduino
Au besoin, le fichier de schématique est disponible sur: https://bvdp.inetdoc.net/files/cesi/tp1/diagram2.json
Lancer une simulation puis l’arrêter. Un fichier portant l'extension vcd est téléchargé, le sauver dans le dossier Téléchargements (si l'option est proposée, cocher toujours effectuer cette action).
Nous allons automatiser l'affichage des chronogrammes contenus dans ce fichier pour cela, ouvrir un terminal en pressant ALT+F2 puis xterm et touche Entrée. Copiez coller dans ce terminal le texte suivant (il faudra ensuite laisser ce terminal ouvert pendant toute la durée où vous souhaitez pouvoir afficher les chronogrammes):
echo commence mkdir -p ~/wokwi cd ~/wokwi rm -f wokwi2gtkwave.py && wget --no-check-certificate https://raw.githubusercontent.com/bvandepo/wokwi2gtkwave/main/wokwi2gtkwave.py python3 ./wokwi2gtkwave.py echo fini
Relancer une simulation puis l’arrêter. Vous devriez voir une fenêtre gtkwave s'ouvrir et afficher le chronogramme, sinon appeler l'enseignant. Sur le chronogramme, vous pourrez zoomer à l'aide de la molette de la souris en maintenant la touche CTRL pressée. Les fichiers chronogrammes sont automatiquement déplacés dans un sous dossier ~/wokwi/vcdforgtkwave que vous pourrez renommer à posteriori si vous voulez en conserver certaines versions et éviter qu'elles ne soient écrasées.
Interprétez les chronogrammes:
- En déduire comment les LED sont câblées dans cet afficheur?
- Zoomer sur des instants de changements de segments et regarder combien de digits sont actifs à cet instant.
- Combien de LEDs peuvent être allumées simultanément au maximum?
- A quelle fréquence l'affichage de la totalité des chiffres est effectué?
Programme avec votre propre librairie
Le programme d'exemple étant maintenant compris (normalement…), vous allez devoir écrire vous même les fonctions permettant de piloter l'afficheur.
Numérotation des digits et segments
Nous utiliserons une numérotation un peu différente de celle de la documentation de l'afficheur 7 segments fournie en: https://docs.wokwi.com/parts/wokwi-7segment
numérotation TP | rôle | affichage sur le chronogramme |
---|---|---|
digit 0 | chiffre le plus à gauche (miliers) | D0 |
digit 1 | chiffre (centaines) | D1 |
digit 2 | chiffre (dizaines) | D2 |
digit 3 | chiffre le plus à droite (unités) | D3 |
segment 0 à 3 | segment A à D | non visibles |
segment 4 | segment E | D4 |
segment 5 | segment F | D5 |
segment 6 | segment G | D6 |
segment 7 | point décimal DP | D7 |
Changements par rapport à l'exercice précédent
La librairie utilisée précédemment est très générique, ce qui signifie qu'elle peut être utilisée dans plusieurs configurations différentes en s'adaptant facilement (par exemple à différents type et taille d'afficheurs, à différente familles de microcontrôleurs). La librairie que vous allez écrire sera moins générique mais sera spécifique et optimisée pour un microcontrôleur et un afficheur particulier, les deux étant connectés d'une manière fixe. Ceci nous permettra d'illustrer la commande à bas niveau en pilotant les broches du microcontrôleur directement via ses registres.
Dans cet exercice, pour changer, nous allons utiliser un autre type de cablage de l'afficheur. Pour changer le type d'afficheur du schéma, remplacer dans le fichier diagram.json dans les attributs du composant “wokwi-7segment”
"attrs": { "digits": "4", "common": "anode" }
par
"attrs": { "digits": "4", "common": "cathode" }
Avec cet afficheur, vous devrez balayer les différents digits (actifs à l'état bas) et pour chaque digit piloter les segments (actifs à l'état haut) qui doivent s'allumer. VOUS DEVREZ ABSOLUMENT veiller à ce que:
- il n'y ait jamais deux digits actifs en même temps, pour cela vous devrez en désactiver un AVANT d'activer le suivant.
- les changements de valeur pilotant les segments soient réalisés lorsque AUCUN des digits n'est actif.
Programme de départ
Copier coller ce programme à la place de l'ancien. Il contient la définition des variables globales dont vous aurez besoin:
- aff7seg.ino
byte numDigits = 4; byte digitPins[] = {2, 3, 4, 5}; byte numSegments = 8; byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; byte tabDeco7seg[]={0x3f,0x06,0x5b,0x4F,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; void setup() { Serial.begin(115200); Serial.println("debut"); } void loop() { }
Initialisations
Dans un premier temps, nous utiliserons les fonctions Arduino digitalWrite(…) et pinMode(…) pour configurer/piloter les broches (en utilisant les tableaux définis en variables globales pour identifier les broches).
Compléter le programme pour configurer toutes les broches utiles dans la bonne direction et à une valeur inactive. Il est très fortement conseillé d'utiliser des boucles car le traitement à produire pour les différentes broches est quasiment le même.
Vérification de la commandabilité
Modifier loop() temporairement juste pour allumer sur l'afficheur des dizaines le segments F et le point décimal.
Faire de même cette fois-ci pour allumer les segments A et E de l'afficheur des milliers.
Une fois que vous avez vérifié en simulation que vous êtes bien capables de piloter les segments, commenter ce code dans loop().
Fonction de pilotage d'un digit
Implémenter la fonction void setDigit(unsigned char nDigitActif,unsigned char nSegsActif) dont les paramètres sont:
- nDigitActif prenant une valeur comprise en 0 et 3 pour indiquer le digit à activer
- nSegsActif prenant une valeur sur 8 bits pour indiquer (à l'état haut) les segments (et le point) à allumer.
Cette fonction devra successivement (copier coller ces 3 items dans votre code en tant que commentaires, et écrire votre code sous chaque commentaire):
- désactiver tous les digits avant de changer les segments
- piloter les segments en utilisant les valeurs des bits de nSegsActif
- activer le bon digit
Tester votre fonction en utilisant ce sous programme loop():
- aff7seg5.ino
void loop() { setDigit(0,0x10); setDigit(1,0x20); setDigit(2,0x40); setDigit(3,0x80); }
Vérifier que l'affichage est correct. Faire de même pour cet autre programme:
Tester votre fonction en utilisant ce sous programme loop():
- aff7seg7.ino
void loop() { setDigit(0,1); setDigit(1,2); setDigit(2,3); setDigit(3,4); }
Décodage 7 segments
Nous avons vu en TD l'utilisation d'une table de transcodage (Look-Ut Table) pour réaliser le décodage 7 segments. Cette table est déclarée dans votre programme dans le tableau tabDeco7seg.
Adapter loop() pour afficher les chiffres présents dans les cases du tableau byte digits[4]; en réalisant le décodage. Vous aurez pris soin d'initialiser digit[] pour que chaque case contienne un chiffre différent à afficher sur le digit correspondant. Vous veillerez aussi à ce qu'une valeur supérieure à 15 dans une case de digit[] ne provoque pas une fuite mémoire lors de la recherche de la valeur correspondante dans la table tabDeco7seg. Pour l'instant vous ne vous occuperez pas du point décimal. Vous ne devez pas modifier la fonction void setDigit(unsigned char nDigitActif,unsigned char nSegsActif)!
Gestion du point décimal
Toutes les valeurs stockées dans le tableau tabDeco7seg ont le bit 7 à la valeur 0. Donc votre programme à l'exercice précédent doit avoir éteint tous les points décimaux.
Nous allons maintenant utiliser la variable globale byte dots; pour indiquer quels points décimaux afficher. Pour cela le bit i de dots à 1 indique qu'il faut allumer le point décimal de l'afficheur i.
Adapter le programme précédent pour activer correctement les points décimaux. Pour cela, utiliser les opérateurs logiques et de décalage vus en TD. Vous ne devez toujours pas modifier la fonction void setDigit(unsigned char nDigitActif,unsigned char nSegsActif)!
Conversion binaire 16 bits vers BCD 4 digits
Vous devez maintenant implémenter une fonction void setNumber(unsigned int val) qui va remplir les 4 cases du tableau digits à partir d'une valeur numérique sur 16 bits non signée passée via le paramètre val. Pour cela, vous pourrez utiliser notamment l'opérateur modulo (% en C).
Tester votre programme pour afficher la valeur “789.5”. Pour cela appelez setNumber(7895); et dots=4;
Gestion du temps
Observez pour l'exercice précédent sur les chronogrammes la fréquence à laquelle les digits sont balayés et relevez la durée pendant laquelle chacun d'eux est allumé à chaque affichage. Un rapport cyclique différent se traduit par une intensité lumineuse perçue différente. Pour éviter cela, nous allons mettre en place 2 tâches pseudo parallèles:
- Une première servant à calculer une valeur à afficher (incrémentée à chaque appel) et à la convertir en BCD.
- Une seconde servant à réaliser l'affichage multiplexé (balayage) des différents digits. UN SEUL DIGIT DOIT ÊTRE PILOTÉ A CHAQUE APPEL.
La structure du sous programme loop() est fournie et vous devez implémenter les 2 taches dans les fonctions correspondantes.
- aff7seg11.ino
/////////////////////////// void tache1(){ } /////////////////////////// void tache2(){ } /////////////////////////// void loop() { unsigned int periodiciteTache1=100; //100ms entre chaque incrémentation de la valeur à afficher unsigned int periodiciteTache2=4; //4ms pour l'affichage de chaque digit static unsigned long timerTache1 = millis(); static unsigned long timerTache2 = millis(); if (millis() - timerTache1 >= periodiciteTache1) { timerTache1 += periodiciteTache1; tache1(); } if (millis() - timerTache2 >= periodiciteTache2) { timerTache2 += periodiciteTache2; tache2(); } } /////////////////////////// }
Vérifier à l'aide des chronogrammes que chaque digit est bien piloté pendant approximativement 4ms et donc que l'affichage est rafraîchi à une cadence de 62.5Hz. Vérifier que la valeur affichée sur l'afficheur est bien cohérente avec le temps simulé (affiché en haut à droite de la schématique pendant la simulation).
Appeler un enseignant pour valider votre travail.
Gestion du temps par Interruption Timer
Vous avez peut être relevé des déviations par rapport à la valeur idéal de 4ms pour l'affichage sur les digits. Nous pouvons aggraver ce phénomène en rendant la tâche 1 bloquante pendant plus longtemps. Pour cela, ajouter à la fin de la tâche 1 un appel à delay(25); et relever les chronogrammes. Dans ce cas, on observe que la tâche 2 ne pourra pas être exécutée toutes les 4ms, le processeur restant bloqué dans l'exécution de la tâche 1 pendant plus de 25ms. Nous allons maintenant utiliser un mécanisme appelé Interruption pour que la tâche 2 soit appelée lorsque nécessaire, en interrompant la tâche 1 si besoin.
Avec les interruptions, il n'est plus nécessaire de venir scruter régulièrement la valeur du timer pour exécuter la tâche si besoin. Au lieu de cela, une configuration de l'interruption est effectuée au début du programme afin que la tâche 2 s'exécute à une cadence prédéterminée.
Retirer l'appel de la tâche 2 dans loop(), et appeler la fonction void setupTimer2() une fois dans setup(). Ainsi le sous programme ISR(TIMER2_COMPA_vect) est appelé automatiquement toutes les 4ms.
- aff7seg13.ino
//Timer 2 : https://www.aranacorp.com/fr/utilisation-des-timers-de-larduino/ // timer2 (8 bits) qui est utilisé par la fonction Tone() et la génération de la PWM sur les broches 3 et 11. void setupTimer2(){ cli(); // disable all interrupts TCCR2A = (1<<WGM21)|(0<<WGM20); // Mode CTC TIMSK2 = (1<<OCIE2A); // Local interruption OCIE2A TCCR2B = (0<<WGM22)|(1<<CS22)|(1<<CS21); // prediviser /256 OCR2A = 250; //250*256*1/16000000 = 4ms sei(); // enable all interrupts } //appelée toutes les 4ms: ISR(TIMER2_COMPA_vect){ // timer compare interrupt service routine tache2(); }
Lorsque nous utilisons le mécanisme d'interruption, il est nécessaire de prendre des précautions: il faut mettre en place un verrou sur les données et périphériques utilisés en commun par les différentes tâches pour éviter par exemple que l'interruption timer affiche des valeurs en cours de réglage par la tâche 1. Pour cela, vous veillerez à ajouter avant toute modification des variables digits[] ou dots par la tache 1, l'instruction suivante pour éviter l'exécution du programme d'interruption timer pendant la modification de variable partagée:
cli(); // disable all interrupts
Une fois la variable modifiée, insérer l'instruction suivante pour autoriser à nouveau l'interruption timer:
sei(); // enable all interrupts
Observer à nouveau les chronogrammes et vérifier que les durées d'alternance des digits sont maintenant respectées.
Appeler un enseignant pour valider votre travail.
Pilotage des broches à bas niveau
Nous avons utilisé jusqu'à maintenant la fonction digitalWrite(…) pour piloter individuellement les broches de l'afficheur. Nous allons maintenant mettre en place un pilotage bas niveau permettant d'accéder simultanément à plusieurs bits en écrivant une valeur 8 bits dans un registre associé au port de sortie.
Nous allons commencer par évaluer le temps nécessaire à la commande de l'afficheur 7 segments par votre fonction void setDigit(void setDigit(…). Pour cela, nous allons utiliser une broche (A3, pilotée par le bit 3 du port C) qui va être mise à 1 pendant l'exécution de la fonction et à 0 le reste du temps. Configurer la broche A3 en sortie et à l'état bas dans setup(). Au début de la fonction void setDigit(…), modifier le registre PORTC pour mettre son bit 3 à la valeur 1, puis le remettre à la valeur 0 à la fin de la fonction (utiliser les opérateurs & et | ainsi que des masques).
Défaire la connexion du point décimal à l'entrée D7 de l'analyseur logique et y connecter A3 de l'Arduino pour pouvoir observer ce signal et relever la durée pendant laquelle le signal est à l'état haut pour quelques digits.
Implémentation bas niveau
Nous allons conserver cette implémentation de votre fonction void setDigit(…) en la renommant void setDigitHAL(…) et vous allez maintenant devoir ré-implémenter une fonction void setDigit(…) réalisant le même travail mais sans utiliser la fonction digitalWrite(…) de la HAL Arduino.
Veillez à ne pas écrire inutilement plusieurs valeurs à la suite dans un registre de PORT, car chaque valeur écrite pilote effectivement la broche. Éventuellement passer par une variable temporaire adéquate, dont la valeur sera finalement affectée au registre de port.
Pour réaliser la nouvelle implémentation de void setDigit(…), vous devrez manipuler les différents registres PORTB, PORTC et PORTD pour successivement (copier coller ces items dans votre code en tant que commentaires, et écrire votre code sous chaque commentaire):
- activer la broche A3 pour début de mesure de la durée d'exécution: TIC
- régler toutes les cathodes inactives
- régler les segments (poids faible), en maintenant toutes les cathodes inactives
- régler les segments (poids fort)
- régler la cathode active
- désactiver la broche A3 pour fin de mesure de la durée d'exécution:TOC
Pour cela vous devrez utiliser des opérateurs logiques, de décalage, des valeurs constantes ainsi que les paramètres nDigitActif et nSegsActif. Avant de coder, vous devriez dessiner chaque registre modifié pour chaque action et les valeurs modifiées pour chacun des bits.
Une fois la fonction codée et le fonctionnement étant correct, relever sa durée d'exécution sur le chronogramme. La durée relevée par votre professeur est de 2.5 us, ce qui est bien plus rapide que l'implémentation utilisant la HAL Arduino.
Organisation des fichiers pour la librairie
En vous inspirant de la librairie utilisée dans le TD1 cesitd1, créer 2 fichiers:
- lib7seg.cpp dans lequel vous déplacerez les constantes et l'implémentation des fonctions. Vous veillerez également à ajouter au début de ce fichier: #include “lib7seg.h”. Vous laisserez les fonctions de configuration du timer et la routine d'interruption timer dans le fichier du programme principal!
- lib7seg.h dans lequel vous copierez les prototypes des fonctions. Vous veillerez également à ajouter au début de ce fichier: #include <Arduino.h>
Vous déplacerez les initialisations liées à l'afficheur 7 segments de la fonction setup() à une fonction setup7seg() qui sera elle même appelée par setup() et rangée dans la librairie.
Vous devrez également ajouter à votre librairie une fonction void setDots(unsigned char val) permettant de régler la valeur de la variable dots et donc de configurer quels points décimaux doivent être allumés.
Vous devrez également ajouter à votre librairie une fonction void refresh() permettant de gérer le balayage des digits. Vous y déplacerez le code de la fonction tache2(), et vous veillerez à appeler refresh() à la place de tache2() dans la routine d'interruption timer.
Appeler un enseignant pour valider votre travail.
Application 1
Nous proposons maintenant d'utiliser la librairie que vous venez de faire pour réaliser une application de monitoring. Connecter 4 potentiomètres aux entrées A0, A1, A2 et A4 de l'Arduino pour reproduire le schéma suivant:
Au besoin, le fichier de schématique est disponible sur: https://bvdp.inetdoc.net/files/cesi/tp1/diagram3.json
Ecrire un programme permettant de réaliser les 4 taches suivantes en parallèles:
- Une première tâche réalise l'acquisition des mesures sur ces 4 entrées en permanence dans une tache, chaque 100ms. Les valeurs lues devront être stockées dans un tableau unsigned int datain[4].
- Dans une seconde tâche, exécutée chaque deux secondes, le numéro de l'entrée dont la valeur est affichée sur l'afficheur 7 segments sera changée, de sorte que l'on balaye les 4 entrées en 8 secondes. Cette tache remplie le rôle de choix d'aiguillage. Elle devra également indiquer sur l'afficheur quelle est la valeur en cours d'affichage, cette tache devra régler la valeur de commande des points décimaux (avec la fonction setDots(…)) pour allumer le point décimal i lors de l'affichage de la valeur datain[i].
- Une troisième tâche, exécutée à la cadence maximale doit utiliser la valeur de l'entrée sélectionnée par la seconde tâche pour qu'elle soit affichée par la routine d'interruption timer de votre librairie.
- Une quatrième tâche gérant le balayage des différents digits est appelée par interruption Timer.
Affichage des mesures
Nous allons maintenant tracer les valeurs lues sur les 4 entrées analogiques dans un plotter comme indiqué sur https://docs.wokwi.com/guides/serial-monitor#configuring-the-serial-monitor . Pour cela, dans diagram.json, après la ligne:
"editor": "wokwi",
ajouter:
"serialMonitor": { "display": "plotter", "newline": "lf" },
et dans la tache 1, après la collecte des mesures sur les entrées analogiques, ajouter:
- fintache1.ino
for (int i=0;i<4;i++){ Serial.print(datain[i]); Serial.print(" "); } Serial.println();
En lançant la simulation et en jouant sur les potentiomètres, vous devriez voir un tracé similaire à:
Appeler un enseignant pour valider votre travail.
Application 2
Nous proposons maintenant d'intégrer la librairie objet permettant d'utiliser l'encodeur incrémental vu dans cesitd2 à ce projet pour afficher la position angulaire et la vitesse de rotation sur l'afficheur 7 segments.
Modifier la schématique pour reproduire le schéma suivant:
Au besoin, le fichier de schématique est disponible sur: https://bvdp.inetdoc.net/files/cesi/tp1/diagram4.json
Sur ce schéma, vous retrouvez l'encodeur incrémental ainsi que l'afficheur 7 segments multiplexé à 4 digits. Une LED connectée à la sortie A5 de l'Arduino fait office de signe, en s'allumant pour indiquer le signe négatif. Un bouton de sélection connecté ) l'entrée A4 est utilisé pour permettre l'affichage soit de la position angulaire soit de la vitesse. L'affichage devra être actualisé cinq fois par seconde.
Pour l'affichage de la vitesse, vous pourrez ajouter une fonction d'affichage d'une valeur flottante positive à la librairie d'affichage. Cette fonction devra convertir la valeur flottante en un entier pour occuper au mieux les 4 digits et piloter correctement l'affichage du point. Dans le cas d'une valeur trop grande pour être afficher, il faudra afficher EEEE pour indiquer une erreur.
Appeler un enseignant pour valider votre travail.
Rendre la librairie de pilotage de l'afficheur 7 segments "Orientée Objet"
Visionner la vidéo de cours présentant les concepts de la Programmation Orientée Objet: https://youtu.be/5Y9P4MIkTIs
Polycopié du cours POO: https://bvdp.inetdoc.net/files/iut/cours_POO_intro_complet_2021_numbered.pdf
La classe suivante est proposée pour la librairie d'affichage:
- lib7seg.h
#include <Arduino.h> /*! Clib7Seg Classe pour la gestion de l'afficheur 7 segments multiplexé */ class Clib7Seg { public: /*! Clib7Seg() constructeur sans paramètre qui utilise des broches par défaut et une taille d'afficheur fixe */ Clib7Seg(); /*! Clib7Seg(byte numDigitsInit,byte * digitPinsInit, byte numSegmentsInit, byte * segmentPinsInit); constructeur avec des paramètres qui permet de configurer les broches utilisées ainsi que le nombre de digits */ Clib7Seg(byte numDigitsInit,byte * digitPinsInit, byte numSegmentsInit, byte * segmentPinsInit); /*! void setNumber(unsigned int val); demande de mise à jour de la valeur numérique affichée à partir du paramètre entier val. */ void setNumber(unsigned int val); /*! void setDots(unsigned char val); demande de mise à jour de la valeur affichée pour les points. val est une valeur dont le bit 0 pilote le point de digit de gauche, et chacun des bits suivants pilote le point du digit suivant. */ void setDots(unsigned char val); /*! void refresh(); demande de rafaichissement de l'affichage pour effectuer le balayage. Cette méthode doit être appelée suffisament fréquemment pour que le balayage ne soit pas perçu par l'oeil. Elle peut être appelée dans une tache périodique utilisant un timer par scrutation ou dans une routine d'interruption timer matériel val est une valeur dont le bit 0 pilote le point de digit de gauche, et chacun des bits suivants pilote le point du digit suivant. */ void refresh(); /*! setNumberFloatAbs(float floatAbs); IMPLEMENTATION SUR 4 DIGITS SEULEMENT demande de mise à jour de la valeur numérique affichée à partir du paramètre entier floatAbs. C'est la valeur absolue de floatAbs qui est affichée. Le point est positionné automatiquement et en cas de dépassement de la valeur par rapport à la capacité d'affichage, des chiffres E sont affichés. */ void setNumberFloatAbs(float floatAbs); private: //! nombre de digits de l'afficheur byte numDigits; /*! liste des broches utilisées pour les digits pointeur vers un tableau alloué dans le constructeur plutot qu'un tableau, utilise un pointeur pour gérer une taille variable*/ byte *digitPins; //! nombre de segments de l'afficheur (doit être 8) byte numSegments; /*! liste des broches utilisées pour les segments pointeur vers un tableau alloué dans le constructeur plutot qu'un tableau, utilise un pointeur pour gérer une taille variable*/ byte *segmentPins; //! masque de bits pour gérer jusqu'à 8 points byte dots; /*! stockage des chiffre à afficher sur les digits de l'afficheur pointeur vers un tableau alloué dans le constructeur*/ byte *digits; //! méthode de pilotage individuel des digits, appelée par refresh() void setDigitHAL(unsigned char nDigitActif,unsigned char nSegsActif); //! méthode contenant les initialisations communes aux différents constructeurs void init(); };
Adapter votre libraire pour qu'elle implémente cette classe. Le code de configuration du timer et de gestion de l'interruption devront être hors de la classe et le programme d'interruption timer devra juste appeler la méthode refresh(). Le plus simple est de mettre tout le code timer dans le fichier du programme principal.
Le code de votre librairie utilisant un accès bas niveau aux broches via les registres ne sera pas repris dans cette librairie objet car il ne permet pas la modularité (changer le nombre de digits et les broches).
Dans la classe, au lieu d'utiliser des tableaux pour stocker les broches et les digits, les membres déclarés sont des pointeurs. Pour pouvoir les utiliser comme des tableaux, il vous faudra procéder à l'allocation dynamique de mémoire dans les constructeurs. Par exemple, pour allouer le tableau digitPins avec numDigitsInit éléments, il faut faire:
- allocation7seg.cpp
numDigits = numDigitsInit; digitPins=new byte[numDigits];
L'instanciation de l'afficheur dans le programme principal se fera par:
- instanciation7seg.cpp
byte digitPins[] = {2, 3, 4, 5}; byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; Clib7Seg aff7seg(4,digitPins,8,segmentPins); //Objet en variable globale car utilisé dans l'interruption
Appeler un enseignant pour valider votre travail.
Si vous êtes arrivé jusqu'ici, demander à l'enseignant quoi faire ensuite.