Interface Homme Machine (IHM)

publicité
DUT informatique, TP info embarquée n°2, année 2015
P. Kauffmann
MODULE INFORMATIQUE EMBARQUEE
Interface Homme Machine (IHM)
Gérer un afficheur et un clavier
1. Présentation
Tous les systèmes informatiques ont besoin d’une interface de contrôle pour interagir avec le
dispositif ; cette interface est appelée "Interface Homme Machine" ou plus simplement IHM.
Dans le cas d’un micro-ordinateur il s’agit de l’écran et du clavier. Dans le cas d’un système
embarqué, l’IHM le plus simple peut se réduire à un bouton Marche/Arrêt et un voyant de
marche. Dans ce TP de 4 h nous allons réaliser une interface de sortie pour IHM embarqué
très répandue : un afficheur graphique à cristaux liquides. Le notre dispose de 128x64 pixels
monochromes ; ce type ayant été préféré à un afficheur couleur tactile à plus haute résolution
pour éviter de charger le processeur inutilement. L’entrée retenue est un clavier
alphanumérique à 4 lignes et 4 colonnes géré par scrutation.
2. Objectif(s) opérationnel(s)
•
•
•
•
Devenir capable de comprendre le fonctionnement d’un pilote d’afficheur.
Devenir capable d’utiliser un pilote d’afficheur pour afficher du texte et des nombres.
Comprendre le fonctionnement d’un pilote de clavier géré par scrutation.
Devenir capable d’utiliser un pilote de clavier géré par scrutation pour entrer du texte
et des nombres dans le contrôleur.
3. Organisation matérielle
Le TP sera réalisé par un groupe de deux étudiants. Le TP fera l'objet d’un rapport écrit
contenant les réponses aux questions et le code des fonctions demandées, rendu en fin de
séance sur papier. De plus, la totalité du code écrit, opérationnel et commenté, sera placé sur
la forge de Clermont-Université à l’endroit spécifié par l’enseignant d’encadrement.
4. Documentation et matériel nécessaire
Les documentations nécessaires pour la réalisation de ce TP sont :
•
•
•
polycopié de cours sur les microcontrôleurs,
notes de cours personnelles,
documentation électronique de la famille RX62,
•
les schémas de la plateforme cible.
Le matériel nécessaire pour la réalisation de ce TP est :
•
•
un ordinateur compatible PC avec la chaîne de développement RX62,
un système RX62N avec carte prototypage rapide.
5. Présentation du système d’affichage
5.1. Le principe de l’afficheur intelligent
Le dispositif étudié est un module d'affichage à cristaux liquides intégrant sa propre
électronique de commande (circuits intégrés dédiés S6B0108 utilisés par la majorité des
afficheurs graphiques monochromes). L'interfaçage se fait en mode parallèle sur 8 bits (bus
DB0-DB7). Le dispositif présenté ci-après comporte trois circuits :
• IC3 pour gérer les lignes de l’afficheur, contrôlé par l’intermédiaire des deux autres
circuits,
• IC1 qui contrôle la moitié gauche de l’écran et mémorise l’état de chacun des ses
64x64 pixels,
• IC2 qui contrôle la moitié droite de l’écran et mémorise l’état de chacun des ses 64x64
pixels.
Les deux broches CS1 et CS2 servent à sélectionner une des deux moitiés de l’afficheur pour
transmettre des données. Si aucun circuit n’est sélectionné, le bus DB0-DB7 peut servir à
autre chose, en particulier la gestion du clavier. Si les deux circuits sont sélectionnés
simultanément, on peut envoyer des commandes en parallèle aux deux circuits.
Chaque contrôleur gère 64 colonnes (adresse Y, aussi nommée line) de 8 lignes horizontales
(nommées page) de 8 pixels verticaux chacune. Lorsqu’on écrit une donnée sur 8 bits, on
contrôle donc une ligne verticale de 8 bits de hauteur. Donc 8 lignes permettent de contrôler
les 64 pixels de hauteur.
5.2. Le schéma électrique du système
Le schéma électrique est très simple puisqu'il suffit de relier les broches du module
d'affichage à la carte mère. Le bus DB0-DB7 est relié au port PD configuré en sortie. CS1 et
CS2 sont reliés respectivement à P8.5 et P8.4. La broche E (Enable : validation) permet de
synchroniser les données entre la carte mère et le contrôleur ; elle est reliée à P5.4. La broche
R/W# (Read/Write : lecture/écriture) permet de choisir le sens de la transmission de données ;
elle est reliée à la masse, on ne peut donc que écrire. La broche RS (Register Select : sélection
de registre) permet de choisir entre le mode commande et le mode données. Dans le premier
cas l'octet transmis à l'afficheur sera interprété comme une commande (voir syntaxe plus
loin), dans le second cas l'octet transmis sera interprété comme une donnée à afficher à la
position courante du curseur qui se décale après chaque donnée affichée. La broche RS aussi
appelée DI (pour Data/Instruction) est reliée à P5.5.
5.3. Commandes du contrôleur
Le contrôleur reconnait 4 commandes en écriture et une en lecture inutilisable donc non
décrite :
Code
Instruction
Description
D7 D6 D5 D4 D3 D2 D1 D0
1
ad5 ad4 ad3 ad2 ad1 ad0
Déplace le pointeur à la colonne
sélectionnée
1
1
ad5 ad4 ad3 ad2 ad1 ad0
Définit le numéro de colonne le plus à
gauche
1
0
1
Spécifie la ligne d’affichage entre 0 et
7
Définit l’adresse Y 0
Définit l’adresse Y
de départ
Définit la page
Contrôle
d’affichage
1
1
ad2 ad1 ad0
Active ou désactive l'affichage
0
0
1
1
1
1
1
ON/OFF
1/0
0 efface l’affichage
N.B. : Pour qu'un caractère DB0-DB7 soit reconnu comme une commande il faut au préalable
forcer la broche RS de l'afficheur au niveau 0. Si RS est à 1, le caractère DB0-DB7 est
considéré comme une donnée et les pixels correspondants sont activés ou éteints à la colonne
courante (Y) et la ligne courante (page).
5.4. Exploitation logicielle de l’afficheur
L’afficheur, bien que graphique, ne sera géré qu’un mode texte pour des questions de
simplicité. Le code source d’une amorce minimaliste de bibliothèque glcd.c permettant
d’afficher du texte ASCII est fourni ; la taille de police étant de 8 pixels verticalement et 6
pixels horizontalement. Ce code source se trouve sur la forge. Il est associé à un fichier
d’entête gldc.h et une table de définitions de caractères ascii.h.
Ce code de pilotage fourni est composé de plusieurs fonctions de niveau hiérarchique
différent :
•
•
•
Au niveau le plus bas on a une fonction d’écriture d’instruction ou de donnée dans
l’afficheur (une colonne de 8 pixels).
Au niveau juste au dessus on trouve la fonction d’initialisation de l’afficheur et la
fonction de changement de position du pointeur de position d’affichage.
Au niveau supérieur on trouve deux fonctions d’affichage d’un caractère unique et
deux fonctions d’affichage d’une chaine de caractères.
Comme les fonctions d’affichage exigent un temps processeur important et que l’œil humain
ne peut pas lire plus de cinq affichages par seconde, les fonctions d’affichage de haut niveau
doivent être appelées uniquement à faible fréquence, au maximum cinq fois par seconde. En
conséquence, le code de plus haut niveau est un affichage périodique sous interruption de
chaque ligne de l’afficheur ; interruption périodique déclenchée par un temporisateur affecté
spécialement à cette tâche.
N.B. : l’utilisation des fonctions d’affichage dans des fonctions d’interruptions ─ hormis
celle du temporisateur prévu pour cela ─ est totalement à proscrire car une fonction
d’interruption doit bloquer le processeur le moins longtemps possible (quelques
microsecondes tout au plus), alors que l’affichage d’une chaîne de caractères demande
plusieurs millisecondes.
Attention : la fonction d’affichage write() de glcd.c a une vitesse d’exécution
optimisée pour une compilation sans optimisation. Si on utilise une optimisation,
l’afficheur ne peut plus suivre et n’affiche pas correctement, à moins d’augmenter les
délais de la fonction write().
6. Présentation du clavier géré par scrutation
6.1. Principe des claviers gérés par scrutation
Un clavier d’ordinateur est constitué de boutons poussoirs qui définissent des niveaux
logiques 0 ou 1 selon qu’ils sont pressés ou non. Ils pourraient être reliés à autant d’entrées
d’un contrôleur, mais il faudrait alors beaucoup d’entrées (plus de 100 dans le cas d’un clavier
de PC). Pour diminuer le nombre d’entrées nécessaires on utilise le principe de la scrutation
décrit ci-après.
On organise les touches en lignes et colonnes. Chaque touche relie un fil de ligne à un fil de
colonne (voir le schéma électrique ci-après). Pour connaître les touches pressées, on active les
lignes une à une (sorties µC), et pour chaque ligne active on lit la ou les touches de la ligne
pressées (entrées µC). Ainsi pour un clavier de 4 colonnes et 4 lignes (16 touches) on aura
besoin que de 4 sorties et 4 entrées. Le clavier sera entièrement scruté en 4 étapes successives.
Typiquement, pour assurer un bon fonctionnement on scrute les claviers à une fréquence
d’environ 100 Hz.
Il existe plusieurs modes de gestion de clavier par scrutation. La première distinction
concerne le nombre de touches appuyées simultanément que le dispositif peut prendre en
compte (pour un clavier de compatible PC, la valeur est de 16). Notre logiciel ne pourra, lui,
prendre en compte qu'une seule touche à la fois. Si plusieurs touches sont pressées, seule la
première (dans l'ordre de scrutation) sera prise en compte. Certains claviers génèrent aussi la
répétition automatique de pression de touche si la durée de la pression dépasse un certain
temps ; ce ne sera pas le cas de notre dispositif.
Un des problèmes des interrupteurs, c’est que lorsqu’on les presse, ils ne se ferment pas
franchement, mais le contact a tendance à se fermer et s’ouvrir plusieurs fois successivement
durant les premières millisecondes (phénomène nommé rebond). Si ce problème n’était pas
géré, à chaque fois qu’on presse une touche, le contrôleur croirait qu’elle a été pressée
plusieurs fois. Pour résoudre ce problème on ne considère donc les touches comme actives ─
et donc valides ─ que si leurs contacts sont restés fermés plus de 40 ms sans rebond (soit 4
scrutations successives à 100 Hz) ; sinon, la pression sur la touche est ignorée.
6.2. Schéma électrique de l’interface clavier
Pour le branchement du clavier, on a utilisé quatre broches en sortie (PD.0-PD.3) partagées
avec l’afficheur et quatre broches en entrée (P9.0-P9.3).
Les diodes D0-D3 permettent d'éviter les courts-circuits entre colonnes lorsque plusieurs
touches sont activées simultanément. Les résistances R23-R26 maintiennent le niveau
d’entrée à 1 (3,3 V au repos) lorsqu’aucun contact n’est pressé. Elles garantissent aussi un
courant minimal dans les contacts lors de la fermeture d'une touche pour la destruction des
micro-couches d’oxyde.
Chaque touche porte un numéro à deux chiffres qui représente son "scan code". Celui de
gauche correspondant au numéro de ligne et l'autre au numéro de colonne. La ligne reliée au
bit de poids le plus faible du port de sortie porte le numéro "0", les numéros de ligne
s'incrémentent ensuite avec le numéro du bit du port. De la même façon, le numéro de
colonne commence à "0" pour la colonne connectée au bit du port d'entrée de poids le plus
faible, pour s'incrémenter ensuite avec le numéro du bit du port d'entrée.
Le niveau actif, aussi bien en entrée (lecture colonne) qu'en sortie (sélection ligne) est le
niveau "0". Par exemple, pour tester la touche ayant le "scan code" 21 on place la ligne 3
(DB2) à "0". Si la colonne 2 (P9.2) est à "0", cela prouve que le contact "21" est fermé et que
la touche correspondante "8" est pressée.
6.3. Interface logicielle du clavier
Le code source de la bibliothèque du clavier est fourni dans le fichier keyboard.c. Ce code
source se trouve sur la forge. Il est associé à un fichier d’entête keyboard.h.
Pour que le clavier puisse fonctionner, les périphériques du clavier devront d’abord avoir été
initialisés à l’aide de la fonction KEYBinit(). Ensuite, il faut utiliser la fonction
CLVscanKeyb() qui effectue le travail de scrutation complet du clavier avant de rendre la
main. Pour que le clavier fonctionne correctement, elle doit être invoquée de façon répétitive
100 fois par seconde sans interférer avec le programme principal.
La fonction CLVGetKey(unsigned char *c) retourne 1 si une nouvelle touche a été activée
et 0 sinon. De plus, cette fonction retourne le code ASCII de la nouvelle touche activée via le
pointeur *c. Si on l’utilise, cette fonction doit être appelée dans la routine de gestion du
clavier après l’exécution de CLVscanKeyb().
La fonction de plus haut niveau est la fonction CLVgets()qui lit une chaîne de caractères
complète. Cette fonction lit les caractères jusqu’à l’arrivée du code de contrôle "retour
chariot" (RC, soit \r en C). De plus, chaque fois qu’un caractère est acquis, il est affiché sur
l’écran à la position spécifiée. Cette fonction doit être appelée de préférence dans la routine de
gestion du clavier après CLVscanKeyb(). On notera que CLVgets()utilise
CLVgetKey()pour savoir s’il y a un caractère à lire avant de récupérer ce caractère, ce qui fait
que le code d’interruption de gestion du clavier on pourra utiliser une fonction ou l’autre,
mais pas les deux.
N. B. : la fonction CLVgets()utilise la fonction de bas niveau GLCDwriteCharXY() qui
n’est pas réentrante et également utilisée par GLCDwriteStringXY(). Il faut donc prendre des
précautions pour éviter toute interférence (exécution simultanée).
7. Manipulations
Le programme que nous allons créer réalisera une petite horloge qui affiche l’heure du jour et
qui peut être mise à l’heure à partir du clavier. Pour gagner du temps nous n’allons pas partir
d’une feuille blanche, mais d’un projet déjà opérationnel nommé horloge_c qui se trouve
sur la forge. Ce projet C++ a la particularité d’utiliser des fonctions de gestion de temps, de
l’afficheur et du clavier en C (d’où son nom). Notre travail sera de comprendre son
fonctionnement puis de le transformer en projet totalement C++ en ajoutant les classes tps,
glcd et keyb.
On notera au passage que le code de départ du projet correspond à un patron de conception
architectural. Dans ce patron toutes les fonctions sont réalisées de façon périodique car elles
sont exécutées par les interruptions de temporisateurs configurés pour générer des
interruptions périodiques. Il n’y a jamais de code exécuté hors des interruptions dans ce
patron, car même les évènements asynchrones (absents dans ce TP) sont réalisés sous
interruption. Nous conserverons ce patron de conception dans les deux prochains TP. On peut
aussi noter que le code de tous les TP d’informatique embarqué proposés utilise également
des patrons de conception comportementaux, qui comme ils sont très spécialisés, ne sont pas
décrits.
7.1. Code de gestion du temps
Etudiez le code placé dans le fichier temps.c. Ce code utilise un fonction unique
incTemps() et utilise une variable globale unique g_temps[].
Réalisez le travail suivant :
•
•
•
•
Etudiez le fonctionnement de ce code et cherchez ou il est utilisé.
Créez une classe tps qui incorpore la fonction incTemps() et la variable globale
g_temps[] transformée en attribut m_temps[], ajoute un constructeur qui met à zéro le
temps, ainsi que des accesseurs et mutateurs pour accéder aux heures, minutes et secondes.
Instanciez de façon statique cette classe (objet temps) et exploitez-la dans le projet à la place
du code C correspondant.
Montrez le résultat à l’enseignant d’encadrement.
7.2. Fonctions du pilote d’affichage
Etudiez les fonctions suivantes du pilote d’affichage fournies dans le fichier glcd.c :
void
void
void
void
GLCDwrite(uint8_t chip, bool D_I, uint8_t data);
GLCDinit(void);
GLCDgoTo(uint8_t selLine, uint8_t selColumn);
GLCDwriteChar(uint8_t data);
void GLCDwriteCharXY(uint8_t setLine, uint8_t setColumn, uint8_t
data);
void GLCDwriteString(uint8_t * string);
void GLCDwriteStringXY(uint8_t selLine, uint8_t selColumn, uint8_t *
string);
Réalisez le travail suivant :
•
•
•
Expliquez et mettez dans votre rapport le rôle de chacune de ces fonctions, le rôle, le sens et
les valeurs limites de chacun des paramètres passés ; ainsi que les fonctions appelées par
chacune d’entre elles.
Créez une classe glcd qui exploite chacune de ces fonctions en tant que méthode (on
enlèvera le préfixe GLCD de chacun des noms des fonctions). Mettez dans votre rapport le
fichier d’entête glcd.h. Créez un objet statique aff à partir de la classe glcd et utilisez le
dans votre application à la place des fonctions C correspondantes.
Montrez le résultat à l’enseignant d’encadrement.
7.3. Fonctions du pilote de clavier
Etudiez les fonctions du pilote de clavier fournies dans le fichier keyboard.c :
void CLVinit(void);
void CLVscanKeyb(void);
uint8_t CLVgetKey(uint8_t *c);
uint8_t CLVgets(uint8_t *c, uint8_t maxChar, uint8_t selLine,
uint8_t selColumn);
Réalisez le travail suivant :
•
•
•
•
Expliquez et mettez dans votre rapport le rôle de chacune de ces fonctions, le rôle, le sens et
les valeurs limites de chacun des paramètres passés ; ainsi que les fonctions appelées par
chacune d’entre elles.
Créez une classe keyb qui exploite chacune de ces fonctions en tant que méthode (on
enlèvera le préfixe CLV de chacun des noms des fonctions). Mettez dans votre rapport le
fichier d’entête keyboard.h. Créez un objet statique clav à partir de la classe keyb et
utilisez le dans votre application à la place des fonctions C correspondantes.
Proposez une solution au problème lié au fait que clav utilise une méthode de glcd.
Montrez le résultat à l’enseignant d’encadrement.
7.4. Réalisation d’un réveil
Afin d’étendre l’application actuelle, réalisez le travail suivant :
•
Réalisez un réveil matin. Le clignotement des deux leds constituera l’alarme qui s’activera
une minute lorsque l’heure courante et l’heure d’alarme seront égales. L’heure courante sera
rentrée en une fois (trois nombres séparés chacun par un espace) après avoir pressé A, l’heure
•
d’alarme sera rentrée en une fois aussi (trois nombres séparés chacun par un espace) après
avoir pressé B. L’heure d’alarme sera affichée sur la cinquième ligne d’affichage. La touche
C fonctionnera comme une bascule pour inhiber ou activer la fonction d’alarme (un symbole
graphique signalera l’alarme si elle est active). L’alarme pourra être stoppée en pressant sur
n’importe quelle autre touche.
Montrez le fonctionnement à l’enseignant d’encadrement et mettez le code spécifique
commenté dans votre rapport.
Téléchargement